]> git.proxmox.com Git - mirror_frr.git/commitdiff
Merge pull request #883 from daveolson53/master
authorDavid Lamparter <equinox@diac24.net>
Wed, 9 Aug 2017 17:29:16 +0000 (19:29 +0200)
committerGitHub <noreply@github.com>
Wed, 9 Aug 2017 17:29:16 +0000 (19:29 +0200)
Switch to using syslog for logging as the default

268 files changed:
Makefile.am
babeld/babeld.conf.sample
bgpd/bgp_attr.c
bgpd/bgp_attr_evpn.c
bgpd/bgp_damp.c
bgpd/bgp_evpn.c
bgpd/bgp_evpn_private.h
bgpd/bgp_fsm.c
bgpd/bgp_open.c
bgpd/bgp_open.h
bgpd/bgp_packet.c
bgpd/bgp_rd.c
bgpd/bgp_route.c
bgpd/bgp_updgrp_packet.c
bgpd/bgp_vty.c
bgpd/bgp_zebra.c
bgpd/bgpd.c
bgpd/bgpd.h
bgpd/rfapi/rfapi.c
bgpd/rfapi/rfapi_import.c
bgpd/rfapi/rfapi_monitor.c
bgpd/rfapi/rfapi_rib.c
bgpd/rfapi/rfapi_vty.c
common.am
configure.ac
doc/babeld.texi
eigrpd/eigrp_dump.c
eigrpd/eigrp_packet.c
eigrpd/eigrp_update.c
fpm/.gitignore
fpm/Makefile [new file with mode: 0644]
fpm/Makefile.am [deleted file]
fpm/fpm.proto
fpm/subdir.am [new file with mode: 0644]
isisd/Makefile.am
isisd/dict.c
isisd/isis_adjacency.c
isisd/isis_adjacency.h
isisd/isis_bpf.c
isisd/isis_circuit.c
isisd/isis_circuit.h
isisd/isis_common.h
isisd/isis_constants.h
isisd/isis_csm.c
isisd/isis_dr.c
isisd/isis_dynhn.c
isisd/isis_dynhn.h
isisd/isis_events.c
isisd/isis_lsp.c
isisd/isis_lsp.h
isisd/isis_main.c
isisd/isis_memory.c
isisd/isis_memory.h
isisd/isis_misc.c
isisd/isis_misc.h
isisd/isis_mt.c
isisd/isis_mt.h
isisd/isis_pdu.c
isisd/isis_pdu.h
isisd/isis_redist.c
isisd/isis_route.c
isisd/isis_routemap.c
isisd/isis_spf.c
isisd/isis_spf.h
isisd/isis_te.c
isisd/isis_te.h
isisd/isis_tlv.c [deleted file]
isisd/isis_tlv.h [deleted file]
isisd/isis_tlvs.c [new file with mode: 0644]
isisd/isis_tlvs.h [new file with mode: 0644]
isisd/isis_zebra.c
isisd/isisd.c
isisd/isisd.h
isisd/iso_checksum.c
ldpd/address.c
ldpd/l2vpn.c
ldpd/lde.c
ldpd/lde.h
ldpd/lde_lib.c
ldpd/ldp.h
ldpd/ldp_vty_cmds.c
ldpd/ldp_zebra.c
ldpd/ldpd.c
ldpd/ldpd.h
ldpd/neighbor.c
lib/.gitignore
lib/Makefile [new file with mode: 0644]
lib/Makefile.am [deleted file]
lib/command.c
lib/command.h
lib/command_graph.c
lib/command_lex.l
lib/command_parse.y
lib/defun_lex.l
lib/hash.c
lib/hash.h
lib/libospf.h
lib/log.c
lib/monotime.h
lib/prefix.c
lib/prefix.h
lib/pw.h [new file with mode: 0644]
lib/sbuf.c [new file with mode: 0644]
lib/sbuf.h [new file with mode: 0644]
lib/sockunion.c
lib/subdir.am [new file with mode: 0644]
lib/table.c
lib/thread.c
lib/thread.h
lib/vty.c
lib/vty.h
lib/zclient.c
lib/zclient.h
lib/zebra.h
m4/Makefile.am [deleted file]
nhrpd/nhrp_cache.c
nhrpd/nhrp_main.c
nhrpd/nhrp_route.c
ospf6d/ospf6_asbr.c
ospf6d/ospf6_lsa.c
ospf6d/ospf6_lsdb.c
ospf6d/ospf6_memory.c
ospf6d/ospf6_memory.h
ospf6d/ospf6_route.c
ospf6d/ospf6_route.h
ospf6d/ospf6_spf.c
ospfd/ospf_dump.c
ospfd/ospf_opaque.c
ospfd/ospf_opaque.h
ospfd/ospf_ri.c
ospfd/ospf_ri.h
ospfd/ospf_te.c
ospfd/ospf_te.h
ospfd/ospf_vty.c
ospfd/ospf_zebra.c
ospfd/ospfd.c
ospfd/ospfd.h
pimd/Makefile.am
pimd/WHY_SSM [deleted file]
pimd/pim_assert.c
pimd/pim_bfd.c
pimd/pim_cmd.c
pimd/pim_cmd.h
pimd/pim_hello.c
pimd/pim_iface.c
pimd/pim_iface.h
pimd/pim_ifchannel.c
pimd/pim_ifchannel.h
pimd/pim_igmp.c
pimd/pim_igmpv3.c
pimd/pim_instance.c [new file with mode: 0644]
pimd/pim_instance.h [new file with mode: 0644]
pimd/pim_join.c
pimd/pim_jp_agg.c
pimd/pim_main.c
pimd/pim_mroute.c
pimd/pim_mroute.h
pimd/pim_msdp.c
pimd/pim_msdp.h
pimd/pim_msdp_packet.c
pimd/pim_msdp_packet.h
pimd/pim_msdp_socket.c
pimd/pim_msdp_socket.h
pimd/pim_msg.c
pimd/pim_neighbor.c
pimd/pim_nht.c
pimd/pim_nht.h
pimd/pim_oil.c
pimd/pim_oil.h
pimd/pim_pim.c
pimd/pim_register.c
pimd/pim_register.h
pimd/pim_rp.c
pimd/pim_rp.h
pimd/pim_rpf.c
pimd/pim_rpf.h
pimd/pim_ssm.c
pimd/pim_ssm.h
pimd/pim_ssmpingd.c
pimd/pim_ssmpingd.h
pimd/pim_static.c
pimd/pim_static.h
pimd/pim_upstream.c
pimd/pim_upstream.h
pimd/pim_util.c
pimd/pim_vty.c
pimd/pim_vty.h
pimd/pim_zebra.c
pimd/pim_zebra.h
pimd/pim_zlookup.c
pimd/pim_zlookup.h
pimd/pimd.c
pimd/pimd.h
pimd/test_igmpv3_join.c
pkgsrc/Makefile.am [deleted file]
python/Makefile.am [deleted file]
qpb/.gitignore
qpb/Makefile [new file with mode: 0644]
qpb/Makefile.am [deleted file]
qpb/qpb.proto
qpb/qpb_allocator.c
qpb/subdir.am [new file with mode: 0644]
redhat/Makefile.am [deleted file]
redhat/frr.spec.in
ripd/rip_peer.c
ripngd/ripng_peer.c
snapcraft/Makefile.am [deleted file]
tests/.gitignore
tests/Makefile.am
tests/bgpd/test_capability.c
tests/bgpd/test_capability.py
tests/bgpd/test_mp_attr.c
tests/isisd/.gitignore [new file with mode: 0644]
tests/isisd/test_fuzz_isis_tlv.c [new file with mode: 0644]
tests/isisd/test_fuzz_isis_tlv.py [new file with mode: 0644]
tests/isisd/test_fuzz_isis_tlv_tests.h.gz [new file with mode: 0644]
vtysh/Makefile.am
vtysh/extract.pl.in
vtysh/vtysh.c
vtysh/vtysh.h
vtysh/vtysh_config.c
watchfrr/watchfrr.c
zebra/.gitignore
zebra/Makefile [new file with mode: 0644]
zebra/Makefile.am [deleted file]
zebra/debug.c
zebra/debug.h
zebra/if_ioctl.c
zebra/if_ioctl_solaris.c
zebra/if_netlink.c
zebra/if_sysctl.c
zebra/interface.c
zebra/ioctl.c
zebra/ioctl_solaris.c
zebra/ipforward_proc.c
zebra/ipforward_solaris.c
zebra/ipforward_sysctl.c
zebra/kernel_netlink.c
zebra/kernel_socket.c
zebra/main.c
zebra/rib.h
zebra/rt.h
zebra/rt_netlink.c
zebra/rt_socket.c
zebra/rtread_getmsg.c
zebra/rtread_netlink.c
zebra/rtread_sysctl.c
zebra/subdir.am [new file with mode: 0644]
zebra/zebra_fpm_netlink.c
zebra/zebra_mpls.c
zebra/zebra_mpls_netlink.c
zebra/zebra_mpls_null.c
zebra/zebra_mpls_openbsd.c
zebra/zebra_mroute.c
zebra/zebra_pw.c [new file with mode: 0644]
zebra/zebra_pw.h [new file with mode: 0644]
zebra/zebra_rib.c
zebra/zebra_rnh.c
zebra/zebra_rnh.h
zebra/zebra_routemap.c
zebra/zebra_static.c
zebra/zebra_static.h
zebra/zebra_vrf.c
zebra/zebra_vrf.h
zebra/zebra_vty.c
zebra/zebra_vxlan.c
zebra/zserv.c
zebra/zserv.h

index 0092ba8c1049b2b37a34fcf06bb175a8595ddfbf..7cfe4a97e3ca632535f6f238a9263c08a9df88f6 100644 (file)
@@ -1,23 +1,95 @@
 ## Process this file with automake to produce Makefile.in.
 
-SUBDIRS = lib qpb fpm @ZEBRA@ @LIBRFP@ @RFPTEST@ \
+AUTOMAKE_OPTIONS = subdir-objects 1.12
+include common.am
+
+AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir) -I$(top_builddir)/lib
+AM_CFLAGS = $(WERROR)
+DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\"
+LIBCAP = @LIBCAP@
+
+EXTRA_DIST =
+BUILT_SOURCES =
+CLEANFILES =
+
+examplesdir = $(exampledir)
+
+bin_PROGRAMS =
+sbin_PROGRAMS =
+noinst_PROGRAMS =
+noinst_HEADERS =
+noinst_LIBRARIES =
+lib_LTLIBRARIES =
+module_LTLIBRARIES =
+pkginclude_HEADERS =
+dist_examples_DATA =
+
+include lib/subdir.am
+include zebra/subdir.am
+include qpb/subdir.am
+include fpm/subdir.am
+
+SUBDIRS = . @LIBRFP@ @RFPTEST@ \
         @BGPD@ @RIPD@ @RIPNGD@ @OSPFD@ @OSPF6D@ @LDPD@ \
          @ISISD@ @PIMD@ @NHRPD@ @EIGRPD@ @BABELD@ \
-        @WATCHFRR@ @VTYSH@ @OSPFCLIENT@ @DOC@ m4 @pkgsrcdir@ \
-         redhat @SOLARIS@ tests tools snapcraft
+        @WATCHFRR@ @VTYSH@ @OSPFCLIENT@ @DOC@ \
+         @SOLARIS@ tests tools
 
-DIST_SUBDIRS = lib qpb fpm zebra bgpd ripd ripngd ospfd ospf6d ldpd \
-         isisd watchfrr vtysh ospfclient doc m4 pkgsrc redhat tests \
+DIST_SUBDIRS = . bgpd ripd ripngd ospfd ospf6d ldpd \
+         isisd watchfrr vtysh ospfclient doc tests \
          solaris pimd nhrpd eigrpd bgpd/rfp-example/librfp \
-         bgpd/rfp-example/rfptest tools snapcraft babeld python \
+         bgpd/rfp-example/rfptest tools babeld \
          # end
 
-EXTRA_DIST = aclocal.m4 SERVICES REPORTING-BUGS \
+if PKGSRC
+rcdir=@pkgsrcrcdir@
+rc_SCRIPTS = \
+       pkgsrc/bgpd.sh \
+       pkgsrc/ospf6d.sh \
+       pkgsrc/ospfd.sh \
+       pkgsrc/ripd.sh \
+       pkgsrc/ripngd.sh \
+       pkgsrc/zebra.sh \
+       # end
+endif
+
+EXTRA_DIST += \
+       REPORTING-BUGS \
+       SERVICES \
+       aclocal.m4 \
        update-autotools \
-       vtysh/Makefile.in vtysh/Makefile.am \
-       tools/rrcheck.pl tools/rrlookup.pl tools/zc.pl \
-       tools/zebra.el tools/multiple-bgpd.sh
+       m4/README.txt \
+       \
+       python/clidef.py \
+       python/clippy/__init__.py \
+       \
+       redhat/frr.init \
+       redhat/frr.service \
+       redhat/daemons \
+       redhat/frr.logrotate \
+       redhat/frr.pam \
+       redhat/frr.spec \
+       redhat/README.rpm_build.md \
+       \
+       snapcraft/snapcraft.yaml \
+       snapcraft/README.snap_build.md \
+       snapcraft/README.usage.md \
+       snapcraft/extra_version_info.txt \
+       snapcraft/scripts \
+       snapcraft/defaults \
+       snapcraft/helpers \
+       snapcraft/snap \
+       \
+       tools/multiple-bgpd.sh \
+       tools/rrcheck.pl \
+       tools/rrlookup.pl \
+       tools/zc.pl \
+       tools/zebra.el \
+       \
+       vtysh/Makefile.am \
+       vtysh/Makefile.in \
+       # end
 
 ACLOCAL_AMFLAGS = -I m4
 
-noinst_HEADERS = defaults.h
+noinst_HEADERS += defaults.h
index a4924ec7b7e5f9b647390952d507373ac4b1a8a1..a77453a73411a4696dcd041735d4c0b0ad5c8bc9 100644 (file)
@@ -9,8 +9,8 @@ debug babel common
 router babel
 ! network wlan0
 ! network eth0
-! redistribute kernel
-! no redistribute static
+! redistribute ipv4 kernel
+! no redistribute ipv6 static
 
 ! The defaults are fine for a wireless interface
 
index ef32b9cf923c0b32190bd72dbf7c53920304f459..dd187976377b15579536b59e4c5dc282d6c2a44b 100644 (file)
@@ -566,12 +566,6 @@ unsigned int attrhash_key_make(void *p)
        MIX(attr->nexthop.s_addr);
        MIX(attr->med);
        MIX(attr->local_pref);
-
-       key += attr->origin;
-       key += attr->nexthop.s_addr;
-       key += attr->med;
-       key += attr->local_pref;
-
        MIX(attr->aggregator_as);
        MIX(attr->aggregator_addr.s_addr);
        MIX(attr->weight);
@@ -1677,7 +1671,8 @@ int bgp_mp_reach_parse(struct bgp_attr_parser_args *args,
 {
        iana_afi_t pkt_afi;
        afi_t afi;
-       safi_t pkt_safi, safi;
+       iana_safi_t pkt_safi;
+       safi_t safi;
        bgp_size_t nlri_len;
        size_t start;
        struct stream *s;
@@ -1826,7 +1821,8 @@ int bgp_mp_unreach_parse(struct bgp_attr_parser_args *args,
        struct stream *s;
        iana_afi_t pkt_afi;
        afi_t afi;
-       safi_t pkt_safi, safi;
+       iana_safi_t pkt_safi;
+       safi_t safi;
        u_int16_t withdraw_len;
        struct peer *const peer = args->peer;
        struct attr *const attr = args->attr;
@@ -2593,7 +2589,7 @@ size_t bgp_packet_mpattr_start(struct stream *s, struct peer *peer, afi_t afi,
 {
        size_t sizep;
        iana_afi_t pkt_afi;
-       safi_t pkt_safi;
+       iana_safi_t pkt_safi;
        afi_t nh_afi;
 
        /* Set extended bit always to encode the attribute length as 2 bytes */
@@ -3280,7 +3276,7 @@ size_t bgp_packet_mpunreach_start(struct stream *s, afi_t afi, safi_t safi)
 {
        unsigned long attrlen_pnt;
        iana_afi_t pkt_afi;
-       safi_t pkt_safi;
+       iana_safi_t pkt_safi;
 
        /* Set extended bit always to encode the attribute length as 2 bytes */
        stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_EXTLEN);
index cd6b87b299d01c263e1809dd6acdea993f9390bf..2f0b566ccf0fa7c7c88bbe1b37dc542add17655b 100644 (file)
@@ -42,7 +42,7 @@ void bgp_add_routermac_ecom(struct attr *attr, struct ethaddr *routermac)
        memset(&routermac_ecom, 0, sizeof(struct ecommunity_val));
        routermac_ecom.val[0] = ECOMMUNITY_ENCODE_EVPN;
        routermac_ecom.val[1] = ECOMMUNITY_EVPN_SUBTYPE_ROUTERMAC;
-       memcpy(&routermac_ecom.val[2], routermac->octet, ETHER_ADDR_LEN);
+       memcpy(&routermac_ecom.val[2], routermac->octet, ETH_ALEN);
        if (!attr->ecommunity)
                attr->ecommunity = ecommunity_new();
        ecommunity_add_val(attr->ecommunity, &routermac_ecom);
index bd3ae27c054b3335fc581fa7c762a51b8d1ceec6..36ffb0e9c571ef72c5285f6ec1de2b86622dd5a5 100644 (file)
@@ -543,8 +543,6 @@ static const char *bgp_get_reuse_time(unsigned int penalty, char *buf,
                reuse_time = 0;
 
 /* Making formatted timer strings. */
-#define ONE_DAY_SECOND 60*60*24
-#define ONE_WEEK_SECOND 60*60*24*7
        if (reuse_time == 0) {
                if (use_json)
                        json_object_int_add(json, "reuseTimerMsecs", 0);
index f0081e6d020c38a042cae81fc5f5c25cb3cca042..fe311832a2fcc25762b353b9750e9bc76adfa2a2 100644 (file)
@@ -351,7 +351,7 @@ static int bgp_zebra_send_remote_macip(struct bgp *bgp, struct bgpevpn *vpn,
                s, add ? ZEBRA_REMOTE_MACIP_ADD : ZEBRA_REMOTE_MACIP_DEL,
                bgp->vrf_id);
        stream_putl(s, vpn->vni);
-       stream_put(s, &p->prefix.mac.octet, ETHER_ADDR_LEN); /* Mac Addr */
+       stream_put(s, &p->prefix.mac.octet, ETH_ALEN); /* Mac Addr */
        /* IP address length and IP address, if any. */
        if (IS_EVPN_PREFIX_IPADDR_NONE(p))
                stream_putl(s, 0);
@@ -1812,9 +1812,9 @@ static int process_type2_route(struct peer *peer, afi_t afi, safi_t safi,
        macaddr_len = *pfx++;
 
        /* Get the MAC Addr */
-       if (macaddr_len == (ETHER_ADDR_LEN * 8)) {
-               memcpy(&p.prefix.mac.octet, pfx, ETHER_ADDR_LEN);
-               pfx += ETHER_ADDR_LEN;
+       if (macaddr_len == (ETH_ALEN * 8)) {
+               memcpy(&p.prefix.mac.octet, pfx, ETH_ALEN);
+               pfx += ETH_ALEN;
        } else {
                zlog_err(
                        "%u:%s - Rx EVPN Type-2 NLRI with unsupported MAC address length %d",
@@ -2186,7 +2186,7 @@ char *bgp_evpn_route2str(struct prefix_evpn *p, char *buf, int len)
        } else if (p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) {
                if (IS_EVPN_PREFIX_IPADDR_NONE(p))
                        snprintf(buf, len, "[%d]:[0]:[0]:[%d]:[%s]",
-                                p->prefix.route_type, 8 * ETHER_ADDR_LEN,
+                                p->prefix.route_type, 8 * ETH_ALEN,
                                 prefix_mac2str(&p->prefix.mac, buf1,
                                                sizeof(buf1)));
                else {
@@ -2195,7 +2195,7 @@ char *bgp_evpn_route2str(struct prefix_evpn *p, char *buf, int len)
                        family = IS_EVPN_PREFIX_IPADDR_V4(p) ? AF_INET
                                                             : AF_INET6;
                        snprintf(buf, len, "[%d]:[0]:[0]:[%d]:[%s]:[%d]:[%s]",
-                                p->prefix.route_type, 8 * ETHER_ADDR_LEN,
+                                p->prefix.route_type, 8 * ETH_ALEN,
                                 prefix_mac2str(&p->prefix.mac, buf1,
                                                sizeof(buf1)),
                                 family == AF_INET ? IPV4_MAX_BITLEN
@@ -2237,7 +2237,7 @@ void bgp_evpn_encode_prefix(struct stream *s, struct prefix *p,
                stream_put(s, prd->val, 8);      /* RD */
                stream_put(s, 0, 10);               /* ESI */
                stream_putl(s, 0);                  /* Ethernet Tag ID */
-               stream_putc(s, 8 * ETHER_ADDR_LEN); /* Mac Addr Len - bits */
+               stream_putc(s, 8 * ETH_ALEN); /* Mac Addr Len - bits */
                stream_put(s, evp->prefix.mac.octet, 6); /* Mac Addr */
                stream_putc(s, 8 * ipa_len);             /* IP address Length */
                if (ipa_len)
index 816a7df98c28772c7e30aa59ca3d68b2bea4d05e..095dfa1b15049ab646f44c66d65dc753d70e27ef 100644 (file)
@@ -174,7 +174,7 @@ static inline void build_evpn_type2_prefix(struct prefix_evpn *p,
        p->family = AF_ETHERNET;
        p->prefixlen = EVPN_TYPE_2_ROUTE_PREFIXLEN;
        p->prefix.route_type = BGP_EVPN_MAC_IP_ROUTE;
-       memcpy(&p->prefix.mac.octet, mac->octet, ETHER_ADDR_LEN);
+       memcpy(&p->prefix.mac.octet, mac->octet, ETH_ALEN);
        p->prefix.ip.ipa_type = IPADDR_NONE;
        if (ip)
                memcpy(&p->prefix.ip, ip, sizeof(*ip));
index cf1cb1868966cecdb779c667a33040c2d0884d69..b609abac6994ab47fdf4b674edf29fd45e261350 100644 (file)
@@ -488,7 +488,7 @@ static int bgp_graceful_restart_timer_expire(struct thread *thread)
 
        /* NSF delete stale route */
        for (afi = AFI_IP; afi < AFI_MAX; afi++)
-               for (safi = SAFI_UNICAST; safi < SAFI_RESERVED_4; safi++)
+               for (safi = SAFI_UNICAST; safi <= SAFI_MPLS_VPN; safi++)
                        if (peer->nsf[afi][safi])
                                bgp_clear_stale_route(peer, afi, safi);
 
@@ -521,7 +521,7 @@ static int bgp_graceful_stale_timer_expire(struct thread *thread)
 
        /* NSF delete stale route */
        for (afi = AFI_IP; afi < AFI_MAX; afi++)
-               for (safi = SAFI_UNICAST; safi < SAFI_RESERVED_4; safi++)
+               for (safi = SAFI_UNICAST; safi <= SAFI_MPLS_VPN; safi++)
                        if (peer->nsf[afi][safi])
                                bgp_clear_stale_route(peer, afi, safi);
 
@@ -1022,7 +1022,7 @@ int bgp_stop(struct peer *peer)
 
                        for (afi = AFI_IP; afi < AFI_MAX; afi++)
                                for (safi = SAFI_UNICAST;
-                                    safi < SAFI_RESERVED_4; safi++)
+                                    safi <= SAFI_MPLS_VPN; safi++)
                                        peer->nsf[afi][safi] = 0;
                }
 
@@ -1425,7 +1425,7 @@ static int bgp_establish(struct peer *peer)
        /* graceful restart */
        UNSET_FLAG(peer->sflags, PEER_STATUS_NSF_WAIT);
        for (afi = AFI_IP; afi < AFI_MAX; afi++)
-               for (safi = SAFI_UNICAST; safi < SAFI_RESERVED_4; safi++) {
+               for (safi = SAFI_UNICAST; safi <= SAFI_MPLS_VPN; safi++) {
                        if (peer->afc_nego[afi][safi]
                            && CHECK_FLAG(peer->cap, PEER_CAP_RESTART_ADV)
                            && CHECK_FLAG(peer->af_cap[afi][safi],
index b18a4b7c46e6237bc63c2349dc5c0191066861ee..3ee865e3ba114c0ba642952ee3d17e73e7a09429 100644 (file)
@@ -271,7 +271,7 @@ static int bgp_capability_mp(struct peer *peer, struct capability_header *hdr)
 }
 
 static void bgp_capability_orf_not_support(struct peer *peer, iana_afi_t afi,
-                                          safi_t safi, u_char type,
+                                          iana_safi_t safi, u_char type,
                                           u_char mode)
 {
        if (bgp_debug_neighbor_events(peer))
@@ -298,7 +298,8 @@ static int bgp_capability_orf_entry(struct peer *peer,
        u_char num;
        iana_afi_t pkt_afi;
        afi_t afi;
-       safi_t pkt_safi, safi;
+       iana_safi_t pkt_safi;
+       safi_t safi;
        u_char type;
        u_char mode;
        u_int16_t sm_cap = 0; /* capability send-mode receive */
@@ -466,7 +467,7 @@ static int bgp_capability_restart(struct peer *peer,
                afi_t afi;
                safi_t safi;
                iana_afi_t pkt_afi = stream_getw(s);
-               safi_t pkt_safi = stream_getc(s);
+               iana_safi_t pkt_safi = stream_getc(s);
                u_char flag = stream_getc(s);
 
                /* Convert AFI, SAFI to internal values, check. */
@@ -543,7 +544,7 @@ static int bgp_capability_addpath(struct peer *peer,
                afi_t afi;
                safi_t safi;
                iana_afi_t pkt_afi = stream_getw(s);
-               safi_t pkt_safi = stream_getc(s);
+               iana_safi_t pkt_safi = stream_getc(s);
                u_char send_receive = stream_getc(s);
 
                if (bgp_debug_neighbor_events(peer))
@@ -600,7 +601,8 @@ static int bgp_capability_enhe(struct peer *peer, struct capability_header *hdr)
        while (stream_get_getp(s) + 6 <= end) {
                iana_afi_t pkt_afi = stream_getw(s);
                afi_t afi;
-               safi_t safi, pkt_safi = stream_getw(s);
+               iana_safi_t pkt_safi = stream_getw(s);
+               safi_t safi;
                iana_afi_t pkt_nh_afi = stream_getw(s);
                afi_t nh_afi;
 
@@ -1199,7 +1201,7 @@ static void bgp_open_capability_orf(struct stream *s, struct peer *peer,
        unsigned long numberp;
        int number_of_orfs = 0;
        iana_afi_t pkt_afi;
-       safi_t pkt_safi;
+       iana_safi_t pkt_safi;
 
        /* Convert AFI, SAFI to values for packet. */
        bgp_map_afi_safi_int2iana(afi, safi, &pkt_afi, &pkt_safi);
@@ -1264,7 +1266,8 @@ void bgp_open_capability(struct stream *s, struct peer *peer)
        unsigned long cp, capp, rcapp;
        iana_afi_t pkt_afi;
        afi_t afi;
-       safi_t safi, pkt_safi;
+       safi_t safi;
+       iana_safi_t pkt_safi;
        as_t local_as;
        u_int32_t restart_time;
        u_char afi_safi_count = 0;
index cbd32116b4a40e714fe716f066826fcd0fda3e9e..83b79a589a2aaa7418eaafc99c373a0bbc88ff54 100644 (file)
@@ -29,9 +29,9 @@ struct capability_header {
 
 /* Generic MP capability data */
 struct capability_mp_data {
-       iana_afi_t afi;
+       uint16_t afi; /* iana_afi_t */
        u_char reserved;
-       safi_t safi;
+       uint8_t safi; /* iana_safi_t */
 };
 
 struct capability_as4 {
index e92f2d69773efa41741e83112e34b9cac3b00e1f..003fbaff632913bdc0d5851da1503277a03e11c6 100644 (file)
@@ -142,7 +142,7 @@ static struct stream *bgp_update_packet_eor(struct peer *peer, afi_t afi,
 {
        struct stream *s;
        iana_afi_t pkt_afi;
-       safi_t pkt_safi;
+       iana_safi_t pkt_safi;
 
        if (DISABLE_BGP_ANNOUNCE)
                return NULL;
@@ -671,7 +671,7 @@ void bgp_route_refresh_send(struct peer *peer, afi_t afi, safi_t safi,
        struct bgp_filter *filter;
        int orf_refresh = 0;
        iana_afi_t pkt_afi;
-       safi_t pkt_safi;
+       iana_safi_t pkt_safi;
 
        if (DISABLE_BGP_ANNOUNCE)
                return;
@@ -761,7 +761,7 @@ void bgp_capability_send(struct peer *peer, afi_t afi, safi_t safi,
 {
        struct stream *s;
        iana_afi_t pkt_afi;
-       safi_t pkt_safi;
+       iana_safi_t pkt_safi;
 
        /* Convert AFI, SAFI to values for packet. */
        bgp_map_afi_safi_int2iana(afi, safi, &pkt_afi, &pkt_safi);
@@ -1338,8 +1338,9 @@ int bgp_nlri_parse(struct peer *peer, struct attr *attr,
                                          packet);
        case SAFI_EVPN:
                return bgp_nlri_parse_evpn(peer, attr, packet, mp_withdraw);
+       default:
+               return -1;
        }
-       return -1;
 }
 
 /* Parse BGP Update packet and make attribute object. */
@@ -1697,7 +1698,8 @@ static void bgp_route_refresh_receive(struct peer *peer, bgp_size_t size)
 {
        iana_afi_t pkt_afi;
        afi_t afi;
-       safi_t pkt_safi, safi;
+       iana_safi_t pkt_safi;
+       safi_t safi;
        struct stream *s;
        struct peer_af *paf;
        struct update_group *updgrp;
@@ -1965,7 +1967,8 @@ static int bgp_capability_msg_parse(struct peer *peer, u_char *pnt,
        u_char action;
        iana_afi_t pkt_afi;
        afi_t afi;
-       safi_t pkt_safi, safi;
+       iana_safi_t pkt_safi;
+       safi_t safi;
 
        end = pnt + length;
 
index fd01693942d4b9b8d9fb0f596baf0cd02ffa66e8..a15828bd36a9402194ff82d72ba24b7a0dc97c97 100644 (file)
@@ -98,7 +98,7 @@ void decode_rd_vnc_eth(u_char *pnt, struct rd_vnc_eth *rd_vnc_eth)
 {
        rd_vnc_eth->type = RD_TYPE_VNC_ETH;
        rd_vnc_eth->local_nve_id = pnt[1];
-       memcpy(rd_vnc_eth->macaddr.octet, pnt + 2, ETHER_ADDR_LEN);
+       memcpy(rd_vnc_eth->macaddr.octet, pnt + 2, ETH_ALEN);
 }
 #endif
 
index b554aeb32b5c2b83d76d141c6ba189946629d57f..e4e421510f2a7905366aff997aae510fd7a69a33 100644 (file)
@@ -2078,7 +2078,7 @@ static wq_item_status bgp_process_main(struct work_queue *wq, void *data)
                        vnc_import_bgp_add_route(bgp, p, old_select);
                        vnc_import_bgp_exterior_add_route(bgp, p, old_select);
 #endif
-                       if (bgp_fibupd_safi(safi) && !bgp->name
+                       if (bgp_fibupd_safi(safi)
                            && !bgp_option_check(BGP_OPT_NO_FIB)
                            && new_select->type == ZEBRA_ROUTE_BGP
                            && new_select->sub_type == BGP_ROUTE_NORMAL)
@@ -2288,7 +2288,7 @@ int bgp_maximum_prefix_overflow(struct peer *peer, afi_t afi, safi_t safi,
                                int always)
 {
        iana_afi_t pkt_afi;
-       safi_t pkt_safi;
+       iana_safi_t pkt_safi;
 
        if (!CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX))
                return 0;
@@ -4775,7 +4775,7 @@ int bgp_static_set_safi(afi_t afi, safi_t safi, struct vty *vty,
                        }
                        if (routermac) {
                                bgp_static->router_mac =
-                                       XCALLOC(MTYPE_ATTR, ETHER_ADDR_LEN + 1);
+                                       XCALLOC(MTYPE_ATTR, ETH_ALEN + 1);
                                prefix_str2mac(routermac,
                                               bgp_static->router_mac);
                        }
index 1a23a36e91a2bec06557ac1903f27226aa0606cb..692db32fa41463d9ce7989d5d7d7967bdbcdab41 100644 (file)
@@ -845,7 +845,7 @@ struct bpacket *subgroup_update_packet(struct update_subgroup *subgrp)
                                           send_attr_str);
                                if (!stream_empty(snlri)) {
                                        iana_afi_t pkt_afi;
-                                       safi_t pkt_safi;
+                                       iana_safi_t pkt_safi;
 
                                        pkt_afi = afi_int2iana(afi);
                                        pkt_safi = safi_int2iana(safi);
@@ -989,7 +989,7 @@ struct bpacket *subgroup_withdraw_packet(struct update_subgroup *subgrp)
                        /* If first time, format the MP_UNREACH header */
                        if (first_time) {
                                iana_afi_t pkt_afi;
-                               safi_t pkt_safi;
+                               iana_safi_t pkt_safi;
 
                                pkt_afi = afi_int2iana(afi);
                                pkt_safi = safi_int2iana(safi);
index 65a1473f75ef4b4e3e7d78213ab96f7a477b027b..0220a7e55de21281169cc73889014e0adcce3c4b 100644 (file)
@@ -78,6 +78,10 @@ static enum node_type bgp_node_type(afi_t afi, safi_t safi)
                case SAFI_MPLS_VPN:
                        return BGP_VPNV4_NODE;
                        break;
+               default:
+                       /* not expected */
+                       return BGP_IPV4_NODE;
+                       break;
                }
                break;
        case AFI_IP6:
@@ -94,6 +98,10 @@ static enum node_type bgp_node_type(afi_t afi, safi_t safi)
                case SAFI_MPLS_VPN:
                        return BGP_VPNV6_NODE;
                        break;
+               default:
+                       /* not expected */
+                       return BGP_IPV4_NODE;
+                       break;
                }
                break;
        case AFI_L2VPN:
@@ -7079,12 +7087,6 @@ static void bgp_show_summary_afi_safi(struct vty *vty, struct bgp *bgp, int afi,
                                                 json);
                        }
                        safi++;
-                       if (safi == SAFI_RESERVED_4
-                           || safi
-                                      == SAFI_RESERVED_5) /* handle special
-                                                             cases to match
-                                                             zebra.h */
-                               safi++;
                        if (!safi_wildcard)
                                safi = SAFI_MAX;
                }
index 4870e54aec991b390db1021877aff58464dbc433..5071be909e61c775da096b6e5028e0b77e67e04e 100644 (file)
@@ -2125,7 +2125,7 @@ static int bgp_zebra_process_local_macip(int command, struct zclient *zclient,
        memset(&ip, 0, sizeof(ip));
        s = zclient->ibuf;
        vni = stream_getl(s);
-       stream_get(&mac.octet, s, ETHER_ADDR_LEN);
+       stream_get(&mac.octet, s, ETH_ALEN);
        ipa_len = stream_getl(s);
        if (ipa_len != 0 && ipa_len != IPV4_MAX_BYTELEN
            && ipa_len != IPV6_MAX_BYTELEN) {
index a0e2d6749a735064fe7b2a13c2eaf3d779e19977..d30def0f07837f5db361068305f585d6f51fba67 100644 (file)
@@ -611,8 +611,8 @@ int bgp_listen_limit_unset(struct bgp *bgp)
        return 0;
 }
 
-int bgp_map_afi_safi_iana2int(iana_afi_t pkt_afi, safi_t pkt_safi, afi_t *afi,
-                             safi_t *safi)
+int bgp_map_afi_safi_iana2int(iana_afi_t pkt_afi, iana_safi_t pkt_safi,
+                             afi_t *afi, safi_t *safi)
 {
        /* Map from IANA values to internal values, return error if
         * values are unrecognized.
@@ -626,7 +626,7 @@ int bgp_map_afi_safi_iana2int(iana_afi_t pkt_afi, safi_t pkt_safi, afi_t *afi,
 }
 
 int bgp_map_afi_safi_int2iana(afi_t afi, safi_t safi, iana_afi_t *pkt_afi,
-                             safi_t *pkt_safi)
+                             iana_safi_t *pkt_safi)
 {
        /* Map from internal values to IANA values, return error if
         * internal values are bad (unexpected).
@@ -746,7 +746,7 @@ static unsigned int peer_hash_key_make(void *p)
        return sockunion_hash(&peer->su);
 }
 
-static int peer_hash_cmp(const void *p1, const void *p2)
+static int peer_hash_same(const void *p1, const void *p2)
 {
        const struct peer *peer1 = p1;
        const struct peer *peer2 = p2;
@@ -1842,7 +1842,7 @@ static void peer_nsf_stop(struct peer *peer)
        UNSET_FLAG(peer->sflags, PEER_STATUS_NSF_MODE);
 
        for (afi = AFI_IP; afi < AFI_MAX; afi++)
-               for (safi = SAFI_UNICAST; safi < SAFI_RESERVED_4; safi++)
+               for (safi = SAFI_UNICAST; safi <= SAFI_MPLS_VPN; safi++)
                        peer->nsf[afi][safi] = 0;
 
        if (peer->t_gr_restart) {
@@ -2757,7 +2757,8 @@ static struct bgp *bgp_create(as_t *as, const char *name,
                XSTRDUP(MTYPE_BGP_PEER_HOST, "Static announcement");
        bgp->peer = list_new();
        bgp->peer->cmp = (int (*)(void *, void *))peer_cmp;
-       bgp->peerhash = hash_create(peer_hash_key_make, peer_hash_cmp, NULL);
+       bgp->peerhash = hash_create(peer_hash_key_make, peer_hash_same, NULL);
+       bgp->peerhash->max_size = BGP_PEER_MAX_HASH_SIZE;
 
        bgp->group = list_new();
        bgp->group->cmp = (int (*)(void *, void *))peer_group_cmp;
@@ -6109,11 +6110,6 @@ char *peer_uptime(time_t uptime2, char *buf, size_t len, u_char use_json,
        uptime1 -= uptime2;
        tm = gmtime(&uptime1);
 
-/* Making formatted timer strings. */
-#define ONE_DAY_SECOND 60*60*24
-#define ONE_WEEK_SECOND ONE_DAY_SECOND*7
-#define ONE_YEAR_SECOND ONE_DAY_SECOND*365
-
        if (uptime1 < ONE_DAY_SECOND)
                snprintf(buf, len, "%02d:%02d:%02d", tm->tm_hour, tm->tm_min,
                         tm->tm_sec);
index 67b8289c70bccbeddb890c88ff21b9cab2de3fc0..208a4e4b4e5964a17bc4dfe7a6829de252f81e5a 100644 (file)
@@ -36,6 +36,7 @@
 #include "bitfield.h"
 
 #define BGP_MAX_HOSTNAME 64    /* Linux max, is larger than most other sys */
+#define BGP_PEER_MAX_HASH_SIZE 16384
 
 /* Default interval for IPv6 RAs when triggered by BGP unnumbered neighbor. */
 #define BGP_UNNUM_DEFAULT_RA_INTERVAL 10
@@ -922,10 +923,10 @@ DECLARE_QOBJ_TYPE(peer)
    stream. */
 struct bgp_nlri {
        /* AFI.  */
-       afi_t afi;
+       uint16_t afi; /* iana_afi_t */
 
        /* SAFI.  */
-       safi_t safi;
+       uint8_t safi; /* iana_safi_t */
 
        /* Pointer to NLRI byte stream.  */
        u_char *nlri;
@@ -1381,10 +1382,10 @@ extern void bgp_route_map_terminate(void);
 
 extern int peer_cmp(struct peer *p1, struct peer *p2);
 
-extern int bgp_map_afi_safi_iana2int(iana_afi_t pkt_afi, safi_t pkt_safi,
+extern int bgp_map_afi_safi_iana2int(iana_afi_t pkt_afi, iana_safi_t pkt_safi,
                                     afi_t *afi, safi_t *safi);
 extern int bgp_map_afi_safi_int2iana(afi_t afi, safi_t safi,
-                                    iana_afi_t *pkt_afi, safi_t *pkt_safi);
+                                    iana_afi_t *pkt_afi, iana_safi_t *pkt_safi);
 
 extern struct peer_af *peer_af_create(struct peer *, afi_t, safi_t);
 extern struct peer_af *peer_af_find(struct peer *, afi_t, safi_t);
index ab71eda126d5ed1abf2a29318c5713bb55e9fc6a..477716cafbc4f67647e1aef443bed9e50785d2c4 100644 (file)
@@ -1568,7 +1568,7 @@ rfapi_query_inner(void *handle, struct rfapi_ip_addr *target,
 
        if (l2o) {
                if (!memcmp(l2o->macaddr.octet, rfapi_ethaddr0.octet,
-                           ETHER_ADDR_LEN)) {
+                           ETH_ALEN)) {
                        eth_is_0 = 1;
                }
                /* per t/c Paul/Lou 151022 */
@@ -3416,7 +3416,7 @@ DEFUN (debug_rfapi_query_vn_un_l2o,
        /* construct option chain */
 
        memset(valbuf, 0, sizeof(valbuf));
-       memcpy(valbuf, &l2o_buf.macaddr.octet, ETHER_ADDR_LEN);
+       memcpy(valbuf, &l2o_buf.macaddr.octet, ETH_ALEN);
        valbuf[11] = (l2o_buf.logical_net_id >> 16) & 0xff;
        valbuf[12] = (l2o_buf.logical_net_id >> 8) & 0xff;
        valbuf[13] = l2o_buf.logical_net_id & 0xff;
index 0bbbe12ccef3c4e302d674b29e030c75435e02ca..7e0ed9150bb8f04b2a4d75d3c8d0fe30d677677e 100644 (file)
@@ -308,7 +308,7 @@ int rfapiGetL2o(struct attr *attr, struct rfapi_l2address_option *l2o)
                                        if (pEncap->value[1] == 14) {
                                                memcpy(l2o->macaddr.octet,
                                                       pEncap->value + 2,
-                                                      ETHER_ADDR_LEN);
+                                                      ETH_ALEN);
                                                l2o->label =
                                                        ((pEncap->value[10]
                                                          >> 4)
@@ -1327,7 +1327,7 @@ rfapiRouteInfo2NextHopEntry(struct rfapi_ip_prefix *rprefix,
                vo->type = RFAPI_VN_OPTION_TYPE_L2ADDR;
 
                memcpy(&vo->v.l2addr.macaddr, &rn->p.u.prefix_eth.octet,
-                      ETHER_ADDR_LEN);
+                      ETH_ALEN);
                /* only low 3 bytes of this are significant */
                if (bi->attr) {
                        (void)rfapiEcommunityGetLNI(
@@ -3872,6 +3872,10 @@ rfapiBgpInfoFilteredImportFunction(safi_t safi)
 
        case SAFI_ENCAP:
                return rfapiBgpInfoFilteredImportEncap;
+
+       default:
+               /* not expected */
+               return NULL;
        }
        zlog_err("%s: bad safi %d", __func__, safi);
        return NULL;
index 9c0d9da6ff916332e7a2208a58ab7b78ba7c5389..6a7595443a844286249043a17f1c69d4745d8699 100644 (file)
@@ -805,7 +805,7 @@ void rfapiMonitorTimersRestart(struct rfapi_descriptor *rfd, struct prefix *p)
                                                 (void **)&mon_eth, &cursor)) {
 
                        if (!memcmp(mon_eth->macaddr.octet,
-                                   p->u.prefix_eth.octet, ETHER_ADDR_LEN)) {
+                                   p->u.prefix_eth.octet, ETH_ALEN)) {
 
                                rfapiMonitorEthTimerRestart(mon_eth);
                        }
@@ -1117,7 +1117,7 @@ static int mon_eth_cmp(void *a, void *b)
        /*
         * compare ethernet addresses
         */
-       for (i = 0; i < ETHER_ADDR_LEN; ++i) {
+       for (i = 0; i < ETH_ALEN; ++i) {
                if (m1->macaddr.octet[i] != m2->macaddr.octet[i])
                        return (m1->macaddr.octet[i] - m2->macaddr.octet[i]);
        }
index 791eb4c916ed09f0c8678c056cdd5e382d0f8b51..748c0c476b1d41ecca8de66e8c449b25592952c2 100644 (file)
@@ -687,7 +687,7 @@ static void rfapiRibBi2Ri(struct bgp_info *bi, struct rfapi_info *ri,
                /* copy from RD already stored in bi, so we don't need it_node
                 */
                memcpy(&vo->v.l2addr.macaddr, bi->extra->vnc.import.rd.val + 2,
-                      ETHER_ADDR_LEN);
+                      ETH_ALEN);
 
                if (bi->attr) {
                        (void)rfapiEcommunityGetLNI(
index 98c3decbd8124bf6e691cf6e6e7b586f251f72f2..e7314d29834d2f661e3a501d8214041116b4f409 100644 (file)
@@ -3092,7 +3092,7 @@ static int rfapiDeleteLocalPrefixesByRFD(struct rfapi_local_reg_delete_arg *cda,
                                        if (memcmp(cda->l2o.o.macaddr.octet,
                                                   adb->u.s.prefix_eth.u
                                                           .prefix_eth.octet,
-                                                  ETHER_ADDR_LEN)) {
+                                                  ETH_ALEN)) {
 #if DEBUG_L2_EXTRA
                                                vnc_zlog_debug_verbose(
                                                        "%s: adb=%p, macaddr doesn't match, skipping",
@@ -3211,7 +3211,7 @@ static int rfapiDeleteLocalPrefixesByRFD(struct rfapi_local_reg_delete_arg *cda,
                                                           adb->u.s.prefix_eth.u
                                                                   .prefix_eth
                                                                   .octet,
-                                                          ETHER_ADDR_LEN)) {
+                                                          ETH_ALEN)) {
 
                                                        continue;
                                                }
index 0ccc4c9fd153984c578b0788de20c217f5df11e0..b115a871b9797d05b518a35f6a24b489ec07221e 100644 (file)
--- a/common.am
+++ b/common.am
@@ -8,12 +8,21 @@ am__v_CLIPPY_ = $(am__v_CLIPPY_$(AM_DEFAULT_VERBOSITY))
 am__v_CLIPPY_0 = @echo "  CLIPPY  " $@;
 am__v_CLIPPY_1 =
 
-SUFFIXES = _clippy.c
+CLIPPY_DEPS = $(HOSTTOOLS)lib/clippy $(top_srcdir)/python/clidef.py
+
+SUFFIXES = _clippy.c .proto .pb-c.c .pb-c.h .pb.h
 .c_clippy.c:
-       $(AM_V_at)$(MAKE) -C $(top_builddir)/$(CLIPPYDIR) clippy
-       $(AM_V_CLIPPY)$(top_builddir)/$(CLIPPYDIR)/clippy $(top_srcdir)/python/clidef.py $< > $@.tmp
+       @{ test -x $(top_builddir)/$(HOSTTOOLS)lib/clippy || $(MAKE) -C $(top_builddir)/$(HOSTTOOLS) lib/clippy; }
+       $(AM_V_CLIPPY)$(top_builddir)/$(HOSTTOOLS)lib/clippy $(top_srcdir)/python/clidef.py $< > $@.tmp
        @{ test -f $@ && diff $@.tmp $@ >/dev/null 2>/dev/null; } && rm $@.tmp || mv $@.tmp $@
 
+## automake's "ylwrap" is a great piece of GNU software... not. 
+.l.c:
+       $(AM_V_LEX)$(am__skiplex) $(LEXCOMPILE) $<
+.y.c:
+       $(AM_V_YACC)$(am__skipyacc) $(YACCCOMPILE) $<
+
+
 if HAVE_PROTOBUF
 
 # Uncomment to use an non-system version of libprotobuf-c.
@@ -27,16 +36,19 @@ Q_PROTOBUF_C_CLIENT_LDOPTS=-lprotobuf-c
 Q_PROTOC=protoc
 Q_PROTOC_C=protoc-c
 
-Q_PROTOBUF_CFILES = $(filter %.pb-c.c,$(SOURCES))
-
-Q_PROTOBUF_SRCS = $(Q_PROTOBUF_CFILES) $(Q_PROTOBUF_HFILES)
-
 # Rules
-%.pb.h: %.proto
-       $(Q_PROTOC) $(PROTOBUF_INCLUDES) --cpp_out=$(top_srcdir) $(top_srcdir)/$(PROTOBUF_PACKAGE)/$^
+.proto.pb.h:
+       $(Q_PROTOC) -I$(top_srcdir) --cpp_out=$(top_srcdir) $(top_srcdir)/$^
+
+AM_V_PROTOC_C = $(am__v_PROTOC_C_$(V))
+am__v_PROTOC_C_ = $(am__v_PROTOC_C_$(AM_DEFAULT_VERBOSITY))
+am__v_PROTOC_C_0 = @echo "  PROTOC_C" $@;
+am__v_PROTOC_C_1 =
 
-%.pb-c.c %.pb-c.h: %.proto
-       $(Q_PROTOC_C) $(PROTOBUF_INCLUDES) --c_out=$(top_srcdir) $(top_srcdir)/$(PROTOBUF_PACKAGE)/$^
+.proto.pb-c.c:
+       $(AM_V_PROTOC_C)$(Q_PROTOC_C) -I$(top_srcdir) --c_out=$(top_srcdir) $(top_srcdir)/$^
+.pb-c.c.pb-c.h:
+       @/bin/true
 
 #
 # Information about how to link to various libraries.
@@ -46,7 +58,3 @@ Q_FRR_PB_CLIENT_LDOPTS = $(top_srcdir)/qpb/libfrr_pb.la $(Q_PROTOBUF_C_CLIENT_LD
 Q_FPM_PB_CLIENT_LDOPTS = $(top_srcdir)/fpm/libfrrfpm_pb.la $(Q_FRR_PB_CLIENT_LDOPTS)
 
 endif  # HAVE_PROTOBUF
-
-Q_CLEANFILES = $(Q_PROTOBUF_SRCS)
-
-Q_BUILT_SRCS = $(Q_PROTOBUF_SRCS)
index cbda2fc84fe8c6a0b15529500d04f5161ac78a63..6b5cd19a5f5bcad7b0c585cfda03aa377e1aeeb8 100755 (executable)
@@ -46,12 +46,12 @@ AS_IF([test "$host" != "$build"], [
   AC_MSG_NOTICE([...])
 
   build_clippy="false"
-  CLIPPYDIR="hosttools/lib"
+  HOSTTOOLS="hosttools/"
 ], [
   build_clippy="true"
-  CLIPPYDIR="lib"
+  HOSTTOOLS=""
 ])
-AC_SUBST(CLIPPYDIR)
+AC_SUBST(HOSTTOOLS)
 AM_CONDITIONAL([BUILD_CLIPPY], [$build_clippy])
 
 # Disable portability warnings -- our automake code (in particular
@@ -75,14 +75,13 @@ AC_SUBST(exampledir)
 
 dnl default is to match previous behavior
 pkgsrcrcdir=""
-pkgsrcdir=""
 AC_ARG_ENABLE([pkgsrcrcdir],
          AS_HELP_STRING([--enable-pkgsrcrcdir],
                         [specify directory for rc.d scripts]),
-                        pkgsrcrcdir="$enableval"; pkgsrcdir="pkgsrc",)
+                        pkgsrcrcdir="$enableval",)
 dnl XXX add --pkgsrcrcdir to autoconf standard directory list somehow
-AC_SUBST(pkgsrcdir)
 AC_SUBST(pkgsrcrcdir)
+AM_CONDITIONAL([PKGSRC], [test "x$pkgsrcrcdir" != "x"])
 
 AC_ARG_WITH([moduledir], [AS_HELP_STRING([--with-moduledir=DIR], [module directory (${libdir}/frr/modules)])], [
        moduledir="$withval"
@@ -379,7 +378,7 @@ AC_ARG_ENABLE([oldvpn_commands],
   AS_HELP_STRING([--enable-oldvpn-commands], [Keep old vpn commands]))
 
 AC_CHECK_HEADERS(json-c/json.h)
-AC_CHECK_LIB(json-c, json_object_get, LIBS="$LIBS -ljson-c")
+AC_CHECK_LIB(json-c, json_object_get, LIBS="$LIBS -ljson-c", [], [-lm])
 if test $ac_cv_lib_json_c_json_object_get = no; then
   AC_CHECK_LIB(json, json_object_get, LIBS="$LIBS -ljson")
   if test $ac_cv_lib_json_json_object_get = no; then
@@ -415,26 +414,6 @@ if test "${enable_rr_semantics}" != "no" ; then
   AC_DEFINE(HAVE_V6_RR_SEMANTICS,, Compile in v6 Route Replacement Semantics)
 fi
 
-dnl ----------
-dnl MPLS check
-dnl ----------
-AC_MSG_CHECKING(whether this OS has MPLS stack)
-case "$host" in
-  *-linux*)
-      MPLS_METHOD="zebra_mpls_netlink.o"
-      AC_MSG_RESULT(Linux MPLS)
-  ;;
-  *-openbsd*)
-      MPLS_METHOD="zebra_mpls_openbsd.o"
-      AC_MSG_RESULT(OpenBSD MPLS)
-  ;;
-  *)
-      MPLS_METHOD="zebra_mpls_null.o"
-      AC_MSG_RESULT(Unsupported kernel)
-  ;;
-esac
-AC_SUBST(MPLS_METHOD)
-
 if test "${enable_datacenter}" = "yes" ; then
   AC_DEFINE(HAVE_DATACENTER,,Compile extensions for a DataCenter)
   DFLT_NAME="datacenter"
@@ -850,50 +829,62 @@ FRR_INCLUDES
 
 dnl V6 headers are checked below, after we check for v6
 
-dnl Some systems (Solaris 2.x) require libnsl (Network Services Library)
-case "$host" in
-  [*-sunos5.[6-7]*] | [*-solaris2.[6-7]*])
-      opsys=sol2-6
-      AC_DEFINE(SUNOS_56, 1, SunOS 5.6 to 5.7)
-      AC_DEFINE(SUNOS_5, 1, SunOS 5)
-      AC_CHECK_LIB(xnet, main)
-      CURSES=-lcurses
-      SOLARIS="solaris"
-  ;;
-  [*-sunos5.[8-9]] \
-  | [*-sunos5.1[0-9]] \
-  | [*-sunos5.1[0-9].[0-9]] \
-  | [*-solaris2.[8-9]] \
-  | [*-solaris2.1[0-9]] \
-  | [*-solaris2.1[0-9].[0-9]])
-      opsys=sol8
-      AC_DEFINE(SUNOS_59, 1, [SunOS 5.8 up])
-      AC_DEFINE(SUNOS_5, 1, [SunOS 5])
-      AC_CHECK_LIB(socket, main)
-      AC_CHECK_LIB(nsl, main)
-      AC_CHECK_LIB(umem, main)
-      AC_CHECK_FUNCS([printstack],
-       [AC_DEFINE([HAVE_PRINTSTACK],1,[Solaris printstack])
-        AC_DEFINE([HAVE_STACK_TRACE],1,[Stack symbols decode functionality])
-       ])
-      CURSES=-lcurses
-      SOLARIS="solaris"
-  ;;
-  *-sunos5* | *-solaris2*)
-      AC_DEFINE(SUNOS_5,,SunOS 5, Unknown SunOS)
-      AC_CHECK_LIB(socket, main)
-      AC_CHECK_LIB(nsl, main)
-      CURSES=-lcurses
-      SOLARIS="solaris"
-  ;;
-  *-linux*)
-      opsys=gnu-linux
-      AC_DEFINE(GNU_LINUX,,GNU Linux)
-  ;;
-  *-openbsd*)
-      opsys=openbsd
-      AC_DEFINE(OPEN_BSD,,OpenBSD)
-  ;;
+AC_MSG_CHECKING([which operating system interface to use])
+case "$host_os" in
+  sunos* | solaris2*)
+    AC_MSG_RESULT([Solaris])
+
+    AC_DEFINE(SUNOS_5, 1, [SunOS 5])
+    AC_DEFINE(SOLARIS_IPV6, 1, Solaris IPv6)
+
+    AC_CHECK_LIB(socket, main)
+    AC_CHECK_LIB(nsl, main)
+    AC_CHECK_LIB(umem, main)
+    AC_CHECK_FUNCS([printstack], [
+      AC_DEFINE([HAVE_PRINTSTACK],1,[Solaris printstack])
+      AC_DEFINE([HAVE_STACK_TRACE],1,[Stack symbols decode functionality])
+    ])
+    CURSES=-lcurses
+    SOLARIS="solaris"
+    ;;
+  linux*)
+    AC_MSG_RESULT([Linux])
+
+    AC_DEFINE(GNU_LINUX,,GNU Linux)
+    AC_DEFINE(HAVE_NETLINK,,netlink)
+    AC_DEFINE(LINUX_IPV6,1,Linux IPv6 stack)
+
+    dnl Linux has a compilation problem with mixing
+    dnl netinet/in.h and linux/in6.h they are not
+    dnl compatible.  There has been discussion on
+    dnl how to fix it but no real progress on implementation
+    dnl when they fix it, remove this
+    AC_DEFINE(IPV6_MINHOPCOUNT, 73, Linux ipv6 Min Hop Count)
+
+    AC_CHECK_DECLS([IFLA_INFO_SLAVE_KIND], [], [], [#include <linux/if_link.h>])
+    ;;
+  openbsd*)
+    AC_MSG_RESULT([OpenBSD])
+
+    AC_DEFINE(OPEN_BSD,,OpenBSD)
+    AC_DEFINE(KAME,1,KAME IPv6)
+
+    if test "x${enable_pimd}" != "xno"; then
+      case "$host_os" in
+      openbsd6.0)
+        ;;
+      openbsd[6-9]*)
+        AC_MSG_FAILURE([pimd cannot be enabled as PIM support has been removed from OpenBSD 6.1])
+        ;;
+      esac
+    fi
+    ;;
+  *)
+    AC_MSG_RESULT([BSD])
+
+    AC_DEFINE(HAVE_NET_RT_IFLIST,,NET_RT_IFLIST)
+    AC_DEFINE(KAME,1,KAME IPv6)
+    ;;
 esac
 
 AC_SYS_LARGEFILE
@@ -1049,26 +1040,6 @@ AC_CHECK_HEADER([asm-generic/unistd.h],
                  AC_CHECK_FUNCS(setns)]
                )
 
-dnl ------------------------------------
-dnl Determine routing get and set method
-dnl ------------------------------------
-AC_MSG_CHECKING(zebra between kernel interface method)
-if test x"$opsys" = x"gnu-linux"; then
-  AC_MSG_RESULT(netlink)
-  RT_METHOD=rt_netlink.o
-  KERNEL_METHOD=kernel_netlink.o
-  AC_DEFINE(HAVE_NETLINK,,netlink)
-  netlink=yes
-  AC_CHECK_DECLS([IFLA_INFO_SLAVE_KIND], [], [], [#include <linux/if_link.h>])
-else
-  AC_MSG_RESULT(Route socket)
-  KERNEL_METHOD="kernel_socket.o"
-  RT_METHOD="rt_socket.o"
-fi
-AC_SUBST(RT_METHOD)
-AC_SUBST(KERNEL_METHOD)
-AM_CONDITIONAL([HAVE_NETLINK], [test "x$netlink" = "xyes"])
-
 dnl --------------------------
 dnl Determine IS-IS I/O method
 dnl --------------------------
@@ -1078,27 +1049,32 @@ AC_DEFINE(ISIS_METHOD_BPF,      3, [ constant value for isis method bpf ])
 AC_CHECK_HEADER(net/bpf.h)
 AC_CHECK_HEADER(sys/dlpi.h)
 AC_MSG_CHECKING(zebra IS-IS I/O method)
-if test x"$opsys" = x"gnu-linux"; then
-  AC_MSG_RESULT(pfpacket)
-  ISIS_METHOD_MACRO="ISIS_METHOD_PFPACKET"
-elif test x"$opsys" = x"sol2-6" -o x"$opsys" = x"sol8"; then
-  AC_MSG_RESULT(DLPI)
-  ISIS_METHOD_MACRO="ISIS_METHOD_DLPI"
-else
-  if test $ac_cv_header_net_bpf_h = no; then
-    if test $ac_cv_header_sys_dlpi_h = no; then
-      AC_MSG_RESULT(none)
-      AC_MSG_WARN([*** IS-IS support will not be built ***])
-      ISISD=""
+
+case "$host_os" in
+  linux*)
+    AC_MSG_RESULT(pfpacket)
+    ISIS_METHOD_MACRO="ISIS_METHOD_PFPACKET"
+    ;;
+  solaris* | sunos*)
+    AC_MSG_RESULT(DLPI)
+    ISIS_METHOD_MACRO="ISIS_METHOD_DLPI"
+    ;;
+  *)
+    if test $ac_cv_header_net_bpf_h = no; then
+      if test $ac_cv_header_sys_dlpi_h = no; then
+        AC_MSG_RESULT(none)
+        AC_MSG_WARN([*** IS-IS support will not be built ***])
+        ISISD=""
+      else
+        AC_MSG_RESULT(DLPI)
+      fi
+      ISIS_METHOD_MACRO="ISIS_METHOD_DLPI"
     else
-      AC_MSG_RESULT(DLPI)
+      AC_MSG_RESULT(BPF)
+      ISIS_METHOD_MACRO="ISIS_METHOD_BPF"
     fi
-    ISIS_METHOD_MACRO="ISIS_METHOD_DLPI"
-  else
-    AC_MSG_RESULT(BPF)
-    ISIS_METHOD_MACRO="ISIS_METHOD_BPF"
-  fi
-fi
+    ;;
+esac
 AC_DEFINE_UNQUOTED(ISIS_METHOD, $ISIS_METHOD_MACRO, [ selected method for isis, == one of the constants ])
 
 dnl ------------------------------------
@@ -1128,59 +1104,6 @@ main()
 }]])],[AC_MSG_RESULT(yes - using workaround) AC_DEFINE(HAVE_BROKEN_CMSG_FIRSTHDR,,Broken CMSG_FIRSTHDR)],
 [AC_MSG_RESULT(no)],[AC_MSG_RESULT(no)])
 
-dnl ------------------------------
-dnl check kernel route read method
-dnl ------------------------------
-AC_CACHE_CHECK([route read method], [frr_cv_rtread_method],
-[if test "x$netlink" = xyes; then
-  frr_cv_rtread_method="netlink"
-else
-for frr_cv_rtread_method in /dev/ip /dev/null;
-do
-  test x`ls $frr_cv_rtread_method 2>/dev/null` = x"$frr_cv_rtread_method" && break
-done
-case $frr_cv_rtread_method in
-  "/dev/ip")
-                     case "$host" in
-                       *-freebsd*)    frr_cv_rtread_method="sysctl";;
-                       *)             frr_cv_rtread_method="getmsg";;
-                     esac;;
-       *)
-                     frr_cv_rtread_method="sysctl";;
-esac
-fi])
-RTREAD_METHOD=rtread_${frr_cv_rtread_method}.o
-AC_SUBST(RTREAD_METHOD)
-
-dnl -----------------------------
-dnl check interface lookup method
-dnl -----------------------------
-IOCTL_METHOD=ioctl.o
-AC_MSG_CHECKING(interface looking up method)
-if test "$netlink" = yes; then
-  AC_MSG_RESULT(netlink)
-  IF_METHOD=if_netlink.o
-elif test "$opsys" = "sol2-6";then
-  AC_MSG_RESULT(Solaris GIF)
-  IF_METHOD=if_ioctl.o
-elif test "$opsys" = "sol8";then
-  AC_MSG_RESULT(Solaris GLIF)
-  IF_METHOD=if_ioctl_solaris.o
-  IOCTL_METHOD=ioctl_solaris.o
-elif test "$opsys" = "openbsd";then
-  AC_MSG_RESULT(openbsd)
-  IF_METHOD=if_ioctl.o
-elif grep NET_RT_IFLIST /usr/include/sys/socket.h >/dev/null 2>&1; then
-  AC_MSG_RESULT(sysctl)
-    IF_METHOD=if_sysctl.o
-    AC_DEFINE(HAVE_NET_RT_IFLIST,,NET_RT_IFLIST)
-else
-    AC_MSG_RESULT(ioctl)
-    IF_METHOD=if_ioctl.o
-fi
-AC_SUBST(IF_METHOD)
-AC_SUBST(IOCTL_METHOD)
-
 dnl ---------------------------------------------------------------
 dnl figure out how to specify an interface in multicast sockets API
 dnl ---------------------------------------------------------------
@@ -1276,71 +1199,11 @@ if test $ac_cv_have_decl_TCP_MD5SIG = no; then
        AC_CHECK_DECLS([TCP_MD5SIG], [], [], MD5_INCLUDES)])
 fi
 
-dnl -----------------------------
-dnl check ipforward detect method
-dnl -----------------------------
-AC_CACHE_CHECK([ipforward method], [frr_cv_ipforward_method],
-[if test x$cross_compiling = xyes; then
-  if test x"$opsys" = x"gnu-linux"; then
-    frr_cv_ipforward_method=/proc/net/snmp
-  else
-    frr_cv_ipforward_method=/dev/ip
-  fi
-else
-  for frr_cv_ipforward_method in /proc/net/snmp /dev/ip /dev/null;
-  do
-    test x`ls $frr_cv_ipforward_method 2>/dev/null` = x"$frr_cv_ipforward_method" && break
-  done
-fi
-case $frr_cv_ipforward_method in
-  "/proc/net/snmp")  frr_cv_ipforward_method="proc";;
-  "/dev/ip")         
-                     case "$host" in
-                       *-freebsd*)    frr_cv_ipforward_method="sysctl";;
-                       *)             frr_cv_ipforward_method="solaris";;
-                     esac;;
-  *)                 frr_cv_ipforward_method="sysctl";;
-esac])
-IPFORWARD=ipforward_${frr_cv_ipforward_method}.o
-AC_SUBST(IPFORWARD)
-
 dnl ----------------------------------------------------------------------------
 dnl figure out if domainname is available in the utsname struct (GNU extension).
 dnl ----------------------------------------------------------------------------
 AC_CHECK_MEMBERS([struct utsname.domainname], [], [], [#include <sys/utsname.h>])
 
-dnl ----------
-dnl IPv6 check
-dnl ----------
-AC_MSG_CHECKING(whether does this OS have IPv6 stack)
-dnl ---------
-dnl KAME IPv6
-dnl ---------
-  if grep WIDE /usr/include/netinet6/in6.h >/dev/null 2>&1; then
-    AC_DEFINE(KAME,1,KAME IPv6)
-    AC_MSG_RESULT(KAME)
-dnl ------------------------------------
-dnl Solaris 9, 10 and potentially higher
-dnl ------------------------------------
-  elif test x"$opsys" = x"sol8"; then
-    AC_DEFINE(SOLARIS_IPV6, 1, Solaris IPv6)
-    AC_MSG_RESULT(Solaris IPv6)
-dnl ----------
-dnl Linux IPv6
-dnl ----------
-  elif test x"$opsys" = x"gnu-linux"; then
-    AC_DEFINE(LINUX_IPV6,1,Linux IPv6 stack)
-    dnl Linux has a compilation problem with mixing
-    dnl netinet/in.h and linux/in6.h they are not
-    dnl compatible.  There has been discussion on
-    dnl how to fix it but no real progress on implementation
-    dnl when they fix it, remove this
-    AC_DEFINE(IPV6_MINHOPCOUNT, 73, Linux ipv6 Min Hop Count)
-    AC_MSG_RESULT(Linux IPv6)
-  else
-    AC_MSG_ERROR([Failed to detect IPv6 stack])
-  fi
-
 dnl ------------------
 dnl IPv6 header checks
 dnl ------------------
@@ -1375,12 +1238,7 @@ fi
 dnl --------------------
 dnl Daemon disable check
 dnl --------------------
-if test "${enable_zebra}" = "no";then
-  ZEBRA=""
-else
-  ZEBRA="zebra"
-fi
-AM_CONDITIONAL(ZEBRA, test "x$ZEBRA" = "xzebra")
+AM_CONDITIONAL(ZEBRA, test "${enable_zebra}" != "no")
 
 if test "${enable_bgpd}" = "no";then
   BGPD=""
@@ -1412,15 +1270,18 @@ fi
 AM_CONDITIONAL(LDPD, test "x$LDPD" = "xldpd")
 
 NHRPD=""
-if test "$opsys" = "gnu-linux"; then
-  if test "${enable_nhrpd}" != "no"; then
-    NHRPD="nhrpd"
-  fi
-else
-  if test "${enable_nhrpd}" = "yes"; then
-    AC_MSG_ERROR([nhrpd requires kernel APIs that are only present on Linux.])
-  fi
-fi
+case "$host_os" in
+  linux*)
+    if test "${enable_nhrpd}" != "no"; then
+      NHRPD="nhrpd"
+    fi
+    ;;
+  *)
+    if test "${enable_nhrpd}" = "yes"; then
+      AC_MSG_ERROR([nhrpd requires kernel APIs that are only present on Linux.])
+    fi
+    ;;
+esac
 AM_CONDITIONAL(NHRPD, test "x$NHRPD" = "xnhrpd")
 
 if test "${enable_eigrpd}" = "no";then
@@ -1506,7 +1367,6 @@ fi
 AM_CONDITIONAL([ENABLE_BGP_VNC], [test x${enable_bgp_vnc} != xno])
 
 AC_SUBST(DOC)
-AC_SUBST(ZEBRA)
 AC_SUBST(RFPTEST)
 AC_SUBST(LIBRFP)
 AC_SUBST(RFPINC)
@@ -1527,7 +1387,8 @@ AC_SUBST(VTYSH)
 AC_SUBST(CURSES)
 AC_SUBST(OSPFCLIENT)
 AC_SUBST(OSPFAPI)
-AC_CHECK_LIB(crypt, crypt)
+AC_CHECK_LIB(crypt, crypt, [],
+                   [AC_CHECK_LIB(crypto, DES_crypt)])
 AC_CHECK_LIB(resolv, res_init)
 
 dnl ---------------------------
@@ -1969,22 +1830,17 @@ AC_CACHE_VAL(ac_cv_htonl_works,
 )
 AC_MSG_RESULT($ac_cv_htonl_works)
 
-AC_CONFIG_FILES([Makefile lib/Makefile qpb/Makefile zebra/Makefile ripd/Makefile
+AC_CONFIG_FILES([Makefile ripd/Makefile
          ripngd/Makefile bgpd/Makefile ospfd/Makefile watchfrr/Makefile
          ospf6d/Makefile ldpd/Makefile isisd/Makefile vtysh/Makefile
-         doc/Makefile ospfclient/Makefile tests/Makefile m4/Makefile
+         doc/Makefile ospfclient/Makefile tests/Makefile
          bgpd/rfp-example/rfptest/Makefile bgpd/rfp-example/librfp/Makefile
          babeld/Makefile
          pimd/Makefile
          eigrpd/Makefile
          nhrpd/Makefile
-         redhat/Makefile
          tools/Makefile
-         pkgsrc/Makefile
-         python/Makefile
-         fpm/Makefile
          redhat/frr.spec
-         snapcraft/Makefile
          snapcraft/snapcraft.yaml
          lib/version.h
          tests/lib/cli/test_cli.refout
index 2dfb5f8c0a3c9065b42e3a745a498ab20db2f18d..341f692869dceac5f59f094823b5a4ae9e89b853 100644 (file)
@@ -179,8 +179,8 @@ The default is 4@dmn{s}.
 @node Babel redistribution, Show Babel information, Babel configuration, Babel
 @section Babel redistribution
 
-@deffn {Babel command} {redistribute @var{kind}}
-@deffnx {Babel command} {no redistribute @var{kind}}
+@deffn {Babel command} {redistribute @var{<ipv4|ipv6>} @var{kind}}
+@deffnx {Babel command} {no redistribute @var{<ipv4|ipv6>} @var{kind}}
 Specify which kind of routes should be redistributed into Babel.
 @end deffn
 
index ba24abe5b3006cd3e93f30233fec62334e2147d7..15a8a71cf3b3db744d1a7873c2a8bfe8af39acf0 100644 (file)
@@ -395,11 +395,11 @@ DEFUN (debug_eigrp_transmit,
                flag = EIGRP_DEBUG_SEND;
        else if (argv_find(argv, argc, "recv", &idx))
                flag = EIGRP_DEBUG_RECV;
-       else if (argv_find(argv, argc, "all", &idx) == 0)
+       else if (argv_find(argv, argc, "all", &idx))
                flag = EIGRP_DEBUG_SEND_RECV;
 
        /* detail option */
-       if (argv_find(argv, argc, "detail", &idx) == 0)
+       if (argv_find(argv, argc, "detail", &idx))
                flag = EIGRP_DEBUG_PACKET_DETAIL;
 
        if (vty->node == CONFIG_NODE)
@@ -426,15 +426,15 @@ DEFUN (no_debug_eigrp_transmit,
        int idx = 3;
 
        /* send or recv. */
-       if (argv_find(argv, argc, "send", &idx) == 0)
+       if (argv_find(argv, argc, "send", &idx))
                flag = EIGRP_DEBUG_SEND;
-       else if (argv_find(argv, argc, "recv", &idx) == 0)
+       else if (argv_find(argv, argc, "recv", &idx))
                flag = EIGRP_DEBUG_RECV;
-       else if (argv_find(argv, argc, "all", &idx) == 0)
+       else if (argv_find(argv, argc, "all", &idx))
                flag = EIGRP_DEBUG_SEND_RECV;
 
        /* detail option */
-       if (argv_find(argv, argc, "detail", &idx) == 0)
+       if (argv_find(argv, argc, "detail", &idx))
                flag = EIGRP_DEBUG_PACKET_DETAIL;
 
        if (vty->node == CONFIG_NODE)
@@ -474,27 +474,27 @@ DEFUN (debug_eigrp_packets,
        int idx = 0;
 
        /* Check packet type. */
-       if (argv_find(argv, argc, "hello", &idx) == 0)
+       if (argv_find(argv, argc, "hello", &idx))
                type = EIGRP_DEBUG_HELLO;
-       if (argv_find(argv, argc, "update", &idx) == 0)
+       if (argv_find(argv, argc, "update", &idx))
                type = EIGRP_DEBUG_UPDATE;
-       if (argv_find(argv, argc, "query", &idx) == 0)
+       if (argv_find(argv, argc, "query", &idx))
                type = EIGRP_DEBUG_QUERY;
-       if (argv_find(argv, argc, "ack", &idx) == 0)
+       if (argv_find(argv, argc, "ack", &idx))
                type = EIGRP_DEBUG_ACK;
-       if (argv_find(argv, argc, "probe", &idx) == 0)
+       if (argv_find(argv, argc, "probe", &idx))
                type = EIGRP_DEBUG_PROBE;
-       if (argv_find(argv, argc, "stub", &idx) == 0)
+       if (argv_find(argv, argc, "stub", &idx))
                type = EIGRP_DEBUG_STUB;
-       if (argv_find(argv, argc, "reply", &idx) == 0)
+       if (argv_find(argv, argc, "reply", &idx))
                type = EIGRP_DEBUG_REPLY;
-       if (argv_find(argv, argc, "request", &idx) == 0)
+       if (argv_find(argv, argc, "request", &idx))
                type = EIGRP_DEBUG_REQUEST;
-       if (argv_find(argv, argc, "siaquery", &idx) == 0)
+       if (argv_find(argv, argc, "siaquery", &idx))
                type = EIGRP_DEBUG_SIAQUERY;
-       if (argv_find(argv, argc, "siareply", &idx) == 0)
+       if (argv_find(argv, argc, "siareply", &idx))
                type = EIGRP_DEBUG_SIAREPLY;
-       if (argv_find(argv, argc, "all", &idx) == 0)
+       if (argv_find(argv, argc, "all", &idx))
                type = EIGRP_DEBUG_PACKETS_ALL;
 
 
@@ -502,13 +502,13 @@ DEFUN (debug_eigrp_packets,
        flag = EIGRP_DEBUG_SEND_RECV;
 
        /* send or recv. */
-       if (argv_find(argv, argc, "s", &idx) == 0)
+       if (argv_find(argv, argc, "s", &idx))
                flag = EIGRP_DEBUG_SEND;
-       else if (argv_find(argv, argc, "r", &idx) == 0)
+       else if (argv_find(argv, argc, "r", &idx))
                flag = EIGRP_DEBUG_RECV;
 
        /* detail. */
-       if (argv_find(argv, argc, "detail", &idx) == 0)
+       if (argv_find(argv, argc, "detail", &idx))
                flag |= EIGRP_DEBUG_PACKET_DETAIL;
 
        for (i = 0; i < 11; i++)
@@ -552,38 +552,38 @@ DEFUN (no_debug_eigrp_packets,
        int idx = 0;
 
        /* Check packet type. */
-       if (argv_find(argv, argc, "hello", &idx) == 0)
+       if (argv_find(argv, argc, "hello", &idx))
                type = EIGRP_DEBUG_HELLO;
-       if (argv_find(argv, argc, "update", &idx) == 0)
+       if (argv_find(argv, argc, "update", &idx))
                type = EIGRP_DEBUG_UPDATE;
-       if (argv_find(argv, argc, "query", &idx) == 0)
+       if (argv_find(argv, argc, "query", &idx))
                type = EIGRP_DEBUG_QUERY;
-       if (argv_find(argv, argc, "ack", &idx) == 0)
+       if (argv_find(argv, argc, "ack", &idx))
                type = EIGRP_DEBUG_ACK;
-       if (argv_find(argv, argc, "probe", &idx) == 0)
+       if (argv_find(argv, argc, "probe", &idx))
                type = EIGRP_DEBUG_PROBE;
-       if (argv_find(argv, argc, "stub", &idx) == 0)
+       if (argv_find(argv, argc, "stub", &idx))
                type = EIGRP_DEBUG_STUB;
-       if (argv_find(argv, argc, "reply", &idx) == 0)
+       if (argv_find(argv, argc, "reply", &idx))
                type = EIGRP_DEBUG_REPLY;
-       if (argv_find(argv, argc, "request", &idx) == 0)
+       if (argv_find(argv, argc, "request", &idx))
                type = EIGRP_DEBUG_REQUEST;
-       if (argv_find(argv, argc, "siaquery", &idx) == 0)
+       if (argv_find(argv, argc, "siaquery", &idx))
                type = EIGRP_DEBUG_SIAQUERY;
-       if (argv_find(argv, argc, "siareply", &idx) == 0)
+       if (argv_find(argv, argc, "siareply", &idx))
                type = EIGRP_DEBUG_SIAREPLY;
 
        /* Default, both send and recv. */
        flag = EIGRP_DEBUG_SEND_RECV;
 
        /* send or recv. */
-       if (argv_find(argv, argc, "send", &idx) == 0)
+       if (argv_find(argv, argc, "send", &idx))
                flag = EIGRP_DEBUG_SEND;
-       else if (argv_find(argv, argc, "reply", &idx) == 0)
+       else if (argv_find(argv, argc, "reply", &idx))
                flag = EIGRP_DEBUG_RECV;
 
        /* detail. */
-       if (argv_find(argv, argc, "detail", &idx) == 0)
+       if (argv_find(argv, argc, "detail", &idx))
                flag |= EIGRP_DEBUG_PACKET_DETAIL;
 
        for (i = 0; i < 11; i++)
index f20ec0ad12e581ed726900cdcd060b176d203653..3befd8a1189d16c22a1e99efff5a62b522e6c84d 100644 (file)
@@ -161,6 +161,7 @@ int eigrp_check_md5_digest(struct stream *s,
 {
        MD5_CTX ctx;
        unsigned char digest[EIGRP_AUTH_TYPE_MD5_LEN];
+       unsigned char orig[EIGRP_AUTH_TYPE_MD5_LEN];
        struct key *key = NULL;
        struct keychain *keychain;
        u_char *ibuf;
@@ -181,7 +182,9 @@ int eigrp_check_md5_digest(struct stream *s,
 
        auth_TLV = (struct TLV_MD5_Authentication_Type *)(s->data
                                                          + EIGRP_HEADER_LEN);
-       memset(auth_TLV->digest, 0, sizeof(auth_TLV->digest));
+       memcpy(orig, auth_TLV->digest, EIGRP_AUTH_TYPE_MD5_LEN);
+       memset(digest, 0, EIGRP_AUTH_TYPE_MD5_LEN);
+       memset(auth_TLV->digest, 0, EIGRP_AUTH_TYPE_MD5_LEN);
 
        ibuf = s->data;
        backup_end = s->endp;
@@ -219,16 +222,15 @@ int eigrp_check_md5_digest(struct stream *s,
        MD5Final(digest, &ctx);
 
        /* compare the two */
-       if (memcmp(authTLV->digest, digest, EIGRP_AUTH_TYPE_MD5_LEN) == 0) {
-               zlog_debug("VSETKO OK");
-       } else {
+       if (memcmp(orig, digest, EIGRP_AUTH_TYPE_MD5_LEN) != 0) {
                zlog_warn("interface %s: eigrp_check_md5 checksum mismatch",
                          IF_NAME(nbr->ei));
                return 0;
        }
 
        /* save neighbor's crypt_seqnum */
-       nbr->crypt_seqnum = authTLV->key_sequence;
+       if (nbr)
+               nbr->crypt_seqnum = authTLV->key_sequence;
 
        return 1;
 }
@@ -884,6 +886,7 @@ void eigrp_packet_header_init(int type, struct eigrp_interface *ei,
 {
        struct eigrp_header *eigrph;
 
+       stream_reset(s);
        eigrph = (struct eigrp_header *)STREAM_DATA(s);
 
        eigrph->version = (u_char)EIGRP_HEADER_VERSION;
index 3c2ce6ce428e37a4a7ff7ab6c19a509569aba6b0..e0169c514b416a58bd09050188d4b444285943df 100644 (file)
@@ -504,10 +504,36 @@ void eigrp_update_send_init(struct eigrp_neighbor *nbr)
        }
 }
 
+static void eigrp_update_place_on_nbr_queue(struct eigrp_neighbor *nbr,
+                                           struct eigrp_packet *ep,
+                                           u_int32_t seq_no,
+                                           int length)
+{
+       if((IF_DEF_PARAMS (nbr->ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) &&
+          (IF_DEF_PARAMS (nbr->ei->ifp)->auth_keychain != NULL)) {
+               eigrp_make_md5_digest(nbr->ei,ep->s, EIGRP_AUTH_UPDATE_FLAG);
+       }
+
+       /* EIGRP Checksum */
+       eigrp_packet_checksum(nbr->ei, ep->s, length);
+
+       ep->length = length;
+       ep->dst.s_addr = nbr->src.s_addr;
+
+       /*This ack number we await from neighbor*/
+       ep->sequence_number = seq_no;
+
+       if (IS_DEBUG_EIGRP_PACKET(0, RECV))
+               zlog_debug("Enqueuing Update Init Len [%u] Seq [%u] Dest [%s]",
+                          ep->length, ep->sequence_number, inet_ntoa(ep->dst));
+
+       /*Put packet to retransmission queue*/
+       eigrp_fifo_push_head(nbr->retrans_queue, ep);
+}
+
 void eigrp_update_send_EOT(struct eigrp_neighbor *nbr)
 {
        struct eigrp_packet *ep;
-       //  struct eigrp_packet *ep_multicast;
        u_int16_t length = EIGRP_HEADER_LEN;
        struct eigrp_neighbor_entry *te;
        struct eigrp_prefix_entry *pe;
@@ -518,38 +544,53 @@ void eigrp_update_send_EOT(struct eigrp_neighbor *nbr)
        struct prefix_list *plist_i;
        struct eigrp *e;
        struct prefix_ipv4 *dest_addr;
+       u_int32_t seq_no = nbr->ei->eigrp->sequence_number;
 
        ep = eigrp_packet_new(nbr->ei->ifp->mtu);
 
        /* Prepare EIGRP EOT UPDATE header */
-       eigrp_packet_header_init(
-               EIGRP_OPC_UPDATE, nbr->ei, ep->s, EIGRP_EOT_FLAG,
-               nbr->ei->eigrp->sequence_number, nbr->recv_sequence_number);
+       eigrp_packet_header_init(EIGRP_OPC_UPDATE, nbr->ei, ep->s, EIGRP_EOT_FLAG,
+                                seq_no,
+                                nbr->recv_sequence_number);
 
        // encode Authentication TLV, if needed
-       if ((IF_DEF_PARAMS(nbr->ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5)
-           && (IF_DEF_PARAMS(nbr->ei->ifp)->auth_keychain != NULL)) {
-               length += eigrp_add_authTLV_MD5_to_stream(ep->s, nbr->ei);
+       if((IF_DEF_PARAMS (nbr->ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) &&
+          (IF_DEF_PARAMS (nbr->ei->ifp)->auth_keychain != NULL)) {
+               length += eigrp_add_authTLV_MD5_to_stream(ep->s,nbr->ei);
        }
 
-       for (ALL_LIST_ELEMENTS(nbr->ei->eigrp->topology_table, node, nnode,
-                              pe)) {
+       for (ALL_LIST_ELEMENTS(nbr->ei->eigrp->topology_table, node, nnode, pe)) {
                for (ALL_LIST_ELEMENTS(pe->entries, node2, nnode2, te)) {
                        if ((te->ei == nbr->ei)
                            && (te->prefix->nt == EIGRP_TOPOLOGY_TYPE_REMOTE))
                                continue;
 
+                       if ((length + 0x001D) > (u_int16_t)nbr->ei->ifp->mtu) {
+                               eigrp_update_place_on_nbr_queue (nbr, ep, seq_no, length);
+                               eigrp_send_packet_reliably(nbr);
+                               seq_no++;
+
+                               length = EIGRP_HEADER_LEN;
+                               ep = eigrp_packet_new(nbr->ei->ifp->mtu);
+                               eigrp_packet_header_init(EIGRP_OPC_UPDATE, nbr->ei, ep->s, EIGRP_EOT_FLAG,
+                                                        seq_no, nbr->recv_sequence_number);
+
+                               if((IF_DEF_PARAMS (nbr->ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) &&
+                                  (IF_DEF_PARAMS (nbr->ei->ifp)->auth_keychain != NULL))
+                               {
+                                       length += eigrp_add_authTLV_MD5_to_stream(ep->s,nbr->ei);
+                               }
+                       }
                        /* Get destination address from prefix */
                        dest_addr = pe->destination_ipv4;
 
                        /*
                         * Filtering
                         */
-                       // TODO: Work in progress
+                       //TODO: Work in progress
                        /* get list from eigrp process */
                        e = eigrp_lookup();
-                       /* Get access-lists and prefix-lists from process and
-                        * interface */
+                       /* Get access-lists and prefix-lists from process and interface */
                        alist = e->list[EIGRP_FILTER_OUT];
                        plist = e->prefix[EIGRP_FILTER_OUT];
                        alist_i = nbr->ei->list[EIGRP_FILTER_OUT];
@@ -557,65 +598,24 @@ void eigrp_update_send_EOT(struct eigrp_neighbor *nbr)
 
                        /* Check if any list fits */
                        if ((alist
-                            && access_list_apply(alist,
-                                                 (struct prefix *)dest_addr)
-                                       == FILTER_DENY)
-                           || (plist
-                               && prefix_list_apply(plist,
-                                                    (struct prefix *)dest_addr)
-                                          == PREFIX_DENY)
-                           || (alist_i
-                               && access_list_apply(alist_i,
-                                                    (struct prefix *)dest_addr)
-                                          == FILTER_DENY)
-                           || (plist_i
-                               && prefix_list_apply(plist_i,
-                                                    (struct prefix *)dest_addr)
-                                          == PREFIX_DENY)) {
-                               zlog_info("PROC OUT EOT: Skipping");
-                               // pe->reported_metric.delay = EIGRP_MAX_METRIC;
-                               zlog_info("PROC OUT EOT Prefix: %s",
-                                         inet_ntoa(dest_addr->prefix));
+                            && access_list_apply (alist,
+                                                  (struct prefix *) dest_addr) == FILTER_DENY)||
+                           (plist && prefix_list_apply (plist,
+                                                        (struct prefix *) dest_addr) == PREFIX_DENY)||
+                           (alist_i && access_list_apply (alist_i,
+                                                          (struct prefix *) dest_addr) == FILTER_DENY)||
+                           (plist_i && prefix_list_apply (plist_i,
+                                                          (struct prefix *) dest_addr) == PREFIX_DENY)) {
+                               //pe->reported_metric.delay = EIGRP_MAX_METRIC;
                                continue;
                        } else {
-                               zlog_info(
-                                       "PROC OUT EOT: NENastavujem metriku ");
-                               length += eigrp_add_internalTLV_to_stream(ep->s,
-                                                                         pe);
+                               length += eigrp_add_internalTLV_to_stream(ep->s, pe);
                        }
-                       /*
-                        * End of filtering
-                        */
-
-                       /* NULL the pointer */
-                       dest_addr = NULL;
                }
        }
 
-       if ((IF_DEF_PARAMS(nbr->ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5)
-           && (IF_DEF_PARAMS(nbr->ei->ifp)->auth_keychain != NULL)) {
-               eigrp_make_md5_digest(nbr->ei, ep->s, EIGRP_AUTH_UPDATE_FLAG);
-       }
-
-       /* EIGRP Checksum */
-       eigrp_packet_checksum(nbr->ei, ep->s, length);
-
-       ep->length = length;
-       ep->dst.s_addr = nbr->src.s_addr;
-
-       /*This ack number we await from neighbor*/
-       ep->sequence_number = nbr->ei->eigrp->sequence_number;
-
-       if (IS_DEBUG_EIGRP_PACKET(0, RECV))
-               zlog_debug("Enqueuing Update Init Len [%u] Seq [%u] Dest [%s]",
-                          ep->length, ep->sequence_number, inet_ntoa(ep->dst));
-
-       /*Put packet to retransmission queue*/
-       eigrp_fifo_push_head(nbr->retrans_queue, ep);
-
-       if (nbr->retrans_queue->count == 1) {
-               eigrp_send_packet_reliably(nbr);
-       }
+       eigrp_update_place_on_nbr_queue (nbr, ep, seq_no, length);
+       eigrp_send_packet_reliably(nbr);
 }
 
 void eigrp_update_send(struct eigrp_interface *ei)
index b133c52a42dc08638463b1250cf309691fbfee08..17e90443e977f113cea3a5a49954767ec7248d3e 100644 (file)
@@ -1,4 +1,4 @@
-Makefile
+!Makefile
 Makefile.in
 *.o
 tags
diff --git a/fpm/Makefile b/fpm/Makefile
new file mode 100644 (file)
index 0000000..1d280d1
--- /dev/null
@@ -0,0 +1,10 @@
+all: ALWAYS
+       @$(MAKE) -s -C .. fpm/libfrrfpm_pb.la
+%: ALWAYS
+       @$(MAKE) -s -C .. fpm/$@
+
+Makefile:
+       #nothing
+ALWAYS:
+.PHONY: ALWAYS makefiles
+.SUFFIXES:
diff --git a/fpm/Makefile.am b/fpm/Makefile.am
deleted file mode 100644 (file)
index 1f46ac6..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-include ../common.am
-
-AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib $(Q_PROTOBUF_C_CLIENT_INCLUDES)
-
-PROTOBUF_INCLUDES=-I$(top_srcdir)
-PROTOBUF_PACKAGE = fpm
-
-lib_LTLIBRARIES = libfrrfpm_pb.la
-libfrrfpm_pb_la_LDFLAGS = -version-info 0:0:0
-
-if HAVE_PROTOBUF
-protobuf_srcs =
-
-protobuf_srcs_nodist =                         \
-       fpm.pb-c.c
-endif
-
-libfrrfpm_pb_la_SOURCES =                      \
-       fpm.h                                   \
-       fpm_pb.h                                \
-       fpm_pb.c                                \
-       $(protobuf_srcs)
-
-nodist_libfrrfpm_pb_la_SOURCES = $(protobuf_srcs_nodist)
-
-CLEANFILES = $(Q_CLEANFILES)
-
-BUILT_SOURCES = $(Q_PROTOBUF_SRCS)
-EXTRA_DIST = fpm.proto
index 318e80a92e8dbe420005be24f49d73b44ca4ad2a..4597c7f8ebdf78a7a7093b3412338fd1ce9319c7 100644 (file)
@@ -20,6 +20,8 @@
 // CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 //
 
+syntax = "proto2";
+
 //
 // Protobuf definitions pertaining to the Forwarding Plane Manager component.
 //
diff --git a/fpm/subdir.am b/fpm/subdir.am
new file mode 100644 (file)
index 0000000..f81a842
--- /dev/null
@@ -0,0 +1,23 @@
+if FPM
+lib_LTLIBRARIES += fpm/libfrrfpm_pb.la
+endif
+
+fpm_libfrrfpm_pb_la_LDFLAGS = -version-info 0:0:0
+fpm_libfrrfpm_pb_la_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir) -I$(top_builddir)/lib \
+       $(Q_PROTOBUF_C_CLIENT_INCLUDES)
+fpm_libfrrfpm_pb_la_SOURCES = \
+       fpm/fpm.h \
+       fpm/fpm_pb.h \
+       fpm/fpm_pb.c \
+       # end
+
+if HAVE_PROTOBUF
+nodist_fpm_libfrrfpm_pb_la_SOURCES = fpm/fpm.pb-c.c
+BUILT_SOURCES += fpm/fpm.pb-c.c
+CLEANFILES += \
+       fpm/fpm.pb-c.c \
+       fpm/fpm.pb-c.h \
+       # end
+endif
+
+EXTRA_DIST += fpm/fpm.proto
index 2973820eedae7fd335b6465758e7f87744ebaa17..dc3d3683a16afbaf646bb541b14bc6a6dae2cf0b 100644 (file)
@@ -8,24 +8,26 @@ LIBS = @LIBS@
 AM_CFLAGS = $(WERROR)
 
 noinst_LIBRARIES = libisis.a
-sbin_PROGRAMS = isisd 
+sbin_PROGRAMS = isisd
 
 libisis_a_SOURCES = \
        isis_memory.c \
        isis_adjacency.c isis_lsp.c dict.c isis_circuit.c isis_pdu.c \
-       isis_tlv.c isisd.c isis_misc.c isis_zebra.c isis_dr.c \
+       isisd.c isis_misc.c isis_zebra.c isis_dr.c \
        isis_flags.c isis_dynhn.c iso_checksum.c isis_csm.c isis_events.c \
        isis_spf.c isis_redist.c isis_route.c isis_routemap.c isis_te.c \
-       isis_vty.c isis_mt.c
+       isis_vty.c isis_mt.c \
+       isis_tlvs.c
 
 
 noinst_HEADERS = \
        isis_memory.h \
-       isisd.h isis_pdu.h isis_tlv.h isis_adjacency.h isis_constants.h \
+       isisd.h isis_pdu.h isis_adjacency.h isis_constants.h \
        isis_lsp.h dict.h isis_circuit.h isis_misc.h isis_network.h \
        isis_zebra.h isis_dr.h isis_flags.h isis_dynhn.h isis_common.h \
        iso_checksum.h isis_csm.h isis_events.h isis_spf.h isis_redist.h \
-       isis_route.h isis_routemap.h isis_te.h isis_mt.h
+       isis_route.h isis_routemap.h isis_te.h isis_mt.h \
+       isis_tlvs.h
 
 isisd_SOURCES = \
        isis_main.c $(libisis_a_SOURCES) \
index f09a8152a836a6109fd0d10d74d47c4c272eae60..2ea86d1b68bdb80655f4b450bd086cb0c831e74d 100644 (file)
@@ -174,6 +174,7 @@ static int verify_bintree(dict_t *dict)
  * subtree is not red-black.
  */
 
+#ifdef EXTREME_DICT_DEBUG
 static unsigned int verify_redblack(dnode_t *nil, dnode_t *root)
 {
        unsigned height_left, height_right;
@@ -198,6 +199,7 @@ static unsigned int verify_redblack(dnode_t *nil, dnode_t *root)
        }
        return 1;
 }
+#endif
 
 /*
  * Compute the actual count of nodes by traversing the tree and
@@ -205,6 +207,7 @@ static unsigned int verify_redblack(dnode_t *nil, dnode_t *root)
  * detect a mismatch.
  */
 
+#ifdef EXTREME_DICT_DEBUG
 static dictcount_t verify_node_count(dnode_t *nil, dnode_t *root)
 {
        if (root == nil)
@@ -213,6 +216,7 @@ static dictcount_t verify_node_count(dnode_t *nil, dnode_t *root)
                return 1 + verify_node_count(nil, root->left)
                       + verify_node_count(nil, root->right);
 }
+#endif
 
 /*
  * Verify that the tree contains the given node. This is done by
@@ -369,6 +373,7 @@ static void dict_clear(dict_t *dict)
 
 int dict_verify(dict_t *dict)
 {
+#ifdef EXTREME_DICT_DEBUG
        dnode_t *nil = dict_nil(dict), *root = dict_root(dict);
 
        /* check that the sentinel node and root node are black */
@@ -389,6 +394,7 @@ int dict_verify(dict_t *dict)
                return 0;
        if (verify_node_count(nil, root) != dict_count(dict))
                return 0;
+#endif
        return 1;
 }
 
index d8cb32375bec3506581ba8901b27b7d37c2a33c9..0afa65d726914aba336a0074f0d02729860d6191 100644 (file)
@@ -43,7 +43,6 @@
 #include "isisd/isis_dr.h"
 #include "isisd/isis_dynhn.h"
 #include "isisd/isis_pdu.h"
-#include "isisd/isis_tlv.h"
 #include "isisd/isis_lsp.h"
 #include "isisd/isis_spf.h"
 #include "isisd/isis_events.h"
@@ -69,11 +68,6 @@ struct isis_adjacency *isis_new_adj(const u_char *id, const u_char *snpa,
 
        adj = adj_alloc(id); /* P2P kludge */
 
-       if (adj == NULL) {
-               zlog_err("Out of memory!");
-               return NULL;
-       }
-
        if (snpa) {
                memcpy(adj->snpa, snpa, ETH_ALEN);
        } else {
@@ -137,12 +131,12 @@ void isis_delete_adj(void *arg)
        /* remove from SPF trees */
        spftree_area_adj_del(adj->circuit->area, adj);
 
-       if (adj->area_addrs)
-               list_delete(adj->area_addrs);
-       if (adj->ipv4_addrs)
-               list_delete(adj->ipv4_addrs);
-       if (adj->ipv6_addrs)
-               list_delete(adj->ipv6_addrs);
+       if (adj->area_addresses)
+               XFREE(MTYPE_ISIS_ADJACENCY_INFO, adj->area_addresses);
+       if (adj->ipv4_addresses)
+               XFREE(MTYPE_ISIS_ADJACENCY_INFO, adj->ipv4_addresses);
+       if (adj->ipv6_addresses)
+               XFREE(MTYPE_ISIS_ADJACENCY_INFO, adj->ipv6_addresses);
 
        adj_mt_finish(adj);
 
@@ -192,7 +186,7 @@ void isis_adj_state_change(struct isis_adjacency *adj,
 
                dyn = dynhn_find_by_id(adj->sysid);
                if (dyn)
-                       adj_name = (const char *)dyn->name.name;
+                       adj_name = dyn->hostname;
                else
                        adj_name = sysid_print(adj->sysid);
 
@@ -301,33 +295,29 @@ void isis_adj_state_change(struct isis_adjacency *adj,
 void isis_adj_print(struct isis_adjacency *adj)
 {
        struct isis_dynhn *dyn;
-       struct listnode *node;
-       struct in_addr *ipv4_addr;
-       struct in6_addr *ipv6_addr;
-       u_char ip6[INET6_ADDRSTRLEN];
 
        if (!adj)
                return;
        dyn = dynhn_find_by_id(adj->sysid);
        if (dyn)
-               zlog_debug("%s", dyn->name.name);
+               zlog_debug("%s", dyn->hostname);
 
        zlog_debug("SystemId %20s SNPA %s, level %d\nHolding Time %d",
                   sysid_print(adj->sysid), snpa_print(adj->snpa), adj->level,
                   adj->hold_time);
-       if (adj->ipv4_addrs && listcount(adj->ipv4_addrs) > 0) {
+       if (adj->ipv4_address_count) {
                zlog_debug("IPv4 Address(es):");
-
-               for (ALL_LIST_ELEMENTS_RO(adj->ipv4_addrs, node, ipv4_addr))
-                       zlog_debug("%s", inet_ntoa(*ipv4_addr));
+               for (unsigned int i = 0; i < adj->ipv4_address_count; i++)
+                       zlog_debug("%s", inet_ntoa(adj->ipv4_addresses[i]));
        }
 
-       if (adj->ipv6_addrs && listcount(adj->ipv6_addrs) > 0) {
+       if (adj->ipv6_address_count) {
                zlog_debug("IPv6 Address(es):");
-               for (ALL_LIST_ELEMENTS_RO(adj->ipv6_addrs, node, ipv6_addr)) {
-                       inet_ntop(AF_INET6, ipv6_addr, (char *)ip6,
-                                 INET6_ADDRSTRLEN);
-                       zlog_debug("%s", ip6);
+               for (unsigned int i = 0; i < adj->ipv6_address_count; i++) {
+                       char buf[INET6_ADDRSTRLEN];
+                       inet_ntop(AF_INET6, &adj->ipv6_addresses[i], buf,
+                                 sizeof(buf));
+                       zlog_debug("%s", buf);
                }
        }
        zlog_debug("Speaks: %s", nlpid2string(&adj->nlpids));
@@ -358,17 +348,13 @@ int isis_adj_expire(struct thread *thread)
 void isis_adj_print_vty(struct isis_adjacency *adj, struct vty *vty,
                        char detail)
 {
-       struct in6_addr *ipv6_addr;
-       u_char ip6[INET6_ADDRSTRLEN];
-       struct in_addr *ip_addr;
        time_t now;
        struct isis_dynhn *dyn;
        int level;
-       struct listnode *node;
 
        dyn = dynhn_find_by_id(adj->sysid);
        if (dyn)
-               vty_out(vty, "  %-20s", dyn->name.name);
+               vty_out(vty, "  %-20s", dyn->hostname);
        else
                vty_out(vty, "  %-20s", sysid_print(adj->sysid));
 
@@ -429,8 +415,7 @@ void isis_adj_print_vty(struct isis_adjacency *adj, struct vty *vty,
                    && (adj->circuit->circ_type == CIRCUIT_T_BROADCAST)) {
                        dyn = dynhn_find_by_id(adj->lanid);
                        if (dyn)
-                               vty_out(vty, ", LAN id: %s.%02x",
-                                       dyn->name.name,
+                               vty_out(vty, ", LAN id: %s.%02x", dyn->hostname,
                                        adj->lanid[ISIS_SYS_ID_LEN]);
                        else
                                vty_out(vty, ", LAN id: %s.%02x",
@@ -452,28 +437,32 @@ void isis_adj_print_vty(struct isis_adjacency *adj, struct vty *vty,
                }
                vty_out(vty, "\n");
 
-               if (adj->area_addrs && listcount(adj->area_addrs) > 0) {
-                       struct area_addr *area_addr;
+               if (adj->area_address_count) {
                        vty_out(vty, "    Area Address(es):\n");
-                       for (ALL_LIST_ELEMENTS_RO(adj->area_addrs, node,
-                                                 area_addr))
+                       for (unsigned int i = 0; i < adj->area_address_count;
+                            i++) {
                                vty_out(vty, "      %s\n",
-                                       isonet_print(area_addr->area_addr,
-                                                    area_addr->addr_len));
+                                         isonet_print(adj->area_addresses[i]
+                                                              .area_addr,
+                                                      adj->area_addresses[i]
+                                                              .addr_len));
+                       }
                }
-               if (adj->ipv4_addrs && listcount(adj->ipv4_addrs) > 0) {
+               if (adj->ipv4_address_count) {
                        vty_out(vty, "    IPv4 Address(es):\n");
-                       for (ALL_LIST_ELEMENTS_RO(adj->ipv4_addrs, node,
-                                                 ip_addr))
-                               vty_out(vty, "      %s\n", inet_ntoa(*ip_addr));
+                       for (unsigned int i = 0; i < adj->ipv4_address_count;
+                            i++)
+                               vty_out(vty, "      %s\n",
+                                         inet_ntoa(adj->ipv4_addresses[i]));
                }
-               if (adj->ipv6_addrs && listcount(adj->ipv6_addrs) > 0) {
+               if (adj->ipv6_address_count) {
                        vty_out(vty, "    IPv6 Address(es):\n");
-                       for (ALL_LIST_ELEMENTS_RO(adj->ipv6_addrs, node,
-                                                 ipv6_addr)) {
-                               inet_ntop(AF_INET6, ipv6_addr, (char *)ip6,
-                                         INET6_ADDRSTRLEN);
-                               vty_out(vty, "      %s\n", ip6);
+                       for (unsigned int i = 0; i < adj->ipv6_address_count;
+                            i++) {
+                               char buf[INET6_ADDRSTRLEN];
+                               inet_ntop(AF_INET6, &adj->ipv6_addresses[i],
+                                         buf, sizeof(buf));
+                               vty_out(vty, "      %s\n", buf);
                        }
                }
                vty_out(vty, "\n");
index 9f4af1b45dc24d84ddff096267017acb3d810e3c..98bb9838fa5170fb9f4fef3c150b7668ca2fecb7 100644 (file)
@@ -73,13 +73,16 @@ struct isis_adjacency {
        int dischanges[ISIS_LEVELS];       /* how many DIS changes ? */
        /* an array of N levels for M records */
        struct isis_dis_record dis_record[DIS_RECORDS * ISIS_LEVELS];
-       enum isis_adj_state adj_state; /* adjacencyState */
-       enum isis_adj_usage adj_usage; /* adjacencyUsage */
-       struct list *area_addrs;       /* areaAdressesOfNeighbour */
-       struct nlpids nlpids;     /* protocols spoken ... */
-       struct list *ipv4_addrs;
+       enum isis_adj_state adj_state;    /* adjacencyState */
+       enum isis_adj_usage adj_usage;    /* adjacencyUsage */
+       struct area_addr *area_addresses; /* areaAdressesOfNeighbour */
+       unsigned int area_address_count;
+       struct nlpids nlpids; /* protocols spoken ... */
+       struct in_addr *ipv4_addresses;
+       unsigned int ipv4_address_count;
        struct in_addr router_address;
-       struct list *ipv6_addrs;
+       struct in6_addr *ipv6_addresses;
+       unsigned int ipv6_address_count;
        struct in6_addr router_address6;
        u_char prio[ISIS_LEVELS];       /* priorityOfNeighbour for DIS */
        int circuit_t;                  /* from hello PDU hdr */
index 69c2f941f072544573e89d74379ad9379f3670a3..98f612f827874b4b74259250c2b1b5d710bbd0e6 100644 (file)
@@ -250,8 +250,8 @@ int isis_recv_pdu_bcast(struct isis_circuit *circuit, u_char *ssnpa)
                     bpf_hdr->bh_caplen - LLC_LEN - ETHER_HDR_LEN);
        stream_set_getp(circuit->rcv_stream, 0);
 
-       memcpy(ssnpa, readbuff + bpf_hdr->bh_hdrlen + ETHER_ADDR_LEN,
-              ETHER_ADDR_LEN);
+       memcpy(ssnpa, readbuff + bpf_hdr->bh_hdrlen + ETH_ALEN,
+              ETH_ALEN);
 
        if (ioctl(circuit->fd, BIOCFLUSH, &one) < 0)
                zlog_warn("Flushing failed: %s", safe_strerror(errno));
@@ -281,10 +281,10 @@ int isis_send_pdu_bcast(struct isis_circuit *circuit, int level)
         */
        eth = (struct ether_header *)sock_buff;
        if (level == 1)
-               memcpy(eth->ether_dhost, ALL_L1_ISS, ETHER_ADDR_LEN);
+               memcpy(eth->ether_dhost, ALL_L1_ISS, ETH_ALEN);
        else
-               memcpy(eth->ether_dhost, ALL_L2_ISS, ETHER_ADDR_LEN);
-       memcpy(eth->ether_shost, circuit->u.bc.snpa, ETHER_ADDR_LEN);
+               memcpy(eth->ether_dhost, ALL_L2_ISS, ETH_ALEN);
+       memcpy(eth->ether_shost, circuit->u.bc.snpa, ETH_ALEN);
        size_t frame_size = stream_get_endp(circuit->snd_stream) + LLC_LEN;
        eth->ether_type = htons(isis_ethertype(frame_size));
 
index 72810532b01a83026a658b13a9869a16164362c6..9622dcdbc4e480c424a7f20fb231920385cfe35d 100644 (file)
 #include <netinet/if_ether.h>
 #endif
 
-#ifndef ETHER_ADDR_LEN
-#define        ETHER_ADDR_LEN  ETHERADDRL
-#endif
-
 #include "log.h"
 #include "memory.h"
 #include "vrf.h"
@@ -48,7 +44,6 @@
 #include "isisd/isis_common.h"
 #include "isisd/isis_flags.h"
 #include "isisd/isis_circuit.h"
-#include "isisd/isis_tlv.h"
 #include "isisd/isis_lsp.h"
 #include "isisd/isis_pdu.h"
 #include "isisd/isis_network.h"
index 5e523cd68ba73dbb38c2dd384d19d797ab5f36c1..ad53be46836619ded13fa3b69ee7393f033e4964 100644 (file)
@@ -26,6 +26,7 @@
 #include "vty.h"
 #include "if.h"
 #include "qobj.h"
+#include "prefix.h"
 
 #include "isis_constants.h"
 #include "isis_common.h"
index ba6c5f876d7f309ef9f9d98501a3e69ecfd567cc..b157bb18369f19a7cc2ec687c91b1ba942368f58 100644 (file)
@@ -46,16 +46,6 @@ struct isis_passwd {
        u_char passwd[255];
 };
 
-/*
- * (Dynamic) Hostname
- * one struct for cache list
- * one struct for LSP TLV
- */
-struct hostname {
-       u_char namelen;
-       u_char name[255];
-};
-
 /*
  * Supported Protocol IDs
  */
index 4b5ff888bab52b7bfd05d3c3bc05e77f476767df..f3a5a24dde577b0ca62913837b686c71ce99b431 100644 (file)
        ((if_is_broadcast((C)->interface)) ? (C->interface->mtu - LLC_LEN)     \
                                           : (C->interface->mtu))
 
-#ifndef ETH_ALEN
-#define ETH_ALEN 6
-#endif
-
 #define MAX_LLC_LEN 0x5ff
 #define ETHERTYPE_EXT_LLC 0x8870
 
index b0ccdee769e24d68717504677430f66b1f359506..10870d5c50210c222d8ea40b9107ab540b28ef9f 100644 (file)
@@ -37,7 +37,6 @@
 #include "isisd/isis_common.h"
 #include "isisd/isis_flags.h"
 #include "isisd/isis_circuit.h"
-#include "isisd/isis_tlv.h"
 #include "isisd/isis_lsp.h"
 #include "isisd/isis_pdu.h"
 #include "isisd/isis_network.h"
index 3f532ecf84a1b757f49ae451ccf2684876f591ce..2db82719156373ccf048098571648b3fc8977141 100644 (file)
@@ -42,7 +42,6 @@
 #include "isisd/isis_adjacency.h"
 #include "isisd/isis_constants.h"
 #include "isisd/isis_pdu.h"
-#include "isisd/isis_tlv.h"
 #include "isisd/isis_lsp.h"
 #include "isisd/isis_dr.h"
 #include "isisd/isis_events.h"
index 9249ad6290677ebf4b8543d488ed0f0e62301f2a..6fa7988304263020e6829f82fa4402eb436f7995 100644 (file)
@@ -94,38 +94,26 @@ struct isis_dynhn *dynhn_find_by_name(const char *hostname)
        struct isis_dynhn *dyn = NULL;
 
        for (ALL_LIST_ELEMENTS_RO(dyn_cache, node, dyn))
-               if (strncmp((char *)dyn->name.name, hostname, 255) == 0)
+               if (strncmp(dyn->hostname, hostname, 255) == 0)
                        return dyn;
 
        return NULL;
 }
 
-void isis_dynhn_insert(const u_char *id, struct hostname *hostname, int level)
+void isis_dynhn_insert(const u_char *id, const char *hostname, int level)
 {
        struct isis_dynhn *dyn;
 
        dyn = dynhn_find_by_id(id);
-       if (dyn) {
-               memcpy(&dyn->name, hostname, hostname->namelen + 1);
-               memcpy(dyn->id, id, ISIS_SYS_ID_LEN);
-               dyn->refresh = time(NULL);
-               return;
-       }
-       dyn = XCALLOC(MTYPE_ISIS_DYNHN, sizeof(struct isis_dynhn));
        if (!dyn) {
-               zlog_warn("isis_dynhn_insert(): out of memory!");
-               return;
+               dyn = XCALLOC(MTYPE_ISIS_DYNHN, sizeof(struct isis_dynhn));
+               memcpy(dyn->id, id, ISIS_SYS_ID_LEN);
+               dyn->level = level;
+               listnode_add(dyn_cache, dyn);
        }
 
-       /* we also copy the length */
-       memcpy(&dyn->name, hostname, hostname->namelen + 1);
-       memcpy(dyn->id, id, ISIS_SYS_ID_LEN);
+       snprintf(dyn->hostname, sizeof(dyn->hostname), "%s", hostname);
        dyn->refresh = time(NULL);
-       dyn->level = level;
-
-       listnode_add(dyn_cache, dyn);
-
-       return;
 }
 
 void isis_dynhn_remove(const u_char *id)
@@ -137,7 +125,6 @@ void isis_dynhn_remove(const u_char *id)
                return;
        listnode_delete(dyn_cache, dyn);
        XFREE(MTYPE_ISIS_DYNHN, dyn);
-       return;
 }
 
 /*
@@ -155,7 +142,7 @@ void dynhn_print_all(struct vty *vty)
        for (ALL_LIST_ELEMENTS_RO(dyn_cache, node, dyn)) {
                vty_out(vty, "%-7d", dyn->level);
                vty_out(vty, "%-15s%-15s\n", sysid_print(dyn->id),
-                       dyn->name.name);
+                       dyn->hostname);
        }
 
        vty_out(vty, "     * %s %s\n", sysid_print(isis->sysid),
index f3ca94d40f9b6a2fb98d43e5eef1f495d65b6838..635d79f3f3f37f9602b8b94c9ae3c8aea993c6b6 100644 (file)
 
 struct isis_dynhn {
        u_char id[ISIS_SYS_ID_LEN];
-       struct hostname name;
+       char hostname[256];
        time_t refresh;
        int level;
 };
 
 void dyn_cache_init(void);
-void isis_dynhn_insert(const u_char *id, struct hostname *hostname, int level);
+void isis_dynhn_insert(const u_char *id, const char *hostname, int level);
 void isis_dynhn_remove(const u_char *id);
 struct isis_dynhn *dynhn_find_by_id(const u_char *id);
 struct isis_dynhn *dynhn_find_by_name(const char *hostname);
index 9af256ba3869eaaf0dd8844b6c526aaf8134c14a..1cc90d031c80874f205ba03d648c38117e8e8829 100644 (file)
@@ -37,7 +37,6 @@
 #include "isisd/isis_common.h"
 #include "isisd/isis_flags.h"
 #include "isisd/isis_circuit.h"
-#include "isisd/isis_tlv.h"
 #include "isisd/isis_lsp.h"
 #include "isisd/isis_pdu.h"
 #include "isisd/isis_network.h"
index 40c6141ab8128a5bdbea2085388a9c4fdab0fb3f..51fe41a706473e13833a963d1e113b8782a48d0f 100644 (file)
@@ -44,7 +44,6 @@
 #include "isisd/isis_flags.h"
 #include "isisd/isis_circuit.h"
 #include "isisd/isisd.h"
-#include "isisd/isis_tlv.h"
 #include "isisd/isis_lsp.h"
 #include "isisd/isis_pdu.h"
 #include "isisd/isis_dynhn.h"
@@ -54,6 +53,7 @@
 #include "isisd/isis_spf.h"
 #include "isisd/isis_te.h"
 #include "isisd/isis_mt.h"
+#include "isisd/isis_tlvs.h"
 
 /* staticly assigned vars for printing purposes */
 char lsp_bits_string[200]; /* FIXME: enough ? */
@@ -105,19 +105,8 @@ static void lsp_clear_data(struct isis_lsp *lsp)
        if (!lsp)
                return;
 
-       if (lsp->tlv_data.hostname)
-               isis_dynhn_remove(lsp->lsp_header->lsp_id);
-
-       if (lsp->own_lsp) {
-               if (lsp->tlv_data.nlpids)
-                       XFREE(MTYPE_ISIS_TLV, lsp->tlv_data.nlpids);
-               if (lsp->tlv_data.hostname)
-                       XFREE(MTYPE_ISIS_TLV, lsp->tlv_data.hostname);
-               if (lsp->tlv_data.router_id)
-                       XFREE(MTYPE_ISIS_TLV, lsp->tlv_data.router_id);
-       }
-
-       free_tlvs(&lsp->tlv_data);
+       isis_free_tlvs(lsp->tlvs);
+       lsp->tlvs = NULL;
 }
 
 static void lsp_destroy(struct isis_lsp *lsp)
@@ -146,7 +135,7 @@ static void lsp_destroy(struct isis_lsp *lsp)
 
        lsp_clear_data(lsp);
 
-       if (LSP_FRAGMENT(lsp->lsp_header->lsp_id) == 0 && lsp->lspu.frags) {
+       if (LSP_FRAGMENT(lsp->hdr.lsp_id) == 0 && lsp->lspu.frags) {
                list_delete(lsp->lspu.frags);
                lsp->lspu.frags = NULL;
        }
@@ -187,7 +176,7 @@ static void lsp_remove_frags(struct list *frags, dict_t *lspdb)
        struct isis_lsp *lsp;
 
        for (ALL_LIST_ELEMENTS(frags, lnode, lnnode, lsp)) {
-               dnode = dict_lookup(lspdb, lsp->lsp_header->lsp_id);
+               dnode = dict_lookup(lspdb, lsp->hdr.lsp_id);
                lsp_destroy(lsp);
                dnode_destroy(dict_delete(lspdb, dnode));
        }
@@ -209,7 +198,7 @@ void lsp_search_and_destroy(u_char *id, dict_t *lspdb)
                /*
                 * If this is a zero lsp, remove all the frags now
                 */
-               if (LSP_FRAGMENT(lsp->lsp_header->lsp_id) == 0) {
+               if (LSP_FRAGMENT(lsp->hdr.lsp_id) == 0) {
                        if (lsp->lspu.frags)
                                lsp_remove_frags(lsp->lspu.frags, lspdb);
                } else {
@@ -231,29 +220,25 @@ void lsp_search_and_destroy(u_char *id, dict_t *lspdb)
  * Compares a LSP to given values
  * Params are given in net order
  */
-int lsp_compare(char *areatag, struct isis_lsp *lsp, u_int32_t seq_num,
-               u_int16_t checksum, u_int16_t rem_lifetime)
+int lsp_compare(char *areatag, struct isis_lsp *lsp, uint32_t seqno,
+               uint16_t checksum, uint16_t rem_lifetime)
 {
-       /* no point in double ntohl on seqnum */
-       if (lsp->lsp_header->seq_num == seq_num
-           && lsp->lsp_header->checksum == checksum &&
-           /*comparing with 0, no need to do ntohl */
-           ((lsp->lsp_header->rem_lifetime == 0 && rem_lifetime == 0)
-            || (lsp->lsp_header->rem_lifetime != 0 && rem_lifetime != 0))) {
+       if (lsp->hdr.seqno == seqno && lsp->hdr.checksum == checksum
+           && ((lsp->hdr.rem_lifetime == 0 && rem_lifetime == 0)
+               || (lsp->hdr.rem_lifetime != 0 && rem_lifetime != 0))) {
                if (isis->debugs & DEBUG_SNP_PACKETS) {
                        zlog_debug(
-                               "ISIS-Snp (%s): Compare LSP %s seq 0x%08x, cksum 0x%04x,"
-                               " lifetime %us",
-                               areatag,
-                               rawlspid_print(lsp->lsp_header->lsp_id),
-                               ntohl(lsp->lsp_header->seq_num),
-                               ntohs(lsp->lsp_header->checksum),
-                               ntohs(lsp->lsp_header->rem_lifetime));
+                               "ISIS-Snp (%s): Compare LSP %s seq 0x%08" PRIx32
+                               ", cksum 0x%04" PRIx16 ", lifetime %" PRIu16
+                               "s",
+                               areatag, rawlspid_print(lsp->hdr.lsp_id),
+                               lsp->hdr.seqno, lsp->hdr.checksum,
+                               lsp->hdr.rem_lifetime);
                        zlog_debug(
-                               "ISIS-Snp (%s):         is equal to ours seq 0x%08x,"
-                               " cksum 0x%04x, lifetime %us",
-                               areatag, ntohl(seq_num), ntohs(checksum),
-                               ntohs(rem_lifetime));
+                               "ISIS-Snp (%s):         is equal to ours seq 0x%08" PRIx32
+                               ", cksum 0x%04" PRIx16 ", lifetime %" PRIu16
+                               "s",
+                               areatag, seqno, checksum, rem_lifetime);
                }
                return LSP_EQUAL;
        }
@@ -270,171 +255,136 @@ int lsp_compare(char *areatag, struct isis_lsp *lsp, u_int32_t seq_num,
         * as given
         *    in 7.3.16.2.
         */
-       if (ntohl(seq_num) > ntohl(lsp->lsp_header->seq_num)
-           || (ntohl(seq_num) == ntohl(lsp->lsp_header->seq_num)
-               && ((lsp->lsp_header->rem_lifetime != 0 && rem_lifetime == 0)
-                   || lsp->lsp_header->checksum != checksum))) {
+       if (seqno > lsp->hdr.seqno
+           || (seqno == lsp->hdr.seqno
+               && ((lsp->hdr.rem_lifetime != 0 && rem_lifetime == 0)
+                   || lsp->hdr.checksum != checksum))) {
                if (isis->debugs & DEBUG_SNP_PACKETS) {
                        zlog_debug(
-                               "ISIS-Snp (%s): Compare LSP %s seq 0x%08x, cksum 0x%04x,"
-                               " lifetime %us",
-                               areatag,
-                               rawlspid_print(lsp->lsp_header->lsp_id),
-                               ntohl(seq_num), ntohs(checksum),
-                               ntohs(rem_lifetime));
+                               "ISIS-Snp (%s): Compare LSP %s seq 0x%08" PRIx32
+                               ", cksum 0x%04" PRIx16 ", lifetime %" PRIu16
+                               "s",
+                               areatag, rawlspid_print(lsp->hdr.lsp_id), seqno,
+                               checksum, rem_lifetime);
                        zlog_debug(
-                               "ISIS-Snp (%s):       is newer than ours seq 0x%08x, "
-                               "cksum 0x%04x, lifetime %us",
-                               areatag, ntohl(lsp->lsp_header->seq_num),
-                               ntohs(lsp->lsp_header->checksum),
-                               ntohs(lsp->lsp_header->rem_lifetime));
+                               "ISIS-Snp (%s):       is newer than ours seq 0x%08" PRIx32
+                               ", cksum 0x%04" PRIx16 ", lifetime %" PRIu16
+                               "s",
+                               areatag, lsp->hdr.seqno, lsp->hdr.checksum,
+                               lsp->hdr.rem_lifetime);
                }
                return LSP_NEWER;
        }
        if (isis->debugs & DEBUG_SNP_PACKETS) {
+               zlog_debug("ISIS-Snp (%s): Compare LSP %s seq 0x%08" PRIx32
+                          ", cksum 0x%04" PRIx16 ", lifetime %" PRIu16 "s",
+                          areatag, rawlspid_print(lsp->hdr.lsp_id), seqno,
+                          checksum, rem_lifetime);
                zlog_debug(
-                       "ISIS-Snp (%s): Compare LSP %s seq 0x%08x, cksum 0x%04x, lifetime %us",
-                       areatag, rawlspid_print(lsp->lsp_header->lsp_id),
-                       ntohl(seq_num), ntohs(checksum), ntohs(rem_lifetime));
-               zlog_debug(
-                       "ISIS-Snp (%s):       is older than ours seq 0x%08x,"
-                       " cksum 0x%04x, lifetime %us",
-                       areatag, ntohl(lsp->lsp_header->seq_num),
-                       ntohs(lsp->lsp_header->checksum),
-                       ntohs(lsp->lsp_header->rem_lifetime));
+                       "ISIS-Snp (%s):       is older than ours seq 0x%08" PRIx32
+                       ", cksum 0x%04" PRIx16 ", lifetime %" PRIu16 "s",
+                       areatag, lsp->hdr.seqno, lsp->hdr.checksum,
+                       lsp->hdr.rem_lifetime);
        }
 
        return LSP_OLDER;
 }
 
-static void lsp_auth_add(struct isis_lsp *lsp)
+static void put_lsp_hdr(struct isis_lsp *lsp, size_t *len_pointer)
 {
-       struct isis_passwd *passwd;
-       unsigned char hmac_md5_hash[ISIS_AUTH_MD5_SIZE];
-
-       /*
-        * Add the authentication info if its present
-        */
-       (lsp->level == IS_LEVEL_1) ? (passwd = &lsp->area->area_passwd)
-                                  : (passwd = &lsp->area->domain_passwd);
-       switch (passwd->type) {
-       /* Cleartext */
-       case ISIS_PASSWD_TYPE_CLEARTXT:
-               memcpy(&lsp->tlv_data.auth_info, passwd,
-                      sizeof(struct isis_passwd));
-               tlv_add_authinfo(passwd->type, passwd->len, passwd->passwd,
-                                lsp->pdu);
-               break;
-
-       /* HMAC MD5 */
-       case ISIS_PASSWD_TYPE_HMAC_MD5:
-               /* Remember where TLV is written so we can later
-                * overwrite the MD5 hash */
-               lsp->auth_tlv_offset = stream_get_endp(lsp->pdu);
-               memset(&hmac_md5_hash, 0, ISIS_AUTH_MD5_SIZE);
-               lsp->tlv_data.auth_info.type = ISIS_PASSWD_TYPE_HMAC_MD5;
-               lsp->tlv_data.auth_info.len = ISIS_AUTH_MD5_SIZE;
-               memcpy(&lsp->tlv_data.auth_info.passwd, hmac_md5_hash,
-                      ISIS_AUTH_MD5_SIZE);
-               tlv_add_authinfo(passwd->type, ISIS_AUTH_MD5_SIZE,
-                                hmac_md5_hash, lsp->pdu);
-               break;
-
-       default:
-               break;
-       }
+       uint8_t pdu_type =
+               (lsp->level == IS_LEVEL_1) ? L1_LINK_STATE : L2_LINK_STATE;
+       struct isis_lsp_hdr *hdr = &lsp->hdr;
+       struct stream *stream = lsp->pdu;
+
+       fill_fixed_hdr(pdu_type, stream);
+
+       if (len_pointer)
+               *len_pointer = stream_get_endp(stream);
+       stream_putw(stream, hdr->pdu_len);
+       stream_putw(stream, hdr->rem_lifetime);
+       stream_put(stream, hdr->lsp_id, sizeof(hdr->lsp_id));
+       stream_putl(stream, hdr->seqno);
+       stream_putw(stream, hdr->checksum);
+       stream_putc(stream, hdr->lsp_bits);
 }
 
-static void lsp_auth_update(struct isis_lsp *lsp)
+static void lsp_add_auth(struct isis_lsp *lsp)
 {
        struct isis_passwd *passwd;
-       unsigned char hmac_md5_hash[ISIS_AUTH_MD5_SIZE];
-       uint16_t checksum, rem_lifetime;
+       passwd = (lsp->level == IS_LEVEL_1) ? &lsp->area->area_passwd
+                                           : &lsp->area->domain_passwd;
+       isis_tlvs_add_auth(lsp->tlvs, passwd);
+}
 
-       /* For HMAC MD5 we need to recompute the md5 hash and store it */
-       (lsp->level == IS_LEVEL_1) ? (passwd = &lsp->area->area_passwd)
-                                  : (passwd = &lsp->area->domain_passwd);
-       if (passwd->type != ISIS_PASSWD_TYPE_HMAC_MD5)
-               return;
+static void lsp_pack_pdu(struct isis_lsp *lsp)
+{
+       if (!lsp->tlvs)
+               lsp->tlvs = isis_alloc_tlvs();
 
-       /*
-        * In transient conditions (when net is configured where authentication
-        * config and lsp regenerate schedule is not yet run), there could be
-        * an own_lsp with auth_tlv_offset set to 0. In such a case, simply
-        * return, when lsp_regenerate is run, lsp will have auth tlv.
-        */
-       if (lsp->auth_tlv_offset == 0)
-               return;
+       lsp_add_auth(lsp);
 
-       /*
-        * RFC 5304 set auth value, checksum and remaining lifetime to zero
-        * before computation and reset to old values after computation.
-        */
-       checksum = lsp->lsp_header->checksum;
-       rem_lifetime = lsp->lsp_header->rem_lifetime;
-       lsp->lsp_header->checksum = 0;
-       lsp->lsp_header->rem_lifetime = 0;
-       /* Set the authentication value as well to zero */
-       memset(STREAM_DATA(lsp->pdu) + lsp->auth_tlv_offset + 3, 0,
-              ISIS_AUTH_MD5_SIZE);
-       /* Compute autentication value */
-       hmac_md5(STREAM_DATA(lsp->pdu), stream_get_endp(lsp->pdu),
-                (unsigned char *)&passwd->passwd, passwd->len,
-                (unsigned char *)&hmac_md5_hash);
-       /* Copy the hash into the stream */
-       memcpy(STREAM_DATA(lsp->pdu) + lsp->auth_tlv_offset + 3, hmac_md5_hash,
-              ISIS_AUTH_MD5_SIZE);
-       memcpy(&lsp->tlv_data.auth_info.passwd, hmac_md5_hash,
-              ISIS_AUTH_MD5_SIZE);
-       /* Copy back the checksum and remaining lifetime */
-       lsp->lsp_header->checksum = checksum;
-       lsp->lsp_header->rem_lifetime = rem_lifetime;
+       size_t len_pointer;
+       stream_reset(lsp->pdu);
+       put_lsp_hdr(lsp, &len_pointer);
+       isis_pack_tlvs(lsp->tlvs, lsp->pdu, len_pointer, false, true);
+
+       lsp->hdr.pdu_len = stream_get_endp(lsp->pdu);
+       lsp->hdr.checksum =
+               ntohs(fletcher_checksum(STREAM_DATA(lsp->pdu) + 12,
+                                       stream_get_endp(lsp->pdu) - 12, 12));
 }
 
-void lsp_inc_seqnum(struct isis_lsp *lsp, u_int32_t seq_num)
+void lsp_inc_seqno(struct isis_lsp *lsp, uint32_t seqno)
 {
-       u_int32_t newseq;
+       uint32_t newseq;
 
-       if (seq_num == 0 || ntohl(lsp->lsp_header->seq_num) > seq_num)
-               newseq = ntohl(lsp->lsp_header->seq_num) + 1;
+       if (seqno == 0 || lsp->hdr.seqno > seqno)
+               newseq = lsp->hdr.seqno + 1;
        else
-               newseq = seq_num + 1;
-
-       lsp->lsp_header->seq_num = htonl(newseq);
-
-       /* Recompute authentication and checksum information */
-       lsp_auth_update(lsp);
-       /* ISO 10589 - 7.3.11 Generation of the checksum
-        * The checksum shall be computed over all fields in the LSP which
-        * appear
-        * after the Remaining Lifetime field. This field (and those appearing
-        * before it) are excluded so that the LSP may be aged by systems
-        * without
-        * requiring recomputation.
-        */
-       fletcher_checksum(STREAM_DATA(lsp->pdu) + 12,
-                         ntohs(lsp->lsp_header->pdu_len) - 12, 12);
+               newseq = seqno + 1;
+
+       lsp->hdr.seqno = newseq;
 
+       lsp_pack_pdu(lsp);
        isis_spf_schedule(lsp->area, lsp->level);
+}
 
-       return;
+static void lsp_purge(struct isis_lsp *lsp, int level)
+{
+       /* reset stream */
+       lsp_clear_data(lsp);
+       stream_reset(lsp->pdu);
+
+       /* update header */
+       lsp->hdr.checksum = 0;
+       lsp->hdr.rem_lifetime = 0;
+       lsp->level = level;
+       lsp->age_out = lsp->area->max_lsp_lifetime[level - 1];
+
+       lsp_pack_pdu(lsp);
+       lsp_set_all_srmflags(lsp);
 }
 
 /*
- * Genetates checksum for LSP and its frags
+ * Generates checksum for LSP and its frags
  */
-static void lsp_seqnum_update(struct isis_lsp *lsp0)
+static void lsp_seqno_update(struct isis_lsp *lsp0)
 {
        struct isis_lsp *lsp;
        struct listnode *node;
 
-       lsp_inc_seqnum(lsp0, 0);
+       lsp_inc_seqno(lsp0, 0);
 
        if (!lsp0->lspu.frags)
                return;
 
-       for (ALL_LIST_ELEMENTS_RO(lsp0->lspu.frags, node, lsp))
-               lsp_inc_seqnum(lsp, 0);
+       for (ALL_LIST_ELEMENTS_RO(lsp0->lspu.frags, node, lsp)) {
+               if (lsp->tlvs)
+                       lsp_inc_seqno(lsp, 0);
+               else
+                       lsp_purge(lsp, lsp0->level);
+       }
 
        return;
 }
@@ -453,12 +403,10 @@ static u_int8_t lsp_bits_generate(int level, int overload_bit, int attached_bit)
        return lsp_bits;
 }
 
-static void lsp_update_data(struct isis_lsp *lsp, struct stream *stream,
+static void lsp_update_data(struct isis_lsp *lsp, struct isis_lsp_hdr *hdr,
+                           struct isis_tlvs *tlvs, struct stream *stream,
                            struct isis_area *area, int level)
 {
-       uint32_t expected = 0, found;
-       int retval;
-
        /* free the old lsp data */
        lsp_clear_data(lsp);
 
@@ -467,50 +415,17 @@ static void lsp_update_data(struct isis_lsp *lsp, struct stream *stream,
                stream_free(lsp->pdu);
        lsp->pdu = stream_dup(stream);
 
-       /* setting pointers to the correct place */
-       lsp->isis_header = (struct isis_fixed_hdr *)(STREAM_DATA(lsp->pdu));
-       lsp->lsp_header = (struct isis_link_state_hdr *)(STREAM_DATA(lsp->pdu)
-                                                        + ISIS_FIXED_HDR_LEN);
+       memcpy(&lsp->hdr, hdr, sizeof(lsp->hdr));
        lsp->area = area;
        lsp->level = level;
        lsp->age_out = ZERO_AGE_LIFETIME;
        lsp->installed = time(NULL);
-       /*
-        * Get LSP data i.e. TLVs
-        */
-       expected |= TLVFLAG_AUTH_INFO;
-       expected |= TLVFLAG_AREA_ADDRS;
-       expected |= TLVFLAG_IS_NEIGHS;
-       expected |= TLVFLAG_NLPID;
-       if (area->dynhostname)
-               expected |= TLVFLAG_DYN_HOSTNAME;
-       if (area->newmetric) {
-               expected |= TLVFLAG_TE_IS_NEIGHS;
-               expected |= TLVFLAG_TE_IPV4_REACHABILITY;
-               expected |= TLVFLAG_TE_ROUTER_ID;
-       }
-       expected |= TLVFLAG_MT_ROUTER_INFORMATION;
-       expected |= TLVFLAG_IPV4_ADDR;
-       expected |= TLVFLAG_IPV4_INT_REACHABILITY;
-       expected |= TLVFLAG_IPV4_EXT_REACHABILITY;
-       expected |= TLVFLAG_IPV6_ADDR;
-       expected |= TLVFLAG_IPV6_REACHABILITY;
-
-       retval = parse_tlvs(area->area_tag,
-                           STREAM_DATA(lsp->pdu) + ISIS_FIXED_HDR_LEN
-                                   + ISIS_LSP_HDR_LEN,
-                           ntohs(lsp->lsp_header->pdu_len) - ISIS_FIXED_HDR_LEN
-                                   - ISIS_LSP_HDR_LEN,
-                           &expected, &found, &lsp->tlv_data, NULL);
-       if (retval != ISIS_OK) {
-               zlog_warn("Could not parse LSP");
-               return;
-       }
 
-       if ((found & TLVFLAG_DYN_HOSTNAME) && (area->dynhostname)) {
-               isis_dynhn_insert(lsp->lsp_header->lsp_id,
-                                 lsp->tlv_data.hostname,
-                                 (lsp->lsp_header->lsp_bits & LSPBIT_IST)
+       lsp->tlvs = tlvs;
+
+       if (area->dynhostname && lsp->tlvs->hostname) {
+               isis_dynhn_insert(lsp->hdr.lsp_id, lsp->tlvs->hostname,
+                                 (lsp->hdr.lsp_bits & LSPBIT_IST)
                                                  == IS_LEVEL_1_AND_2
                                          ? IS_LEVEL_2
                                          : IS_LEVEL_1);
@@ -519,44 +434,55 @@ static void lsp_update_data(struct isis_lsp *lsp, struct stream *stream,
        return;
 }
 
-void lsp_update(struct isis_lsp *lsp, struct stream *stream,
-               struct isis_area *area, int level)
+void lsp_update(struct isis_lsp *lsp, struct isis_lsp_hdr *hdr,
+               struct isis_tlvs *tlvs, struct stream *stream,
+               struct isis_area *area, int level, bool confusion)
 {
        dnode_t *dnode = NULL;
 
        /* Remove old LSP from database. This is required since the
         * lsp_update_data will free the lsp->pdu (which has the key, lsp_id)
-        * and will update it with the new data in the stream. */
-       dnode = dict_lookup(area->lspdb[level - 1], lsp->lsp_header->lsp_id);
+        * and will update it with the new data in the stream.
+        * XXX: This doesn't hold true anymore since the header is now a copy.
+        * keeping the LSP in the dict if it is already present should be possible */
+       dnode = dict_lookup(area->lspdb[level - 1], lsp->hdr.lsp_id);
        if (dnode)
                dnode_destroy(dict_delete(area->lspdb[level - 1], dnode));
 
        if (lsp->own_lsp) {
                zlog_err(
                        "ISIS-Upd (%s): BUG updating LSP %s still marked as own LSP",
-                       area->area_tag,
-                       rawlspid_print(lsp->lsp_header->lsp_id));
+                       area->area_tag, rawlspid_print(lsp->hdr.lsp_id));
                lsp_clear_data(lsp);
                lsp->own_lsp = 0;
        }
 
-       /* rebuild the lsp data */
-       lsp_update_data(lsp, stream, area, level);
+       if (confusion) {
+               lsp_clear_data(lsp);
+               if (lsp->pdu != NULL)
+                       stream_free(lsp->pdu);
+               lsp->pdu = stream_new(LLC_LEN + area->lsp_mtu);
+               lsp->age_out = ZERO_AGE_LIFETIME;
+               lsp->hdr.rem_lifetime = 0;
+               lsp_pack_pdu(lsp);
+       } else {
+               lsp_update_data(lsp, hdr, tlvs, stream, area, level);
+       }
 
        /* insert the lsp back into the database */
        lsp_insert(lsp, area->lspdb[level - 1]);
 }
 
 /* creation of LSP directly from what we received */
-struct isis_lsp *lsp_new_from_stream_ptr(struct stream *stream,
-                                        u_int16_t pdu_len,
-                                        struct isis_lsp *lsp0,
-                                        struct isis_area *area, int level)
+struct isis_lsp *lsp_new_from_recv(struct isis_lsp_hdr *hdr,
+                                  struct isis_tlvs *tlvs,
+                                  struct stream *stream, struct isis_lsp *lsp0,
+                                  struct isis_area *area, int level)
 {
        struct isis_lsp *lsp;
 
        lsp = XCALLOC(MTYPE_ISIS_LSP, sizeof(struct isis_lsp));
-       lsp_update_data(lsp, stream, area, level);
+       lsp_update_data(lsp, hdr, tlvs, stream, area, level);
 
        if (lsp0 == NULL) {
                /*
@@ -576,8 +502,8 @@ struct isis_lsp *lsp_new_from_stream_ptr(struct stream *stream,
 }
 
 struct isis_lsp *lsp_new(struct isis_area *area, u_char *lsp_id,
-                        u_int16_t rem_lifetime, u_int32_t seq_num,
-                        u_int8_t lsp_bits, u_int16_t checksum, int level)
+                        uint16_t rem_lifetime, uint32_t seqno,
+                        uint8_t lsp_bits, uint16_t checksum, int level)
 {
        struct isis_lsp *lsp;
 
@@ -587,44 +513,32 @@ struct isis_lsp *lsp_new(struct isis_area *area, u_char *lsp_id,
        lsp->pdu = stream_new(LLC_LEN + area->lsp_mtu);
        if (LSP_FRAGMENT(lsp_id) == 0)
                lsp->lspu.frags = list_new();
-       lsp->isis_header = (struct isis_fixed_hdr *)(STREAM_DATA(lsp->pdu));
-       lsp->lsp_header = (struct isis_link_state_hdr *)(STREAM_DATA(lsp->pdu)
-                                                        + ISIS_FIXED_HDR_LEN);
 
-       /* at first we fill the FIXED HEADER */
-       (level == IS_LEVEL_1) ? fill_fixed_hdr(lsp->isis_header, L1_LINK_STATE)
-                             : fill_fixed_hdr(lsp->isis_header, L2_LINK_STATE);
-
-       /* now for the LSP HEADER */
        /* Minimal LSP PDU size */
-       lsp->lsp_header->pdu_len = htons(ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
-       memcpy(lsp->lsp_header->lsp_id, lsp_id, ISIS_SYS_ID_LEN + 2);
-       lsp->lsp_header->checksum = checksum; /* Provided in network order */
-       lsp->lsp_header->seq_num = htonl(seq_num);
-       lsp->lsp_header->rem_lifetime = htons(rem_lifetime);
-       lsp->lsp_header->lsp_bits = lsp_bits;
+       lsp->hdr.pdu_len = ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN;
+       memcpy(lsp->hdr.lsp_id, lsp_id, sizeof(lsp->hdr.lsp_id));
+       lsp->hdr.checksum = checksum;
+       lsp->hdr.seqno = seqno;
+       lsp->hdr.rem_lifetime = rem_lifetime;
+       lsp->hdr.lsp_bits = lsp_bits;
        lsp->level = level;
        lsp->age_out = ZERO_AGE_LIFETIME;
-
-       stream_forward_endp(lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
+       put_lsp_hdr(lsp, NULL);
 
        if (isis->debugs & DEBUG_EVENTS)
                zlog_debug("New LSP with ID %s-%02x-%02x len %d seqnum %08x",
-                          sysid_print(lsp_id),
-                          LSP_PSEUDO_ID(lsp->lsp_header->lsp_id),
-                          LSP_FRAGMENT(lsp->lsp_header->lsp_id),
-                          ntohl(lsp->lsp_header->pdu_len),
-                          ntohl(lsp->lsp_header->seq_num));
+                          sysid_print(lsp_id), LSP_PSEUDO_ID(lsp->hdr.lsp_id),
+                          LSP_FRAGMENT(lsp->hdr.lsp_id), lsp->hdr.pdu_len,
+                          lsp->hdr.seqno);
 
        return lsp;
 }
 
 void lsp_insert(struct isis_lsp *lsp, dict_t *lspdb)
 {
-       dict_alloc_insert(lspdb, lsp->lsp_header->lsp_id, lsp);
-       if (lsp->lsp_header->seq_num != 0) {
+       dict_alloc_insert(lspdb, lsp->hdr.lsp_id, lsp);
+       if (lsp->hdr.seqno)
                isis_spf_schedule(lsp->area, lsp->level);
-       }
 }
 
 /*
@@ -643,14 +557,13 @@ void lsp_build_list_nonzero_ht(u_char *start_id, u_char *stop_id,
 
        curr = first;
 
-       if (((struct isis_lsp *)(curr->dict_data))->lsp_header->rem_lifetime)
+       if (((struct isis_lsp *)(curr->dict_data))->hdr.rem_lifetime)
                listnode_add(list, first->dict_data);
 
        while (curr) {
                curr = dict_next(lspdb, curr);
                if (curr
-                   && ((struct isis_lsp *)(curr->dict_data))
-                              ->lsp_header->rem_lifetime)
+                   && ((struct isis_lsp *)(curr->dict_data))->hdr.rem_lifetime)
                        listnode_add(list, curr->dict_data);
                if (curr == last)
                        break;
@@ -659,77 +572,19 @@ void lsp_build_list_nonzero_ht(u_char *start_id, u_char *stop_id,
        return;
 }
 
-/*
- * Build a list of num_lsps LSPs bounded by start_id and stop_id.
- */
-void lsp_build_list(u_char *start_id, u_char *stop_id, u_char num_lsps,
-                   struct list *list, dict_t *lspdb)
-{
-       u_char count;
-       dnode_t *first, *last, *curr;
-
-       first = dict_lower_bound(lspdb, start_id);
-       if (!first)
-               return;
-
-       last = dict_upper_bound(lspdb, stop_id);
-
-       curr = first;
-
-       listnode_add(list, first->dict_data);
-       count = 1;
-
-       while (curr) {
-               curr = dict_next(lspdb, curr);
-               if (curr) {
-                       listnode_add(list, curr->dict_data);
-                       count++;
-               }
-               if (count == num_lsps || curr == last)
-                       break;
-       }
-
-       return;
-}
-
-/*
- * Build a list of LSPs with SSN flag set for the given circuit
- */
-void lsp_build_list_ssn(struct isis_circuit *circuit, u_char num_lsps,
-                       struct list *list, dict_t *lspdb)
-{
-       dnode_t *dnode, *next;
-       struct isis_lsp *lsp;
-       u_char count = 0;
-
-       dnode = dict_first(lspdb);
-       while (dnode != NULL) {
-               next = dict_next(lspdb, dnode);
-               lsp = dnode_get(dnode);
-               if (ISIS_CHECK_FLAG(lsp->SSNflags, circuit)) {
-                       listnode_add(list, lsp);
-                       ++count;
-               }
-               if (count == num_lsps)
-                       break;
-               dnode = next;
-       }
-
-       return;
-}
-
 static void lsp_set_time(struct isis_lsp *lsp)
 {
        assert(lsp);
 
-       if (lsp->lsp_header->rem_lifetime == 0) {
+       if (lsp->hdr.rem_lifetime == 0) {
                if (lsp->age_out > 0)
                        lsp->age_out--;
                return;
        }
 
-       lsp->lsp_header->rem_lifetime =
-               htons(ntohs(lsp->lsp_header->rem_lifetime) - 1);
+       lsp->hdr.rem_lifetime--;
+       if (lsp->pdu && stream_get_endp(lsp->pdu) >= 12)
+               stream_putw_at(lsp->pdu, 10, lsp->hdr.rem_lifetime);
 }
 
 static void lspid_print(u_char *lsp_id, u_char *trg, char dynhost, char frag)
@@ -743,7 +598,7 @@ static void lspid_print(u_char *lsp_id, u_char *trg, char dynhost, char frag)
                dyn = NULL;
 
        if (dyn)
-               sprintf((char *)id, "%.14s", dyn->name.name);
+               sprintf((char *)id, "%.14s", dyn->hostname);
        else if (!memcmp(isis->sysid, lsp_id, ISIS_SYS_ID_LEN) && dynhost)
                sprintf((char *)id, "%.14s", unix_hostname());
        else
@@ -756,21 +611,21 @@ static void lspid_print(u_char *lsp_id, u_char *trg, char dynhost, char frag)
 }
 
 /* Convert the lsp attribute bits to attribute string */
-const char *lsp_bits2string(u_char *lsp_bits)
+static const char *lsp_bits2string(uint8_t lsp_bits)
 {
        char *pos = lsp_bits_string;
 
-       if (!*lsp_bits)
+       if (!lsp_bits)
                return " none";
 
        /* we only focus on the default metric */
        pos += sprintf(pos, "%d/",
-                      ISIS_MASK_LSP_ATT_DEFAULT_BIT(*lsp_bits) ? 1 : 0);
+                      ISIS_MASK_LSP_ATT_DEFAULT_BIT(lsp_bits) ? 1 : 0);
 
        pos += sprintf(pos, "%d/",
-                      ISIS_MASK_LSP_PARTITION_BIT(*lsp_bits) ? 1 : 0);
+                      ISIS_MASK_LSP_PARTITION_BIT(lsp_bits) ? 1 : 0);
 
-       pos += sprintf(pos, "%d", ISIS_MASK_LSP_OL_BIT(*lsp_bits) ? 1 : 0);
+       pos += sprintf(pos, "%d", ISIS_MASK_LSP_OL_BIT(lsp_bits) ? 1 : 0);
 
        *(pos) = '\0';
 
@@ -783,276 +638,26 @@ void lsp_print(struct isis_lsp *lsp, struct vty *vty, char dynhost)
        u_char LSPid[255];
        char age_out[8];
 
-       lspid_print(lsp->lsp_header->lsp_id, LSPid, dynhost, 1);
+       lspid_print(lsp->hdr.lsp_id, LSPid, dynhost, 1);
        vty_out(vty, "%-21s%c  ", LSPid, lsp->own_lsp ? '*' : ' ');
-       vty_out(vty, "%5u   ", ntohs(lsp->lsp_header->pdu_len));
-       vty_out(vty, "0x%08x  ", ntohl(lsp->lsp_header->seq_num));
-       vty_out(vty, "0x%04x  ", ntohs(lsp->lsp_header->checksum));
-       if (ntohs(lsp->lsp_header->rem_lifetime) == 0) {
-               snprintf(age_out, 8, "(%u)", lsp->age_out);
+       vty_out(vty, "%5" PRIu16 "   ", lsp->hdr.pdu_len);
+       vty_out(vty, "0x%08" PRIx32 "  ", lsp->hdr.seqno);
+       vty_out(vty, "0x%04" PRIx16 "  ", lsp->hdr.checksum);
+       if (lsp->hdr.rem_lifetime == 0) {
+               snprintf(age_out, 8, "(%d)", lsp->age_out);
                age_out[7] = '\0';
                vty_out(vty, "%7s   ", age_out);
        } else
-               vty_out(vty, " %5u    ", ntohs(lsp->lsp_header->rem_lifetime));
-       vty_out(vty, "%s\n", lsp_bits2string(&lsp->lsp_header->lsp_bits));
-}
-
-static void lsp_print_mt_reach(struct list *list, struct vty *vty, char dynhost,
-                              uint16_t mtid)
-{
-       struct listnode *node;
-       struct te_is_neigh *neigh;
-
-       for (ALL_LIST_ELEMENTS_RO(list, node, neigh)) {
-               u_char lspid[255];
-
-               lspid_print(neigh->neigh_id, lspid, dynhost, 0);
-               if (mtid == ISIS_MT_IPV4_UNICAST) {
-                       vty_out(vty,
-                               "  Metric      : %-8u IS-Extended   : %s\n",
-                               GET_TE_METRIC(neigh), lspid);
-               } else {
-                       vty_out(vty,
-                               "  Metric      : %-8u MT-Reach      : %s %s\n",
-                               GET_TE_METRIC(neigh), lspid,
-                               isis_mtid2str(mtid));
-               }
-               if (IS_MPLS_TE(isisMplsTE))
-                       mpls_te_print_detail(vty, neigh);
-       }
-}
-
-static void lsp_print_mt_ipv6_reach(struct list *list, struct vty *vty,
-                                   uint16_t mtid)
-{
-       struct listnode *node;
-       struct ipv6_reachability *ipv6_reach;
-       struct in6_addr in6;
-       u_char buff[BUFSIZ];
-
-       for (ALL_LIST_ELEMENTS_RO(list, node, ipv6_reach)) {
-               memset(&in6, 0, sizeof(in6));
-               memcpy(in6.s6_addr, ipv6_reach->prefix,
-                      PSIZE(ipv6_reach->prefix_len));
-               inet_ntop(AF_INET6, &in6, (char *)buff, BUFSIZ);
-               if (mtid == ISIS_MT_IPV4_UNICAST) {
-                       if ((ipv6_reach->control_info & CTRL_INFO_DISTRIBUTION)
-                           == DISTRIBUTION_INTERNAL)
-                               vty_out(vty, "  Metric      : %-8" PRIu32
-                                            " IPv6-Internal : %s/%d\n",
-                                       ntohl(ipv6_reach->metric), buff,
-                                       ipv6_reach->prefix_len);
-                       else
-                               vty_out(vty, "  Metric      : %-8" PRIu32
-                                            " IPv6-External : %s/%d\n",
-                                       ntohl(ipv6_reach->metric), buff,
-                                       ipv6_reach->prefix_len);
-               } else {
-                       if ((ipv6_reach->control_info & CTRL_INFO_DISTRIBUTION)
-                           == DISTRIBUTION_INTERNAL)
-                               vty_out(vty, "  Metric      : %-8" PRIu32
-                                            " IPv6-MT-Int   : %s/%d %s\n",
-                                       ntohl(ipv6_reach->metric), buff,
-                                       ipv6_reach->prefix_len,
-                                       isis_mtid2str(mtid));
-                       else
-                               vty_out(vty, "  Metric      : %-8" PRIu32
-                                            " IPv6-MT-Ext   : %s/%d %s\n",
-                                       ntohl(ipv6_reach->metric), buff,
-                                       ipv6_reach->prefix_len,
-                                       isis_mtid2str(mtid));
-               }
-       }
-}
-
-static void lsp_print_mt_ipv4_reach(struct list *list, struct vty *vty,
-                                   uint16_t mtid)
-{
-       struct listnode *node;
-       struct te_ipv4_reachability *te_ipv4_reach;
-
-       for (ALL_LIST_ELEMENTS_RO(list, node, te_ipv4_reach)) {
-               if (mtid == ISIS_MT_IPV4_UNICAST) {
-                       /* FIXME: There should be better way to output this
-                        * stuff. */
-                       vty_out(vty, "  Metric      : %-8" PRIu32
-                                    " IPv4-Extended : %s/%d\n",
-                               ntohl(te_ipv4_reach->te_metric),
-                               inet_ntoa(newprefix2inaddr(
-                                       &te_ipv4_reach->prefix_start,
-                                       te_ipv4_reach->control)),
-                               te_ipv4_reach->control & 0x3F);
-               } else {
-                       /* FIXME: There should be better way to output this
-                        * stuff. */
-                       vty_out(vty, "  Metric      : %-8" PRIu32
-                                    " IPv4-MT       : %s/%d %s\n",
-                               ntohl(te_ipv4_reach->te_metric),
-                               inet_ntoa(newprefix2inaddr(
-                                       &te_ipv4_reach->prefix_start,
-                                       te_ipv4_reach->control)),
-                               te_ipv4_reach->control & 0x3F,
-                               isis_mtid2str(mtid));
-               }
-       }
+               vty_out(vty, " %5" PRIu16 "    ", lsp->hdr.rem_lifetime);
+       vty_out(vty, "%s\n", lsp_bits2string(lsp->hdr.lsp_bits));
 }
 
 void lsp_print_detail(struct isis_lsp *lsp, struct vty *vty, char dynhost)
 {
-       struct area_addr *area_addr;
-       int i;
-       struct listnode *lnode;
-       struct is_neigh *is_neigh;
-       struct ipv4_reachability *ipv4_reach;
-       struct in_addr *ipv4_addr;
-       struct mt_router_info *mt_router_info;
-       struct tlv_mt_ipv6_reachs *mt_ipv6_reachs;
-       struct tlv_mt_neighbors *mt_is_neigh;
-       struct tlv_mt_ipv4_reachs *mt_ipv4_reachs;
-       u_char LSPid[255];
-       u_char hostname[255];
-       u_char ipv4_reach_prefix[20];
-       u_char ipv4_reach_mask[20];
-       u_char ipv4_address[20];
-
-       lspid_print(lsp->lsp_header->lsp_id, LSPid, dynhost, 1);
        lsp_print(lsp, vty, dynhost);
-
-       /* for all area address */
-       if (lsp->tlv_data.area_addrs)
-               for (ALL_LIST_ELEMENTS_RO(lsp->tlv_data.area_addrs, lnode,
-                                         area_addr)) {
-                       vty_out(vty, "  Area Address: %s\n",
-                               isonet_print(area_addr->area_addr,
-                                            area_addr->addr_len));
-               }
-
-       /* for the nlpid tlv */
-       if (lsp->tlv_data.nlpids) {
-               for (i = 0; i < lsp->tlv_data.nlpids->count; i++) {
-                       switch (lsp->tlv_data.nlpids->nlpids[i]) {
-                       case NLPID_IP:
-                       case NLPID_IPV6:
-                               vty_out(vty, "  NLPID       : 0x%X\n",
-                                       lsp->tlv_data.nlpids->nlpids[i]);
-                               break;
-                       default:
-                               vty_out(vty, "  NLPID       : %s\n", "unknown");
-                               break;
-                       }
-               }
-       }
-
-       for (ALL_LIST_ELEMENTS_RO(lsp->tlv_data.mt_router_info, lnode,
-                                 mt_router_info)) {
-               vty_out(vty, "  MT          : %s%s\n",
-                       isis_mtid2str(mt_router_info->mtid),
-                       mt_router_info->overload ? " (overload)" : "");
-       }
-
-       /* for the hostname tlv */
-       if (lsp->tlv_data.hostname) {
-               bzero(hostname, sizeof(hostname));
-               memcpy(hostname, lsp->tlv_data.hostname->name,
-                      lsp->tlv_data.hostname->namelen);
-               vty_out(vty, "  Hostname    : %s\n", hostname);
-       }
-
-       /* authentication tlv */
-       if (lsp->tlv_data.auth_info.type != ISIS_PASSWD_TYPE_UNUSED) {
-               if (lsp->tlv_data.auth_info.type == ISIS_PASSWD_TYPE_HMAC_MD5)
-                       vty_out(vty, "  Auth type   : md5\n");
-               else if (lsp->tlv_data.auth_info.type
-                        == ISIS_PASSWD_TYPE_CLEARTXT)
-                       vty_out(vty, "  Auth type   : clear text\n");
-       }
-
-       /* TE router id */
-       if (lsp->tlv_data.router_id) {
-               memcpy(ipv4_address, inet_ntoa(lsp->tlv_data.router_id->id),
-                      sizeof(ipv4_address));
-               vty_out(vty, "  Router ID   : %s\n", ipv4_address);
-       }
-
-       if (lsp->tlv_data.ipv4_addrs)
-               for (ALL_LIST_ELEMENTS_RO(lsp->tlv_data.ipv4_addrs, lnode,
-                                         ipv4_addr)) {
-                       memcpy(ipv4_address, inet_ntoa(*ipv4_addr),
-                              sizeof(ipv4_address));
-                       vty_out(vty, "  IPv4 Address: %s\n", ipv4_address);
-               }
-
-       /* for the IS neighbor tlv */
-       if (lsp->tlv_data.is_neighs)
-               for (ALL_LIST_ELEMENTS_RO(lsp->tlv_data.is_neighs, lnode,
-                                         is_neigh)) {
-                       lspid_print(is_neigh->neigh_id, LSPid, dynhost, 0);
-                       vty_out(vty, "  Metric      : %-8" PRIu8
-                                    " IS            : %s\n",
-                               is_neigh->metrics.metric_default, LSPid);
-               }
-
-       /* for the internal reachable tlv */
-       if (lsp->tlv_data.ipv4_int_reachs)
-               for (ALL_LIST_ELEMENTS_RO(lsp->tlv_data.ipv4_int_reachs, lnode,
-                                         ipv4_reach)) {
-                       memcpy(ipv4_reach_prefix, inet_ntoa(ipv4_reach->prefix),
-                              sizeof(ipv4_reach_prefix));
-                       memcpy(ipv4_reach_mask, inet_ntoa(ipv4_reach->mask),
-                              sizeof(ipv4_reach_mask));
-                       vty_out(vty, "  Metric      : %-8" PRIu8
-                                    " IPv4-Internal : %s %s\n",
-                               ipv4_reach->metrics.metric_default,
-                               ipv4_reach_prefix, ipv4_reach_mask);
-               }
-
-       /* for the external reachable tlv */
-       if (lsp->tlv_data.ipv4_ext_reachs)
-               for (ALL_LIST_ELEMENTS_RO(lsp->tlv_data.ipv4_ext_reachs, lnode,
-                                         ipv4_reach)) {
-                       memcpy(ipv4_reach_prefix, inet_ntoa(ipv4_reach->prefix),
-                              sizeof(ipv4_reach_prefix));
-                       memcpy(ipv4_reach_mask, inet_ntoa(ipv4_reach->mask),
-                              sizeof(ipv4_reach_mask));
-                       vty_out(vty, "  Metric      : %-8" PRIu8
-                                    " IPv4-External : %s %s\n",
-                               ipv4_reach->metrics.metric_default,
-                               ipv4_reach_prefix, ipv4_reach_mask);
-               }
-
-       /* IPv6 tlv */
-       lsp_print_mt_ipv6_reach(lsp->tlv_data.ipv6_reachs, vty,
-                               ISIS_MT_IPV4_UNICAST);
-
-       /* MT IPv6 reachability tlv */
-       for (ALL_LIST_ELEMENTS_RO(lsp->tlv_data.mt_ipv6_reachs, lnode,
-                                 mt_ipv6_reachs))
-               lsp_print_mt_ipv6_reach(mt_ipv6_reachs->list, vty,
-                                       mt_ipv6_reachs->mtid);
-
-       /* TE IS neighbor tlv */
-       lsp_print_mt_reach(lsp->tlv_data.te_is_neighs, vty, dynhost,
-                          ISIS_MT_IPV4_UNICAST);
-
-       /* MT IS neighbor tlv */
-       for (ALL_LIST_ELEMENTS_RO(lsp->tlv_data.mt_is_neighs, lnode,
-                                 mt_is_neigh))
-               lsp_print_mt_reach(mt_is_neigh->list, vty, dynhost,
-                                  mt_is_neigh->mtid);
-
-       /* TE IPv4 tlv */
-       lsp_print_mt_ipv4_reach(lsp->tlv_data.te_ipv4_reachs, vty,
-                               ISIS_MT_IPV4_UNICAST);
-
-       /* MT IPv4 reachability tlv */
-       for (ALL_LIST_ELEMENTS_RO(lsp->tlv_data.mt_ipv4_reachs, lnode,
-                                 mt_ipv4_reachs))
-               lsp_print_mt_ipv4_reach(mt_ipv4_reachs->list, vty,
-                                       mt_ipv4_reachs->mtid);
-
+       if (lsp->tlvs)
+               vty_multiline(vty, "  ", "%s", isis_format_tlvs(lsp->tlvs));
        vty_out(vty, "\n");
-
-       return;
 }
 
 /* print all the lsps info in the local lspdb */
@@ -1083,85 +688,6 @@ int lsp_print_all(struct vty *vty, dict_t *lspdb, char detail, char dynhost)
        return lsp_count;
 }
 
-static void _lsp_tlv_fit(struct isis_lsp *lsp, struct list **from,
-                        struct list **to, int frag_thold,
-                        unsigned int tlv_build_func(struct list *,
-                                                    struct stream *,
-                                                    void *arg),
-                        void *arg)
-{
-       while (*from && listcount(*from)) {
-               unsigned int count;
-
-               count = tlv_build_func(*from, lsp->pdu, arg);
-
-               if (listcount(*to) != 0 || count != listcount(*from)) {
-                       struct listnode *node, *nnode;
-                       void *elem;
-
-                       for (ALL_LIST_ELEMENTS(*from, node, nnode, elem)) {
-                               if (!count)
-                                       break;
-                               listnode_add(*to, elem);
-                               list_delete_node(*from, node);
-                               --count;
-                       }
-               } else {
-                       list_free(*to);
-                       *to = *from;
-                       *from = NULL;
-               }
-       }
-}
-
-#define FRAG_THOLD(S, T) ((STREAM_SIZE(S) * T) / 100)
-
-/* stream*, area->lsp_frag_threshold, increment */
-#define FRAG_NEEDED(S, T, I)                                                   \
-       (STREAM_SIZE(S) - STREAM_REMAIN(S) + (I) > FRAG_THOLD(S, T))
-
-/* FIXME: It shouldn't be necessary to pass tlvsize here, TLVs can have
- * variable length (TE TLVs, sub TLVs). */
-static void lsp_tlv_fit(struct isis_lsp *lsp, struct list **from,
-                       struct list **to, int tlvsize, int frag_thold,
-                       int tlv_build_func(struct list *, struct stream *))
-{
-       int count, i;
-
-       /* can we fit all ? */
-       if (!FRAG_NEEDED(lsp->pdu, frag_thold,
-                        listcount(*from) * tlvsize + 2)) {
-               tlv_build_func(*from, lsp->pdu);
-               if (listcount(*to) != 0) {
-                       struct listnode *node, *nextnode;
-                       void *elem;
-
-                       for (ALL_LIST_ELEMENTS(*from, node, nextnode, elem)) {
-                               listnode_add(*to, elem);
-                               list_delete_node(*from, node);
-                       }
-               } else {
-                       list_free(*to);
-                       *to = *from;
-                       *from = NULL;
-               }
-       } else if (!FRAG_NEEDED(lsp->pdu, frag_thold, tlvsize + 2)) {
-               /* fit all we can */
-               count = FRAG_THOLD(lsp->pdu, frag_thold) - 2
-                       - (STREAM_SIZE(lsp->pdu) - STREAM_REMAIN(lsp->pdu));
-               count = count / tlvsize;
-               if (count > (int)listcount(*from))
-                       count = listcount(*from);
-               for (i = 0; i < count; i++) {
-                       listnode_add(*to, listgetdata(listhead(*from)));
-                       listnode_delete(*from, listgetdata(listhead(*from)));
-               }
-               tlv_build_func(*to, lsp->pdu);
-       }
-       lsp->lsp_header->pdu_len = htons(stream_get_endp(lsp->pdu));
-       return;
-}
-
 static u_int16_t lsp_rem_lifetime(struct isis_area *area, int level)
 {
        u_int16_t rem_lifetime;
@@ -1204,155 +730,90 @@ static u_int16_t lsp_refresh_time(struct isis_lsp *lsp, u_int16_t rem_lifetime)
        return refresh_time;
 }
 
-static struct isis_lsp *lsp_next_frag(u_char frag_num, struct isis_lsp *lsp0,
-                                     struct isis_area *area, int level)
-{
-       struct isis_lsp *lsp;
-       u_char frag_id[ISIS_SYS_ID_LEN + 2];
-
-       memcpy(frag_id, lsp0->lsp_header->lsp_id, ISIS_SYS_ID_LEN + 1);
-       LSP_FRAGMENT(frag_id) = frag_num;
-       /* FIXME add authentication TLV for fragment LSPs */
-       lsp = lsp_search(frag_id, area->lspdb[level - 1]);
-       if (lsp) {
-               /* Clear the TLVs */
-               lsp_clear_data(lsp);
-               return lsp;
-       }
-       lsp = lsp_new(area, frag_id, ntohs(lsp0->lsp_header->rem_lifetime), 0,
-                     lsp_bits_generate(level, area->overload_bit,
-                                       area->attached_bit),
-                     0, level);
-       lsp->area = area;
-       lsp->own_lsp = 1;
-       lsp_insert(lsp, area->lspdb[level - 1]);
-       listnode_add(lsp0->lspu.frags, lsp);
-       lsp->lspu.zero_lsp = lsp0;
-       return lsp;
-}
-
 static void lsp_build_ext_reach_ipv4(struct isis_lsp *lsp,
-                                    struct isis_area *area,
-                                    struct tlvs *tlv_data)
+                                    struct isis_area *area)
 {
-       struct route_table *er_table;
-       struct route_node *rn;
-       struct prefix_ipv4 *ipv4;
-       struct isis_ext_info *info;
-       struct ipv4_reachability *ipreach;
-       struct te_ipv4_reachability *te_ipreach;
-
-       er_table = get_ext_reach(area, AF_INET, lsp->level);
+       struct route_table *er_table = get_ext_reach(area, AF_INET, lsp->level);
        if (!er_table)
                return;
 
-       for (rn = route_top(er_table); rn; rn = route_next(rn)) {
+       for (struct route_node *rn = route_top(er_table); rn;
+            rn = route_next(rn)) {
                if (!rn->info)
                        continue;
 
-               ipv4 = (struct prefix_ipv4 *)&rn->p;
-               info = rn->info;
-               if (area->oldmetric) {
-                       if (tlv_data->ipv4_ext_reachs == NULL) {
-                               tlv_data->ipv4_ext_reachs = list_new();
-                               tlv_data->ipv4_ext_reachs->del = free_tlv;
-                       }
-                       ipreach = XMALLOC(MTYPE_ISIS_TLV, sizeof(*ipreach));
-
-                       ipreach->prefix.s_addr = ipv4->prefix.s_addr;
-                       masklen2ip(ipv4->prefixlen, &ipreach->mask);
-                       ipreach->prefix.s_addr &= ipreach->mask.s_addr;
-
-                       if ((info->metric & 0x3f) != info->metric)
-                               ipreach->metrics.metric_default = 0x3f;
-                       else
-                               ipreach->metrics.metric_default = info->metric;
-                       ipreach->metrics.metric_expense = METRICS_UNSUPPORTED;
-                       ipreach->metrics.metric_error = METRICS_UNSUPPORTED;
-                       ipreach->metrics.metric_delay = METRICS_UNSUPPORTED;
-                       listnode_add(tlv_data->ipv4_ext_reachs, ipreach);
-               }
-               if (area->newmetric) {
-                       if (tlv_data->te_ipv4_reachs == NULL) {
-                               tlv_data->te_ipv4_reachs = list_new();
-                               tlv_data->te_ipv4_reachs->del = free_tlv;
-                       }
-                       te_ipreach = XCALLOC(MTYPE_ISIS_TLV,
-                                            sizeof(*te_ipreach) - 1
-                                                    + PSIZE(ipv4->prefixlen));
-                       if (info->metric > MAX_WIDE_PATH_METRIC)
-                               te_ipreach->te_metric =
-                                       htonl(MAX_WIDE_PATH_METRIC);
-                       else
-                               te_ipreach->te_metric = htonl(info->metric);
-                       te_ipreach->control = ipv4->prefixlen & 0x3f;
-                       memcpy(&te_ipreach->prefix_start, &ipv4->prefix.s_addr,
-                              PSIZE(ipv4->prefixlen));
-                       listnode_add(tlv_data->te_ipv4_reachs, te_ipreach);
-               }
-       }
-}
+               struct prefix_ipv4 *ipv4 = (struct prefix_ipv4 *)&rn->p;
+               struct isis_ext_info *info = rn->info;
 
-static struct list *tlv_get_ipv6_reach_list(struct isis_area *area,
-                                           struct tlvs *tlv_data)
-{
-       uint16_t mtid = isis_area_ipv6_topology(area);
-       if (mtid == ISIS_MT_IPV4_UNICAST) {
-               if (!tlv_data->ipv6_reachs) {
-                       tlv_data->ipv6_reachs = list_new();
-                       tlv_data->ipv6_reachs->del = free_tlv;
-               }
-               return tlv_data->ipv6_reachs;
-       }
+               uint32_t metric = info->metric;
+               if (metric > MAX_WIDE_PATH_METRIC)
+                       metric = MAX_WIDE_PATH_METRIC;
+               if (area->oldmetric && metric > 0x3f)
+                       metric = 0x3f;
 
-       struct tlv_mt_ipv6_reachs *reachs =
-               tlvs_get_mt_ipv6_reachs(tlv_data, mtid);
-       return reachs->list;
+               if (area->oldmetric)
+                       isis_tlvs_add_oldstyle_ip_reach(lsp->tlvs, ipv4,
+                                                       metric);
+               if (area->newmetric)
+                       isis_tlvs_add_extended_ip_reach(lsp->tlvs, ipv4,
+                                                       metric);
+       }
 }
 
 static void lsp_build_ext_reach_ipv6(struct isis_lsp *lsp,
-                                    struct isis_area *area,
-                                    struct tlvs *tlv_data)
+                                    struct isis_area *area)
 {
-       struct route_table *er_table;
-       struct route_node *rn;
-       struct prefix_ipv6 *ipv6;
-       struct isis_ext_info *info;
-       struct ipv6_reachability *ip6reach;
-       struct list *reach_list = NULL;
-
-       er_table = get_ext_reach(area, AF_INET6, lsp->level);
+       struct route_table *er_table =
+               get_ext_reach(area, AF_INET6, lsp->level);
        if (!er_table)
                return;
 
-       for (rn = route_top(er_table); rn; rn = route_next(rn)) {
+       for (struct route_node *rn = route_top(er_table); rn;
+            rn = route_next(rn)) {
                if (!rn->info)
                        continue;
 
-               ipv6 = (struct prefix_ipv6 *)&rn->p;
-               info = rn->info;
-
-               if (!reach_list)
-                       reach_list = tlv_get_ipv6_reach_list(area, tlv_data);
+               struct prefix_ipv6 *ipv6 = (struct prefix_ipv6 *)&rn->p;
+               struct isis_ext_info *info = rn->info;
 
-               ip6reach = XCALLOC(MTYPE_ISIS_TLV, sizeof(*ip6reach));
+               uint32_t metric = info->metric;
                if (info->metric > MAX_WIDE_PATH_METRIC)
-                       ip6reach->metric = htonl(MAX_WIDE_PATH_METRIC);
-               else
-                       ip6reach->metric = htonl(info->metric);
-               ip6reach->control_info = DISTRIBUTION_EXTERNAL;
-               ip6reach->prefix_len = ipv6->prefixlen;
-               memcpy(ip6reach->prefix, ipv6->prefix.s6_addr,
-                      sizeof(ip6reach->prefix));
-               listnode_add(reach_list, ip6reach);
+                       metric = MAX_WIDE_PATH_METRIC;
+               isis_tlvs_add_ipv6_reach(
+                       lsp->tlvs, isis_area_ipv6_topology(area), ipv6, metric);
        }
 }
 
-static void lsp_build_ext_reach(struct isis_lsp *lsp, struct isis_area *area,
-                               struct tlvs *tlv_data)
+static void lsp_build_ext_reach(struct isis_lsp *lsp, struct isis_area *area)
 {
-       lsp_build_ext_reach_ipv4(lsp, area, tlv_data);
-       lsp_build_ext_reach_ipv6(lsp, area, tlv_data);
+       lsp_build_ext_reach_ipv4(lsp, area);
+       lsp_build_ext_reach_ipv6(lsp, area);
+}
+
+static struct isis_lsp *lsp_next_frag(uint8_t frag_num, struct isis_lsp *lsp0,
+                                     struct isis_area *area, int level)
+{
+       struct isis_lsp *lsp;
+       uint8_t frag_id[ISIS_SYS_ID_LEN + 2];
+
+       memcpy(frag_id, lsp0->hdr.lsp_id, ISIS_SYS_ID_LEN + 1);
+       LSP_FRAGMENT(frag_id) = frag_num;
+
+       lsp = lsp_search(frag_id, area->lspdb[level - 1]);
+       if (lsp) {
+               lsp_clear_data(lsp);
+               return lsp;
+       }
+
+       lsp = lsp_new(area, frag_id, lsp0->hdr.rem_lifetime, 0,
+                     lsp_bits_generate(level, area->overload_bit,
+                                       area->attached_bit),
+                     0, level);
+       lsp->own_lsp = 1;
+       lsp_insert(lsp, area->lspdb[level - 1]);
+       listnode_add(lsp0->lspu.frags, lsp);
+       lsp->lspu.zero_lsp = lsp0;
+       return lsp;
 }
 
 /*
@@ -1361,126 +822,69 @@ static void lsp_build_ext_reach(struct isis_lsp *lsp, struct isis_area *area,
  */
 static void lsp_build(struct isis_lsp *lsp, struct isis_area *area)
 {
-       struct is_neigh *is_neigh;
-       struct te_is_neigh *te_is_neigh;
-       struct listnode *node, *ipnode;
        int level = lsp->level;
-       struct isis_circuit *circuit;
-       struct prefix_ipv4 *ipv4;
-       struct ipv4_reachability *ipreach;
-       struct te_ipv4_reachability *te_ipreach;
-       struct isis_adjacency *nei;
-       struct prefix_ipv6 *ipv6, ip6prefix;
-       struct list *ipv6_reachs = NULL;
-       struct ipv6_reachability *ip6reach;
-       struct tlvs tlv_data;
-       struct isis_lsp *lsp0 = lsp;
-       struct in_addr *routerid;
-       uint32_t expected = 0, found = 0;
-       uint32_t metric;
-       u_char zero_id[ISIS_SYS_ID_LEN + 1];
-       int retval = ISIS_OK;
-       char buf[BUFSIZ];
+       char buf[PREFIX2STR_BUFFER];
+       struct listnode *node;
+       struct isis_lsp *frag;
+
+       lsp_clear_data(lsp);
+       for (ALL_LIST_ELEMENTS_RO(lsp->lspu.frags, node, frag))
+               lsp_clear_data(frag);
 
+       lsp->tlvs = isis_alloc_tlvs();
        lsp_debug("ISIS (%s): Constructing local system LSP for level %d",
                  area->area_tag, level);
 
-       /*
-        * Building the zero lsp
-        */
-       memset(zero_id, 0, ISIS_SYS_ID_LEN + 1);
-
-       /* Reset stream endp. Stream is always there and on every LSP refresh
-        * only
-        * TLV part of it is overwritten. So we must seek past header we will
-        * not
-        * touch. */
-       stream_reset(lsp->pdu);
-       stream_forward_endp(lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
-
-       /*
-        * Add the authentication info if its present
-        */
-       lsp_auth_add(lsp);
+       lsp->hdr.lsp_bits = lsp_bits_generate(level, area->overload_bit,
+                                             area->attached_bit);
 
-       /*
-        * First add the tlvs related to area
-        */
+       lsp_add_auth(lsp);
 
-       /* Area addresses */
-       if (lsp->tlv_data.area_addrs == NULL)
-               lsp->tlv_data.area_addrs = list_new();
-       list_add_list(lsp->tlv_data.area_addrs, area->area_addrs);
-       if (listcount(lsp->tlv_data.area_addrs) > 0)
-               tlv_add_area_addrs(lsp->tlv_data.area_addrs, lsp->pdu);
+       isis_tlvs_add_area_addresses(lsp->tlvs, area->area_addrs);
 
        /* Protocols Supported */
        if (area->ip_circuits > 0 || area->ipv6_circuits > 0) {
-               lsp->tlv_data.nlpids =
-                       XCALLOC(MTYPE_ISIS_TLV, sizeof(struct nlpids));
-               lsp->tlv_data.nlpids->count = 0;
+               struct nlpids nlpids = {.count = 0};
                if (area->ip_circuits > 0) {
                        lsp_debug(
                                "ISIS (%s): Found IPv4 circuit, adding IPv4 to NLPIDs",
                                area->area_tag);
-                       lsp->tlv_data.nlpids->count++;
-                       lsp->tlv_data.nlpids->nlpids[0] = NLPID_IP;
+                       nlpids.nlpids[nlpids.count] = NLPID_IP;
+                       nlpids.count++;
                }
                if (area->ipv6_circuits > 0) {
                        lsp_debug(
                                "ISIS (%s): Found IPv6 circuit, adding IPv6 to NLPIDs",
                                area->area_tag);
-                       lsp->tlv_data.nlpids->count++;
-                       lsp->tlv_data.nlpids
-                               ->nlpids[lsp->tlv_data.nlpids->count - 1] =
-                               NLPID_IPV6;
+                       nlpids.nlpids[nlpids.count] = NLPID_IPV6;
+                       nlpids.count++;
                }
-               tlv_add_nlpid(lsp->tlv_data.nlpids, lsp->pdu);
+               isis_tlvs_set_protocols_supported(lsp->tlvs, &nlpids);
        }
 
        if (area_is_mt(area)) {
                lsp_debug("ISIS (%s): Adding MT router tlv...", area->area_tag);
-               lsp->tlv_data.mt_router_info = list_new();
-               lsp->tlv_data.mt_router_info->del = free_tlv;
 
                struct isis_area_mt_setting **mt_settings;
                unsigned int mt_count;
 
                mt_settings = area_mt_settings(area, &mt_count);
                for (unsigned int i = 0; i < mt_count; i++) {
-                       struct mt_router_info *info;
-
-                       info = XCALLOC(MTYPE_ISIS_TLV, sizeof(*info));
-                       info->mtid = mt_settings[i]->mtid;
-                       info->overload = mt_settings[i]->overload;
-                       listnode_add(lsp->tlv_data.mt_router_info, info);
+                       isis_tlvs_add_mt_router_info(
+                               lsp->tlvs, mt_settings[i]->mtid,
+                               mt_settings[i]->overload, false);
                        lsp_debug("ISIS (%s):   MT %s", area->area_tag,
-                                 isis_mtid2str(info->mtid));
+                                 isis_mtid2str(mt_settings[i]->mtid));
                }
-               tlv_add_mt_router_info(lsp->tlv_data.mt_router_info, lsp->pdu);
        } else {
                lsp_debug("ISIS (%s): Not adding MT router tlv (disabled)",
                          area->area_tag);
        }
        /* Dynamic Hostname */
        if (area->dynhostname) {
-               const char *hostname = unix_hostname();
-               size_t hostname_len = strlen(hostname);
-
-               lsp->tlv_data.hostname =
-                       XMALLOC(MTYPE_ISIS_TLV, sizeof(struct hostname));
-
-               strncpy((char *)lsp->tlv_data.hostname->name, hostname,
-                       sizeof(lsp->tlv_data.hostname->name));
-               if (hostname_len <= MAX_TLV_LEN)
-                       lsp->tlv_data.hostname->namelen = hostname_len;
-               else
-                       lsp->tlv_data.hostname->namelen = MAX_TLV_LEN;
-
-               lsp_debug("ISIS (%s): Adding dynamic hostname '%.*s'",
-                         area->area_tag, lsp->tlv_data.hostname->namelen,
-                         lsp->tlv_data.hostname->name);
-               tlv_add_dynamic_hostname(lsp->tlv_data.hostname, lsp->pdu);
+               isis_tlvs_set_dynamic_hostname(lsp->tlvs, unix_hostname());
+               lsp_debug("ISIS (%s): Adding dynamic hostname '%s'",
+                         area->area_tag, unix_hostname());
        } else {
                lsp_debug("ISIS (%s): Not adding dynamic hostname (disabled)",
                          area->area_tag);
@@ -1491,45 +895,31 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area)
         * into
         * LSP and this address is same as router id. */
        if (isis->router_id != 0) {
-               inet_ntop(AF_INET, &isis->router_id, buf, sizeof(buf));
+               struct in_addr id = {.s_addr = isis->router_id};
+               inet_ntop(AF_INET, &id, buf, sizeof(buf));
                lsp_debug("ISIS (%s): Adding router ID %s as IPv4 tlv.",
                          area->area_tag, buf);
-               if (lsp->tlv_data.ipv4_addrs == NULL) {
-                       lsp->tlv_data.ipv4_addrs = list_new();
-                       lsp->tlv_data.ipv4_addrs->del = free_tlv;
-               }
-
-               routerid = XMALLOC(MTYPE_ISIS_TLV, sizeof(struct in_addr));
-               routerid->s_addr = isis->router_id;
-               listnode_add(lsp->tlv_data.ipv4_addrs, routerid);
-               tlv_add_in_addr(routerid, lsp->pdu, IPV4_ADDR);
+               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 (area->newmetric) {
+
                        lsp_debug(
                                "ISIS (%s): Adding router ID also as TE router ID tlv.",
                                area->area_tag);
-                       lsp->tlv_data.router_id =
-                               XMALLOC(MTYPE_ISIS_TLV, sizeof(struct in_addr));
-                       lsp->tlv_data.router_id->id.s_addr = isis->router_id;
-                       tlv_add_in_addr(&lsp->tlv_data.router_id->id, lsp->pdu,
-                                       TE_ROUTER_ID);
+                       isis_tlvs_set_te_router_id(lsp->tlvs, &id);
                }
        } else {
                lsp_debug("ISIS (%s): Router ID is unset. Not adding tlv.",
                          area->area_tag);
        }
 
-       memset(&tlv_data, 0, sizeof(struct tlvs));
-
        lsp_debug("ISIS (%s): Adding circuit specific information.",
                  area->area_tag);
 
-       /*
-        * Then build lists of tlvs related to circuits
-        */
+       struct isis_circuit *circuit;
        for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit)) {
                if (!circuit->interface)
                        lsp_debug(
@@ -1549,245 +939,94 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area)
                        continue;
                }
 
-               /*
-                * Add IPv4 internal reachability of this circuit
-                */
+               uint32_t metric = area->oldmetric
+                                         ? circuit->metric[level - 1]
+                                         : circuit->te_metric[level - 1];
+
                if (circuit->ip_router && circuit->ip_addrs
                    && circuit->ip_addrs->count > 0) {
                        lsp_debug(
                                "ISIS (%s): Circuit has IPv4 active, adding respective TLVs.",
                                area->area_tag);
-                       if (area->oldmetric) {
-                               if (tlv_data.ipv4_int_reachs == NULL) {
-                                       tlv_data.ipv4_int_reachs = list_new();
-                                       tlv_data.ipv4_int_reachs->del =
-                                               free_tlv;
-                               }
-                               for (ALL_LIST_ELEMENTS_RO(circuit->ip_addrs,
-                                                         ipnode, ipv4)) {
-                                       ipreach = XMALLOC(
-                                               MTYPE_ISIS_TLV,
-                                               sizeof(struct
-                                                      ipv4_reachability));
-                                       ipreach->metrics.metric_default =
-                                               circuit->metric[level - 1];
-                                       ipreach->metrics.metric_expense =
-                                               METRICS_UNSUPPORTED;
-                                       ipreach->metrics.metric_error =
-                                               METRICS_UNSUPPORTED;
-                                       ipreach->metrics.metric_delay =
-                                               METRICS_UNSUPPORTED;
-                                       masklen2ip(ipv4->prefixlen,
-                                                  &ipreach->mask);
-                                       ipreach->prefix.s_addr =
-                                               ((ipreach->mask.s_addr)
-                                                & (ipv4->prefix.s_addr));
-                                       inet_ntop(AF_INET,
-                                                 &ipreach->prefix.s_addr, buf,
-                                                 sizeof(buf));
+                       struct listnode *ipnode;
+                       struct prefix_ipv4 *ipv4;
+                       for (ALL_LIST_ELEMENTS_RO(circuit->ip_addrs, ipnode,
+                                                 ipv4)) {
+                               if (area->oldmetric) {
                                        lsp_debug(
-                                               "ISIS (%s): Adding old-style IP reachability for %s/%d",
-                                               area->area_tag, buf,
-                                               ipv4->prefixlen);
-                                       listnode_add(tlv_data.ipv4_int_reachs,
-                                                    ipreach);
-                               }
-                       }
-                       if (area->newmetric) {
-                               if (tlv_data.te_ipv4_reachs == NULL) {
-                                       tlv_data.te_ipv4_reachs = list_new();
-                                       tlv_data.te_ipv4_reachs->del = free_tlv;
+                                               "ISIS (%s): Adding old-style IP reachability for %s",
+                                               area->area_tag,
+                                               prefix2str(ipv4, buf,
+                                                          sizeof(buf)));
+                                       isis_tlvs_add_oldstyle_ip_reach(
+                                               lsp->tlvs, ipv4, metric);
                                }
-                               for (ALL_LIST_ELEMENTS_RO(circuit->ip_addrs,
-                                                         ipnode, ipv4)) {
-                                       /* FIXME All this assumes that we have
-                                        * no sub TLVs. */
-                                       te_ipreach = XCALLOC(
-                                               MTYPE_ISIS_TLV,
-                                               sizeof(struct
-                                                      te_ipv4_reachability)
-                                                       + ((ipv4->prefixlen + 7)
-                                                          / 8)
-                                                       - 1);
-
-                                       if (area->oldmetric)
-                                               te_ipreach->te_metric = htonl(
-                                                       circuit->metric[level
-                                                                       - 1]);
-                                       else
-                                               te_ipreach->te_metric = htonl(
-                                                       circuit->te_metric
-                                                               [level - 1]);
-
-                                       te_ipreach->control =
-                                               (ipv4->prefixlen & 0x3F);
-                                       memcpy(&te_ipreach->prefix_start,
-                                              &ipv4->prefix.s_addr,
-                                              (ipv4->prefixlen + 7) / 8);
-                                       inet_ntop(AF_INET, &ipv4->prefix.s_addr,
-                                                 buf, sizeof(buf));
+
+                               if (area->newmetric) {
                                        lsp_debug(
-                                               "ISIS (%s): Adding te-style IP reachability for %s/%d",
-                                               area->area_tag, buf,
-                                               ipv4->prefixlen);
-                                       listnode_add(tlv_data.te_ipv4_reachs,
-                                                    te_ipreach);
+                                               "ISIS (%s): Adding te-style IP reachability for %s",
+                                               area->area_tag,
+                                               prefix2str(ipv4, buf,
+                                                          sizeof(buf)));
+                                       isis_tlvs_add_extended_ip_reach(
+                                               lsp->tlvs, ipv4, metric);
                                }
                        }
                }
 
-               /*
-                * Add IPv6 reachability of this circuit
-                */
                if (circuit->ipv6_router && circuit->ipv6_non_link
                    && circuit->ipv6_non_link->count > 0) {
-                       if (!ipv6_reachs)
-                               ipv6_reachs = tlv_get_ipv6_reach_list(
-                                       area, &tlv_data);
-
+                       struct listnode *ipnode;
+                       struct prefix_ipv6 *ipv6;
                        for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_non_link,
                                                  ipnode, ipv6)) {
-                               ip6reach = XCALLOC(
-                                       MTYPE_ISIS_TLV,
-                                       sizeof(struct ipv6_reachability));
-
-                               if (area->oldmetric)
-                                       ip6reach->metric = htonl(
-                                               circuit->metric[level - 1]);
-                               else
-                                       ip6reach->metric = htonl(
-                                               circuit->te_metric[level - 1]);
-
-                               ip6reach->control_info = 0;
-                               ip6reach->prefix_len = ipv6->prefixlen;
-                               memcpy(&ip6prefix, ipv6, sizeof(ip6prefix));
-                               apply_mask_ipv6(&ip6prefix);
-
-                               inet_ntop(AF_INET6, &ip6prefix.prefix.s6_addr,
-                                         buf, sizeof(buf));
                                lsp_debug(
-                                       "ISIS (%s): Adding IPv6 reachability for %s/%d",
-                                       area->area_tag, buf, ipv6->prefixlen);
-
-                               memcpy(ip6reach->prefix,
-                                      ip6prefix.prefix.s6_addr,
-                                      sizeof(ip6reach->prefix));
-                               listnode_add(ipv6_reachs, ip6reach);
+                                       "ISIS (%s): Adding IPv6 reachability for %s",
+                                       area->area_tag,
+                                       prefix2str(ipv6, buf, sizeof(buf)));
+                               isis_tlvs_add_ipv6_reach(
+                                       lsp->tlvs,
+                                       isis_area_ipv6_topology(area), ipv6,
+                                       metric);
                        }
                }
 
                switch (circuit->circ_type) {
                case CIRCUIT_T_BROADCAST:
                        if (level & circuit->is_type) {
-                               if (area->oldmetric) {
-                                       if (tlv_data.is_neighs == NULL) {
-                                               tlv_data.is_neighs = list_new();
-                                               tlv_data.is_neighs->del =
-                                                       free_tlv;
-                                       }
-                                       is_neigh = XCALLOC(
-                                               MTYPE_ISIS_TLV,
-                                               sizeof(struct is_neigh));
-                                       if (level == IS_LEVEL_1)
-                                               memcpy(is_neigh->neigh_id,
-                                                      circuit->u.bc
-                                                              .l1_desig_is,
-                                                      ISIS_SYS_ID_LEN + 1);
-                                       else
-                                               memcpy(is_neigh->neigh_id,
-                                                      circuit->u.bc
-                                                              .l2_desig_is,
-                                                      ISIS_SYS_ID_LEN + 1);
-                                       is_neigh->metrics.metric_default =
-                                               circuit->metric[level - 1];
-                                       is_neigh->metrics.metric_expense =
-                                               METRICS_UNSUPPORTED;
-                                       is_neigh->metrics.metric_error =
-                                               METRICS_UNSUPPORTED;
-                                       is_neigh->metrics.metric_delay =
-                                               METRICS_UNSUPPORTED;
-                                       if (!memcmp(is_neigh->neigh_id, zero_id,
-                                                   ISIS_SYS_ID_LEN + 1)) {
-                                               XFREE(MTYPE_ISIS_TLV, is_neigh);
-                                               lsp_debug(
-                                                       "ISIS (%s): No DIS for circuit, not adding old-style IS neighbor.",
-                                                       area->area_tag);
-                                       } else {
-                                               listnode_add(tlv_data.is_neighs,
-                                                            is_neigh);
+                               uint8_t *ne_id =
+                                       (level == IS_LEVEL_1)
+                                               ? circuit->u.bc.l1_desig_is
+                                               : circuit->u.bc.l2_desig_is;
+
+                               if (LSP_PSEUDO_ID(ne_id)) {
+                                       if (area->oldmetric) {
                                                lsp_debug(
                                                        "ISIS (%s): Adding DIS %s.%02x as old-style neighbor",
                                                        area->area_tag,
-                                                       sysid_print(
-                                                               is_neigh->neigh_id),
-                                                       LSP_PSEUDO_ID(
-                                                               is_neigh->neigh_id));
+                                                       sysid_print(ne_id),
+                                                       LSP_PSEUDO_ID(ne_id));
+                                               isis_tlvs_add_oldstyle_reach(
+                                                       lsp->tlvs, ne_id,
+                                                       metric);
                                        }
-                               }
-                               if (area->newmetric) {
-                                       if (tlv_data.te_is_neighs == NULL) {
-                                               tlv_data.te_is_neighs =
-                                                       list_new();
-                                               tlv_data.te_is_neighs->del =
-                                                       free_tlv;
-                                       }
-                                       te_is_neigh = XCALLOC(
-                                               MTYPE_ISIS_TLV,
-                                               sizeof(struct te_is_neigh));
-                                       if (level == IS_LEVEL_1)
-                                               memcpy(te_is_neigh->neigh_id,
-                                                      circuit->u.bc
-                                                              .l1_desig_is,
-                                                      ISIS_SYS_ID_LEN + 1);
-                                       else
-                                               memcpy(te_is_neigh->neigh_id,
-                                                      circuit->u.bc
-                                                              .l2_desig_is,
-                                                      ISIS_SYS_ID_LEN + 1);
-                                       if (area->oldmetric)
-                                               metric = circuit->metric[level
-                                                                        - 1];
-                                       else
-                                               metric =
-                                                       circuit->te_metric[level
-                                                                          - 1];
-                                       SET_TE_METRIC(te_is_neigh, metric);
-                                       if (!memcmp(te_is_neigh->neigh_id,
-                                                   zero_id,
-                                                   ISIS_SYS_ID_LEN + 1)) {
-                                               XFREE(MTYPE_ISIS_TLV,
-                                                     te_is_neigh);
-                                               lsp_debug(
-                                                       "ISIS (%s): No DIS for circuit, not adding te-style IS neighbor.",
-                                                       area->area_tag);
-                                       } else {
-                                               /* Check if MPLS_TE is activate
-                                                */
+                                       if (area->newmetric) {
+                                               uint8_t subtlvs[256];
+                                               uint8_t subtlv_len;
+
                                                if (IS_MPLS_TE(isisMplsTE)
                                                    && HAS_LINK_PARAMS(
                                                               circuit->interface))
-                                                       /* Add SubTLVs & Adjust
-                                                        * real size of SubTLVs
-                                                        */
-                                                       te_is_neigh
-                                                               ->sub_tlvs_length = add_te_subtlvs(
-                                                               te_is_neigh
-                                                                       ->sub_tlvs,
+                                                       subtlv_len = add_te_subtlvs(
+                                                               subtlvs,
                                                                circuit->mtc);
                                                else
-                                                       /* Or keep only TE
-                                                        * metric with no
-                                                        * SubTLVs if MPLS_TE is
-                                                        * off */
-                                                       te_is_neigh
-                                                               ->sub_tlvs_length =
-                                                               0;
+                                                       subtlv_len = 0;
 
                                                tlvs_add_mt_bcast(
-                                                       &tlv_data, circuit,
-                                                       level, te_is_neigh);
-                                               XFREE(MTYPE_ISIS_TLV,
-                                                     te_is_neigh);
+                                                       lsp->tlvs, circuit,
+                                                       level, ne_id, metric,
+                                                       subtlvs, subtlv_len);
                                        }
                                }
                        } else {
@@ -1796,53 +1035,25 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area)
                                        area->area_tag);
                        }
                        break;
-               case CIRCUIT_T_P2P:
-                       nei = circuit->u.p2p.neighbor;
+               case CIRCUIT_T_P2P: {
+                       struct isis_adjacency *nei = circuit->u.p2p.neighbor;
                        if (nei && (level & nei->circuit_t)) {
+                               uint8_t ne_id[7];
+                               memcpy(ne_id, nei->sysid, ISIS_SYS_ID_LEN);
+                               LSP_PSEUDO_ID(ne_id) = 0;
+
                                if (area->oldmetric) {
-                                       if (tlv_data.is_neighs == NULL) {
-                                               tlv_data.is_neighs = list_new();
-                                               tlv_data.is_neighs->del =
-                                                       free_tlv;
-                                       }
-                                       is_neigh = XCALLOC(
-                                               MTYPE_ISIS_TLV,
-                                               sizeof(struct is_neigh));
-                                       memcpy(is_neigh->neigh_id, nei->sysid,
-                                              ISIS_SYS_ID_LEN);
-                                       is_neigh->metrics.metric_default =
-                                               circuit->metric[level - 1];
-                                       is_neigh->metrics.metric_expense =
-                                               METRICS_UNSUPPORTED;
-                                       is_neigh->metrics.metric_error =
-                                               METRICS_UNSUPPORTED;
-                                       is_neigh->metrics.metric_delay =
-                                               METRICS_UNSUPPORTED;
-                                       listnode_add(tlv_data.is_neighs,
-                                                    is_neigh);
                                        lsp_debug(
                                                "ISIS (%s): Adding old-style is reach for %s",
                                                area->area_tag,
-                                               sysid_print(
-                                                       is_neigh->neigh_id));
+                                               sysid_print(ne_id));
+                                       isis_tlvs_add_oldstyle_reach(
+                                               lsp->tlvs, ne_id, metric);
                                }
                                if (area->newmetric) {
-                                       uint32_t metric;
+                                       uint8_t subtlvs[256];
+                                       uint8_t subtlv_len;
 
-                                       if (tlv_data.te_is_neighs == NULL) {
-                                               tlv_data.te_is_neighs =
-                                                       list_new();
-                                               tlv_data.te_is_neighs->del =
-                                                       free_tlv;
-                                       }
-                                       te_is_neigh = XCALLOC(
-                                               MTYPE_ISIS_TLV,
-                                               sizeof(struct te_is_neigh));
-                                       memcpy(te_is_neigh->neigh_id,
-                                              nei->sysid, ISIS_SYS_ID_LEN);
-                                       metric = circuit->te_metric[level - 1];
-                                       SET_TE_METRIC(te_is_neigh, metric);
-                                       /* Check if MPLS_TE is activate */
                                        if (IS_MPLS_TE(isisMplsTE)
                                            && HAS_LINK_PARAMS(
                                                       circuit->interface))
@@ -1861,28 +1072,24 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area)
 
                                                /* Add SubTLVs & Adjust real
                                                 * size of SubTLVs */
-                                               te_is_neigh->sub_tlvs_length =
-                                                       add_te_subtlvs(
-                                                               te_is_neigh
-                                                                       ->sub_tlvs,
-                                                               circuit->mtc);
+                                               subtlv_len = add_te_subtlvs(
+                                                       subtlvs, circuit->mtc);
                                        else
                                                /* Or keep only TE metric with
                                                 * no SubTLVs if MPLS_TE is off
                                                 */
-                                               te_is_neigh->sub_tlvs_length =
-                                                       0;
+                                               subtlv_len = 0;
 
-                                       tlvs_add_mt_p2p(&tlv_data, circuit,
-                                                       te_is_neigh);
-                                       XFREE(MTYPE_ISIS_TLV, te_is_neigh);
+                                       tlvs_add_mt_p2p(lsp->tlvs, circuit,
+                                                       ne_id, metric, subtlvs,
+                                                       subtlv_len);
                                }
                        } else {
                                lsp_debug(
                                        "ISIS (%s): No adjacency for given level on this circuit. Not adding IS neighbors",
                                        area->area_tag);
                        }
-                       break;
+               } break;
                case CIRCUIT_T_LOOPBACK:
                        break;
                default:
@@ -1890,169 +1097,36 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area)
                }
        }
 
-       lsp_build_ext_reach(lsp, area, &tlv_data);
-
-       lsp_debug("ISIS (%s): LSP construction is complete. Serializing...",
-                 area->area_tag);
-
-       while (tlv_data.ipv4_int_reachs
-              && listcount(tlv_data.ipv4_int_reachs)) {
-               if (lsp->tlv_data.ipv4_int_reachs == NULL)
-                       lsp->tlv_data.ipv4_int_reachs = list_new();
-               lsp_tlv_fit(lsp, &tlv_data.ipv4_int_reachs,
-                           &lsp->tlv_data.ipv4_int_reachs, IPV4_REACH_LEN,
-                           area->lsp_frag_threshold, tlv_add_ipv4_int_reachs);
-               if (tlv_data.ipv4_int_reachs
-                   && listcount(tlv_data.ipv4_int_reachs))
-                       lsp = lsp_next_frag(
-                               LSP_FRAGMENT(lsp->lsp_header->lsp_id) + 1, lsp0,
-                               area, level);
-       }
-
-       while (tlv_data.ipv4_ext_reachs
-              && listcount(tlv_data.ipv4_ext_reachs)) {
-               if (lsp->tlv_data.ipv4_ext_reachs == NULL)
-                       lsp->tlv_data.ipv4_ext_reachs = list_new();
-               lsp_tlv_fit(lsp, &tlv_data.ipv4_ext_reachs,
-                           &lsp->tlv_data.ipv4_ext_reachs, IPV4_REACH_LEN,
-                           area->lsp_frag_threshold, tlv_add_ipv4_ext_reachs);
-               if (tlv_data.ipv4_ext_reachs
-                   && listcount(tlv_data.ipv4_ext_reachs))
-                       lsp = lsp_next_frag(
-                               LSP_FRAGMENT(lsp->lsp_header->lsp_id) + 1, lsp0,
-                               area, level);
-       }
-
-       while (tlv_data.te_ipv4_reachs && listcount(tlv_data.te_ipv4_reachs)) {
-               if (lsp->tlv_data.te_ipv4_reachs == NULL)
-                       lsp->tlv_data.te_ipv4_reachs = list_new();
-               _lsp_tlv_fit(lsp, &tlv_data.te_ipv4_reachs,
-                            &lsp->tlv_data.te_ipv4_reachs,
-                            area->lsp_frag_threshold, tlv_add_te_ipv4_reachs,
-                            NULL);
-               if (tlv_data.te_ipv4_reachs
-                   && listcount(tlv_data.te_ipv4_reachs))
-                       lsp = lsp_next_frag(
-                               LSP_FRAGMENT(lsp->lsp_header->lsp_id) + 1, lsp0,
-                               area, level);
-       }
+       lsp_build_ext_reach(lsp, area);
 
-       struct tlv_mt_ipv4_reachs *mt_ipv4_reachs;
-       for (ALL_LIST_ELEMENTS_RO(tlv_data.mt_ipv4_reachs, node,
-                                 mt_ipv4_reachs)) {
-               while (mt_ipv4_reachs->list
-                      && listcount(mt_ipv4_reachs->list)) {
-                       struct tlv_mt_ipv4_reachs *frag_mt_ipv4_reachs;
-
-                       frag_mt_ipv4_reachs = tlvs_get_mt_ipv4_reachs(
-                               &lsp->tlv_data, mt_ipv4_reachs->mtid);
-                       _lsp_tlv_fit(lsp, &mt_ipv4_reachs->list,
-                                    &frag_mt_ipv4_reachs->list,
-                                    area->lsp_frag_threshold,
-                                    tlv_add_te_ipv4_reachs,
-                                    &mt_ipv4_reachs->mtid);
-                       if (mt_ipv4_reachs->list
-                           && listcount(mt_ipv4_reachs->list))
-                               lsp = lsp_next_frag(
-                                       LSP_FRAGMENT(lsp->lsp_header->lsp_id)
-                                               + 1,
-                                       lsp0, area, level);
-               }
-       }
+       struct isis_tlvs *tlvs = lsp->tlvs;
+       lsp->tlvs = NULL;
 
-       while (tlv_data.ipv6_reachs && listcount(tlv_data.ipv6_reachs)) {
-               if (lsp->tlv_data.ipv6_reachs == NULL)
-                       lsp->tlv_data.ipv6_reachs = list_new();
-               _lsp_tlv_fit(
-                       lsp, &tlv_data.ipv6_reachs, &lsp->tlv_data.ipv6_reachs,
-                       area->lsp_frag_threshold, tlv_add_ipv6_reachs, NULL);
-               if (tlv_data.ipv6_reachs && listcount(tlv_data.ipv6_reachs))
-                       lsp = lsp_next_frag(
-                               LSP_FRAGMENT(lsp->lsp_header->lsp_id) + 1, lsp0,
-                               area, level);
-       }
-
-       struct tlv_mt_ipv6_reachs *mt_ipv6_reachs;
-       for (ALL_LIST_ELEMENTS_RO(tlv_data.mt_ipv6_reachs, node,
-                                 mt_ipv6_reachs)) {
-               while (mt_ipv6_reachs->list
-                      && listcount(mt_ipv6_reachs->list)) {
-                       struct tlv_mt_ipv6_reachs *frag_mt_ipv6_reachs;
-
-                       frag_mt_ipv6_reachs = tlvs_get_mt_ipv6_reachs(
-                               &lsp->tlv_data, mt_ipv6_reachs->mtid);
-                       _lsp_tlv_fit(lsp, &mt_ipv6_reachs->list,
-                                    &frag_mt_ipv6_reachs->list,
-                                    area->lsp_frag_threshold,
-                                    tlv_add_ipv6_reachs,
-                                    &mt_ipv6_reachs->mtid);
-                       if (mt_ipv6_reachs->list
-                           && listcount(mt_ipv6_reachs->list))
-                               lsp = lsp_next_frag(
-                                       LSP_FRAGMENT(lsp->lsp_header->lsp_id)
-                                               + 1,
-                                       lsp0, area, level);
-               }
-       }
-
-       while (tlv_data.is_neighs && listcount(tlv_data.is_neighs)) {
-               if (lsp->tlv_data.is_neighs == NULL)
-                       lsp->tlv_data.is_neighs = list_new();
-               lsp_tlv_fit(lsp, &tlv_data.is_neighs, &lsp->tlv_data.is_neighs,
-                           IS_NEIGHBOURS_LEN, area->lsp_frag_threshold,
-                           tlv_add_is_neighs);
-               if (tlv_data.is_neighs && listcount(tlv_data.is_neighs))
-                       lsp = lsp_next_frag(
-                               LSP_FRAGMENT(lsp->lsp_header->lsp_id) + 1, lsp0,
-                               area, level);
-       }
+       lsp_pack_pdu(lsp);
+       size_t tlv_space = STREAM_WRITEABLE(lsp->pdu) - LLC_LEN;
+       lsp_clear_data(lsp);
 
-       while (tlv_data.te_is_neighs && listcount(tlv_data.te_is_neighs)) {
-               if (lsp->tlv_data.te_is_neighs == NULL)
-                       lsp->tlv_data.te_is_neighs = list_new();
-               _lsp_tlv_fit(lsp, &tlv_data.te_is_neighs,
-                            &lsp->tlv_data.te_is_neighs,
-                            area->lsp_frag_threshold, tlv_add_te_is_neighs,
-                            NULL);
-               if (tlv_data.te_is_neighs && listcount(tlv_data.te_is_neighs))
-                       lsp = lsp_next_frag(
-                               LSP_FRAGMENT(lsp->lsp_header->lsp_id) + 1, lsp0,
-                               area, level);
+       struct list *fragments = isis_fragment_tlvs(tlvs, tlv_space);
+       if (!fragments) {
+               zlog_warn("BUG: could not fragment own LSP:");
+               log_multiline(LOG_WARNING, "    ", "%s", isis_format_tlvs(tlvs));
+               isis_free_tlvs(tlvs);
+               return;
        }
+       isis_free_tlvs(tlvs);
 
-       struct tlv_mt_neighbors *mt_neighs;
-       for (ALL_LIST_ELEMENTS_RO(tlv_data.mt_is_neighs, node, mt_neighs)) {
-               while (mt_neighs->list && listcount(mt_neighs->list)) {
-                       struct tlv_mt_neighbors *frag_mt_neighs;
-
-                       frag_mt_neighs = tlvs_get_mt_neighbors(&lsp->tlv_data,
-                                                              mt_neighs->mtid);
-                       _lsp_tlv_fit(lsp, &mt_neighs->list,
-                                    &frag_mt_neighs->list,
-                                    area->lsp_frag_threshold,
-                                    tlv_add_te_is_neighs, &mt_neighs->mtid);
-                       if (mt_neighs->list && listcount(mt_neighs->list))
-                               lsp = lsp_next_frag(
-                                       LSP_FRAGMENT(lsp->lsp_header->lsp_id)
-                                               + 1,
-                                       lsp0, area, level);
+       frag = lsp;
+       for (ALL_LIST_ELEMENTS_RO(fragments, node, tlvs)) {
+               if (node != listhead(fragments)) {
+                       frag = lsp_next_frag(LSP_FRAGMENT(frag->hdr.lsp_id) + 1,
+                                            lsp, area, level);
                }
+               frag->tlvs = tlvs;
        }
 
-
-       lsp->lsp_header->pdu_len = htons(stream_get_endp(lsp->pdu));
-
-       free_tlvs(&tlv_data);
-
-       /* Validate the LSP */
-       retval = parse_tlvs(area->area_tag,
-                           STREAM_DATA(lsp->pdu) + ISIS_FIXED_HDR_LEN
-                                   + ISIS_LSP_HDR_LEN,
-                           stream_get_endp(lsp->pdu) - ISIS_FIXED_HDR_LEN
-                                   - ISIS_LSP_HDR_LEN,
-                           &expected, &found, &tlv_data, NULL);
-       assert(retval == ISIS_OK);
-
+       list_delete(fragments);
+       lsp_debug("ISIS (%s): LSP construction is complete. Serializing...",
+                 area->area_tag);
        return;
 }
 
@@ -2076,8 +1150,8 @@ int lsp_generate(struct isis_area *area, int level)
        oldlsp = lsp_search(lspid, area->lspdb[level - 1]);
        if (oldlsp) {
                /* FIXME: we should actually initiate a purge */
-               seq_num = ntohl(oldlsp->lsp_header->seq_num);
-               lsp_search_and_destroy(oldlsp->lsp_header->lsp_id,
+               seq_num = oldlsp->hdr.seqno;
+               lsp_search_and_destroy(oldlsp->hdr.lsp_id,
                                       area->lspdb[level - 1]);
        }
        rem_lifetime = lsp_rem_lifetime(area, level);
@@ -2092,7 +1166,7 @@ int lsp_generate(struct isis_area *area, int level)
        /* build_lsp_data (newlsp, area); */
        lsp_build(newlsp, area);
        /* time to calculate our checksum */
-       lsp_seqnum_update(newlsp);
+       lsp_seqno_update(newlsp);
        newlsp->last_generated = time(NULL);
        lsp_set_all_srmflags(newlsp);
 
@@ -2108,15 +1182,14 @@ int lsp_generate(struct isis_area *area, int level)
                                 &area->t_lsp_refresh[level - 1]);
 
        if (isis->debugs & DEBUG_UPDATE_PACKETS) {
-               zlog_debug(
-                       "ISIS-Upd (%s): Building L%d LSP %s, len %d, "
-                       "seq 0x%08x, cksum 0x%04x, lifetime %us refresh %us",
-                       area->area_tag, level,
-                       rawlspid_print(newlsp->lsp_header->lsp_id),
-                       ntohl(newlsp->lsp_header->pdu_len),
-                       ntohl(newlsp->lsp_header->seq_num),
-                       ntohs(newlsp->lsp_header->checksum),
-                       ntohs(newlsp->lsp_header->rem_lifetime), refresh_time);
+               zlog_debug("ISIS-Upd (%s): Building L%d LSP %s, len %" PRIu16
+                          ", seq 0x%08" PRIx32 ", cksum 0x%04" PRIx16
+                          ", lifetime %" PRIu16 "s refresh %" PRIu16 "s",
+                          area->area_tag, level,
+                          rawlspid_print(newlsp->hdr.lsp_id),
+                          newlsp->hdr.pdu_len, newlsp->hdr.seqno,
+                          newlsp->hdr.checksum, newlsp->hdr.rem_lifetime,
+                          refresh_time);
        }
        sched_debug(
                "ISIS (%s): Built L%d LSP. Set triggered regenerate to non-pending.",
@@ -2154,24 +1227,21 @@ static int lsp_regenerate(struct isis_area *area, int level)
 
        lsp_clear_data(lsp);
        lsp_build(lsp, area);
-       lsp->lsp_header->lsp_bits = lsp_bits_generate(level, area->overload_bit,
-                                                     area->attached_bit);
        rem_lifetime = lsp_rem_lifetime(area, level);
-       lsp->lsp_header->rem_lifetime = htons(rem_lifetime);
-       lsp_seqnum_update(lsp);
-
+       lsp->hdr.rem_lifetime = rem_lifetime;
        lsp->last_generated = time(NULL);
        lsp_set_all_srmflags(lsp);
        for (ALL_LIST_ELEMENTS_RO(lsp->lspu.frags, node, frag)) {
-               frag->lsp_header->lsp_bits = lsp_bits_generate(
+               frag->hdr.lsp_bits = lsp_bits_generate(
                        level, area->overload_bit, area->attached_bit);
                /* Set the lifetime values of all the fragments to the same
                 * value,
                 * so that no fragment expires before the lsp is refreshed.
                 */
-               frag->lsp_header->rem_lifetime = htons(rem_lifetime);
+               frag->hdr.rem_lifetime = rem_lifetime;
                lsp_set_all_srmflags(frag);
        }
+       lsp_seqno_update(lsp);
 
        refresh_time = lsp_refresh_time(lsp, rem_lifetime);
        if (level == IS_LEVEL_1)
@@ -2184,14 +1254,12 @@ static int lsp_regenerate(struct isis_area *area, int level)
 
        if (isis->debugs & DEBUG_UPDATE_PACKETS) {
                zlog_debug(
-                       "ISIS-Upd (%s): Refreshing our L%d LSP %s, len %d, "
-                       "seq 0x%08x, cksum 0x%04x, lifetime %us refresh %us",
-                       area->area_tag, level,
-                       rawlspid_print(lsp->lsp_header->lsp_id),
-                       ntohl(lsp->lsp_header->pdu_len),
-                       ntohl(lsp->lsp_header->seq_num),
-                       ntohs(lsp->lsp_header->checksum),
-                       ntohs(lsp->lsp_header->rem_lifetime), refresh_time);
+                       "ISIS-Upd (%s): Refreshed our L%d LSP %s, len %" PRIu16
+                       ", seq 0x%08" PRIx32 ", cksum 0x%04" PRIx16
+                       ", lifetime %" PRIu16 "s refresh %" PRIu16 "s",
+                       area->area_tag, level, rawlspid_print(lsp->hdr.lsp_id),
+                       lsp->hdr.pdu_len, lsp->hdr.seqno, lsp->hdr.checksum,
+                       lsp->hdr.rem_lifetime, refresh_time);
        }
        sched_debug(
                "ISIS (%s): Rebuilt L%d LSP. Set triggered regenerate to non-pending.",
@@ -2351,164 +1419,89 @@ static void lsp_build_pseudo(struct isis_lsp *lsp, struct isis_circuit *circuit,
                             int level)
 {
        struct isis_adjacency *adj;
-       struct is_neigh *is_neigh;
-       struct te_is_neigh *te_is_neigh;
-       struct es_neigh *es_neigh;
        struct list *adj_list;
        struct listnode *node;
        struct isis_area *area = circuit->area;
 
+       lsp_clear_data(lsp);
+       lsp->tlvs = isis_alloc_tlvs();
        lsp_debug(
                "ISIS (%s): Constructing pseudo LSP %s for interface %s level %d",
-               area->area_tag, rawlspid_print(lsp->lsp_header->lsp_id),
+               area->area_tag, rawlspid_print(lsp->hdr.lsp_id),
                circuit->interface->name, level);
 
        lsp->level = level;
        /* RFC3787  section 4 SHOULD not set overload bit in pseudo LSPs */
-       lsp->lsp_header->lsp_bits =
+       lsp->hdr.lsp_bits =
                lsp_bits_generate(level, 0, circuit->area->attached_bit);
 
        /*
         * add self to IS neighbours
         */
-       if (circuit->area->oldmetric) {
-               if (lsp->tlv_data.is_neighs == NULL) {
-                       lsp->tlv_data.is_neighs = list_new();
-                       lsp->tlv_data.is_neighs->del = free_tlv;
-               }
-               is_neigh = XCALLOC(MTYPE_ISIS_TLV, sizeof(struct is_neigh));
+       uint8_t ne_id[ISIS_SYS_ID_LEN + 1];
 
-               memcpy(&is_neigh->neigh_id, isis->sysid, ISIS_SYS_ID_LEN);
-               listnode_add(lsp->tlv_data.is_neighs, is_neigh);
+       memcpy(ne_id, isis->sysid, ISIS_SYS_ID_LEN);
+       LSP_PSEUDO_ID(ne_id) = 0;
+
+       if (circuit->area->oldmetric) {
+               isis_tlvs_add_oldstyle_reach(lsp->tlvs, ne_id, 0);
                lsp_debug(
                        "ISIS (%s): Adding %s.%02x as old-style neighbor (self)",
-                       area->area_tag, sysid_print(is_neigh->neigh_id),
-                       LSP_PSEUDO_ID(is_neigh->neigh_id));
+                       area->area_tag, sysid_print(ne_id),
+                       LSP_PSEUDO_ID(ne_id));
        }
        if (circuit->area->newmetric) {
-               if (lsp->tlv_data.te_is_neighs == NULL) {
-                       lsp->tlv_data.te_is_neighs = list_new();
-                       lsp->tlv_data.te_is_neighs->del = free_tlv;
-               }
-               te_is_neigh =
-                       XCALLOC(MTYPE_ISIS_TLV, sizeof(struct te_is_neigh));
-
-               memcpy(&te_is_neigh->neigh_id, isis->sysid, ISIS_SYS_ID_LEN);
-               listnode_add(lsp->tlv_data.te_is_neighs, te_is_neigh);
+               isis_tlvs_add_extended_reach(lsp->tlvs, ISIS_MT_IPV4_UNICAST,
+                                            ne_id, 0, NULL, 0);
                lsp_debug(
                        "ISIS (%s): Adding %s.%02x as te-style neighbor (self)",
-                       area->area_tag, sysid_print(te_is_neigh->neigh_id),
-                       LSP_PSEUDO_ID(te_is_neigh->neigh_id));
+                       area->area_tag, sysid_print(ne_id),
+                       LSP_PSEUDO_ID(ne_id));
        }
 
        adj_list = list_new();
        isis_adj_build_up_list(circuit->u.bc.adjdb[level - 1], adj_list);
 
        for (ALL_LIST_ELEMENTS_RO(adj_list, node, adj)) {
-               if (adj->level & level) {
-                       if ((level == IS_LEVEL_1
-                            && adj->sys_type == ISIS_SYSTYPE_L1_IS)
-                           || (level == IS_LEVEL_1
-                               && adj->sys_type == ISIS_SYSTYPE_L2_IS
-                               && adj->adj_usage == ISIS_ADJ_LEVEL1AND2)
-                           || (level == IS_LEVEL_2
-                               && adj->sys_type == ISIS_SYSTYPE_L2_IS)) {
-                               /* an IS neighbour -> add it */
-                               if (circuit->area->oldmetric) {
-                                       is_neigh = XCALLOC(
-                                               MTYPE_ISIS_TLV,
-                                               sizeof(struct is_neigh));
-
-                                       memcpy(&is_neigh->neigh_id, adj->sysid,
-                                              ISIS_SYS_ID_LEN);
-                                       listnode_add(lsp->tlv_data.is_neighs,
-                                                    is_neigh);
-                                       lsp_debug(
-                                               "ISIS (%s): Adding %s.%02x as old-style neighbor (peer)",
-                                               area->area_tag,
-                                               sysid_print(is_neigh->neigh_id),
-                                               LSP_PSEUDO_ID(
-                                                       is_neigh->neigh_id));
-                               }
-                               if (circuit->area->newmetric) {
-                                       te_is_neigh = XCALLOC(
-                                               MTYPE_ISIS_TLV,
-                                               sizeof(struct te_is_neigh));
-                                       memcpy(&te_is_neigh->neigh_id,
-                                              adj->sysid, ISIS_SYS_ID_LEN);
-                                       listnode_add(lsp->tlv_data.te_is_neighs,
-                                                    te_is_neigh);
-                                       lsp_debug(
-                                               "ISIS (%s): Adding %s.%02x as te-style neighbor (peer)",
-                                               area->area_tag,
-                                               sysid_print(
-                                                       te_is_neigh->neigh_id),
-                                               LSP_PSEUDO_ID(
-                                                       te_is_neigh->neigh_id));
-                               }
-                       } else if (level == IS_LEVEL_1
-                                  && adj->sys_type == ISIS_SYSTYPE_ES) {
-                               /* an ES neigbour add it, if we are building
-                                * level 1 LSP */
-                               /* FIXME: the tlv-format is hard to use here */
-                               if (lsp->tlv_data.es_neighs == NULL) {
-                                       lsp->tlv_data.es_neighs = list_new();
-                                       lsp->tlv_data.es_neighs->del = free_tlv;
-                               }
-                               es_neigh = XCALLOC(MTYPE_ISIS_TLV,
-                                                  sizeof(struct es_neigh));
-
-                               memcpy(&es_neigh->first_es_neigh, adj->sysid,
-                                      ISIS_SYS_ID_LEN);
-                               listnode_add(lsp->tlv_data.es_neighs, es_neigh);
-                               lsp_debug(
-                                       "ISIS (%s): Adding %s as ES neighbor (peer)",
-                                       area->area_tag,
-                                       sysid_print(es_neigh->first_es_neigh));
-                       } else {
-                               lsp_debug(
-                                       "ISIS (%s): Ignoring neighbor %s, level does not match",
-                                       area->area_tag,
-                                       sysid_print(adj->sysid));
-                       }
-               } else {
+               if (!(adj->level & level)) {
                        lsp_debug(
                                "ISIS (%s): Ignoring neighbor %s, level does not intersect",
                                area->area_tag, sysid_print(adj->sysid));
+                       continue;
                }
-       }
-       list_delete(adj_list);
-
-       lsp_debug("ISIS (%s): Pseudo LSP construction is complete.",
-                 area->area_tag);
-
-       /* Reset endp of stream to overwrite only TLV part of it. */
-       stream_reset(lsp->pdu);
-       stream_forward_endp(lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
-
-       /*
-        * Add the authentication info if it's present
-        */
-       lsp_auth_add(lsp);
-
-       if (lsp->tlv_data.is_neighs && listcount(lsp->tlv_data.is_neighs) > 0)
-               tlv_add_is_neighs(lsp->tlv_data.is_neighs, lsp->pdu);
 
-       if (lsp->tlv_data.te_is_neighs
-           && listcount(lsp->tlv_data.te_is_neighs) > 0)
-               tlv_add_te_is_neighs(lsp->tlv_data.te_is_neighs, lsp->pdu,
-                                    NULL);
-
-       if (lsp->tlv_data.es_neighs && listcount(lsp->tlv_data.es_neighs) > 0)
-               tlv_add_is_neighs(lsp->tlv_data.es_neighs, lsp->pdu);
-
-       lsp->lsp_header->pdu_len = htons(stream_get_endp(lsp->pdu));
-
-       /* Recompute authentication and checksum information */
-       lsp_auth_update(lsp);
-       fletcher_checksum(STREAM_DATA(lsp->pdu) + 12,
-                         ntohs(lsp->lsp_header->pdu_len) - 12, 12);
+               if (!(level == IS_LEVEL_1
+                     && adj->sys_type == ISIS_SYSTYPE_L1_IS)
+                   && !(level == IS_LEVEL_1
+                        && adj->sys_type == ISIS_SYSTYPE_L2_IS
+                        && adj->adj_usage == ISIS_ADJ_LEVEL1AND2)
+                   && !(level == IS_LEVEL_2
+                        && adj->sys_type == ISIS_SYSTYPE_L2_IS)) {
+                       lsp_debug(
+                               "ISIS (%s): Ignoring neighbor %s, level does not match",
+                               area->area_tag, sysid_print(adj->sysid));
+                       continue;
+               }
 
+               memcpy(ne_id, adj->sysid, ISIS_SYS_ID_LEN);
+               if (circuit->area->oldmetric) {
+                       isis_tlvs_add_oldstyle_reach(lsp->tlvs, ne_id, 0);
+                       lsp_debug(
+                               "ISIS (%s): Adding %s.%02x as old-style neighbor (peer)",
+                               area->area_tag, sysid_print(ne_id),
+                               LSP_PSEUDO_ID(ne_id));
+               }
+               if (circuit->area->newmetric) {
+                       isis_tlvs_add_extended_reach(lsp->tlvs,
+                                                    ISIS_MT_IPV4_UNICAST,
+                                                    ne_id, 0, NULL, 0);
+                       lsp_debug(
+                               "ISIS (%s): Adding %s.%02x as te-style neighbor (peer)",
+                               area->area_tag, sysid_print(ne_id),
+                               LSP_PSEUDO_ID(ne_id));
+               }
+       }
+       list_delete(adj_list);
        return;
 }
 
@@ -2543,7 +1536,7 @@ int lsp_generate_pseudo(struct isis_circuit *circuit, int level)
        lsp->area = circuit->area;
 
        lsp_build_pseudo(lsp, circuit, level);
-
+       lsp_pack_pdu(lsp);
        lsp->own_lsp = 1;
        lsp_insert(lsp, lspdb);
        lsp_set_all_srmflags(lsp);
@@ -2562,14 +1555,13 @@ int lsp_generate_pseudo(struct isis_circuit *circuit, int level)
 
        if (isis->debugs & DEBUG_UPDATE_PACKETS) {
                zlog_debug(
-                       "ISIS-Upd (%s): Building L%d Pseudo LSP %s, len %d, "
-                       "seq 0x%08x, cksum 0x%04x, lifetime %us, refresh %us",
+                       "ISIS-Upd (%s): Built L%d Pseudo LSP %s, len %" PRIu16
+                       ", seq 0x%08" PRIx32 ", cksum 0x%04" PRIx16
+                       ", lifetime %" PRIu16 "s, refresh %" PRIu16 "s",
                        circuit->area->area_tag, level,
-                       rawlspid_print(lsp->lsp_header->lsp_id),
-                       ntohl(lsp->lsp_header->pdu_len),
-                       ntohl(lsp->lsp_header->seq_num),
-                       ntohs(lsp->lsp_header->checksum),
-                       ntohs(lsp->lsp_header->rem_lifetime), refresh_time);
+                       rawlspid_print(lsp->hdr.lsp_id), lsp->hdr.pdu_len,
+                       lsp->hdr.seqno, lsp->hdr.checksum,
+                       lsp->hdr.rem_lifetime, refresh_time);
        }
 
        return ISIS_OK;
@@ -2599,16 +1591,11 @@ static int lsp_regenerate_pseudo(struct isis_circuit *circuit, int level)
                         rawlspid_print(lsp_id));
                return ISIS_ERROR;
        }
-       lsp_clear_data(lsp);
 
-       lsp_build_pseudo(lsp, circuit, level);
-
-       /* RFC3787  section 4 SHOULD not set overload bit in pseudo LSPs */
-       lsp->lsp_header->lsp_bits =
-               lsp_bits_generate(level, 0, circuit->area->attached_bit);
        rem_lifetime = lsp_rem_lifetime(circuit->area, level);
-       lsp->lsp_header->rem_lifetime = htons(rem_lifetime);
-       lsp_inc_seqnum(lsp, 0);
+       lsp->hdr.rem_lifetime = rem_lifetime;
+       lsp_build_pseudo(lsp, circuit, level);
+       lsp_inc_seqno(lsp, 0);
        lsp->last_generated = time(NULL);
        lsp_set_all_srmflags(lsp);
 
@@ -2624,14 +1611,13 @@ static int lsp_regenerate_pseudo(struct isis_circuit *circuit, int level)
 
        if (isis->debugs & DEBUG_UPDATE_PACKETS) {
                zlog_debug(
-                       "ISIS-Upd (%s): Refreshing L%d Pseudo LSP %s, len %d, "
-                       "seq 0x%08x, cksum 0x%04x, lifetime %us, refresh %us",
+                       "ISIS-Upd (%s): Refreshed L%d Pseudo LSP %s, len %" PRIu16
+                       ", seq 0x%08" PRIx32 ", cksum 0x%04" PRIx16
+                       ", lifetime %" PRIu16 "s, refresh %" PRIu16 "s",
                        circuit->area->area_tag, level,
-                       rawlspid_print(lsp->lsp_header->lsp_id),
-                       ntohl(lsp->lsp_header->pdu_len),
-                       ntohl(lsp->lsp_header->seq_num),
-                       ntohs(lsp->lsp_header->checksum),
-                       ntohs(lsp->lsp_header->rem_lifetime), refresh_time);
+                       rawlspid_print(lsp->hdr.lsp_id), lsp->hdr.pdu_len,
+                       lsp->hdr.seqno, lsp->hdr.checksum,
+                       lsp->hdr.rem_lifetime, refresh_time);
        }
 
        return ISIS_OK;
@@ -2828,8 +1814,7 @@ int lsp_tick(struct thread *thread)
                                 * when
                                 * the first time rem_lifetime becomes 0.
                                 */
-                               rem_lifetime =
-                                       ntohs(lsp->lsp_header->rem_lifetime);
+                               rem_lifetime = lsp->hdr.rem_lifetime;
                                lsp_set_time(lsp);
 
                                /*
@@ -2839,8 +1824,7 @@ int lsp_tick(struct thread *thread)
                                 * time.
                                 * ISO 10589 - 7.3.16.4 first paragraph.
                                 */
-                               if (rem_lifetime == 1
-                                   && lsp->lsp_header->seq_num != 0) {
+                               if (rem_lifetime == 1 && lsp->hdr.seqno != 0) {
                                        /* 7.3.16.4 a) set SRM flags on all */
                                        lsp_set_all_srmflags(lsp);
                                        /* 7.3.16.4 b) retain only the header
@@ -2857,13 +1841,11 @@ int lsp_tick(struct thread *thread)
 
                                if (lsp->age_out == 0) {
                                        zlog_debug(
-                                               "ISIS-Upd (%s): L%u LSP %s seq 0x%08x aged out",
+                                               "ISIS-Upd (%s): L%u LSP %s seq "
+                                               "0x%08" PRIx32 " aged out",
                                                area->area_tag, lsp->level,
-                                               rawlspid_print(
-                                                       lsp->lsp_header
-                                                               ->lsp_id),
-                                               ntohl(lsp->lsp_header
-                                                             ->seq_num));
+                                               rawlspid_print(lsp->hdr.lsp_id),
+                                               lsp->hdr.seqno);
                                        lsp_destroy(lsp);
                                        lsp = NULL;
                                        dict_delete_free(area->lspdb[level],
@@ -2924,51 +1906,19 @@ int lsp_tick(struct thread *thread)
 void lsp_purge_pseudo(u_char *id, struct isis_circuit *circuit, int level)
 {
        struct isis_lsp *lsp;
-       u_int16_t seq_num;
-       u_int8_t lsp_bits;
 
        lsp = lsp_search(id, circuit->area->lspdb[level - 1]);
        if (!lsp)
                return;
 
-       /* store old values */
-       seq_num = lsp->lsp_header->seq_num;
-       lsp_bits = lsp->lsp_header->lsp_bits;
-
-       /* reset stream */
-       lsp_clear_data(lsp);
-       stream_reset(lsp->pdu);
-
-       /* update header */
-       lsp->lsp_header->pdu_len = htons(ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
-       memcpy(lsp->lsp_header->lsp_id, id, ISIS_SYS_ID_LEN + 2);
-       lsp->lsp_header->checksum = 0;
-       lsp->lsp_header->seq_num = seq_num;
-       lsp->lsp_header->rem_lifetime = 0;
-       lsp->lsp_header->lsp_bits = lsp_bits;
-       lsp->level = level;
-       lsp->age_out = lsp->area->max_lsp_lifetime[level - 1];
-       stream_forward_endp(lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
-
-       /*
-        * Add and update the authentication info if its present
-        */
-       lsp_auth_add(lsp);
-       lsp->lsp_header->pdu_len = htons(stream_get_endp(lsp->pdu));
-       lsp_auth_update(lsp);
-       fletcher_checksum(STREAM_DATA(lsp->pdu) + 12,
-                         ntohs(lsp->lsp_header->pdu_len) - 12, 12);
-
-       lsp_set_all_srmflags(lsp);
-
-       return;
+       lsp_purge(lsp, level);
 }
 
 /*
  * Purge own LSP that is received and we don't have.
  * -> Do as in 7.3.16.4
  */
-void lsp_purge_non_exist(int level, struct isis_link_state_hdr *lsp_hdr,
+void lsp_purge_non_exist(int level, struct isis_lsp_hdr *hdr,
                         struct isis_area *area)
 {
        struct isis_lsp *lsp;
@@ -2980,39 +1930,14 @@ void lsp_purge_non_exist(int level, struct isis_link_state_hdr *lsp_hdr,
        lsp->area = area;
        lsp->level = level;
        lsp->pdu = stream_new(LLC_LEN + area->lsp_mtu);
-       lsp->isis_header = (struct isis_fixed_hdr *)STREAM_DATA(lsp->pdu);
-       fill_fixed_hdr(lsp->isis_header,
-                      (lsp->level == IS_LEVEL_1) ? L1_LINK_STATE
-                                                 : L2_LINK_STATE);
-       lsp->lsp_header = (struct isis_link_state_hdr *)(STREAM_DATA(lsp->pdu)
-                                                        + ISIS_FIXED_HDR_LEN);
-       memcpy(lsp->lsp_header, lsp_hdr, ISIS_LSP_HDR_LEN);
-       stream_forward_endp(lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
-
-       /*
-        * Set the remaining lifetime to 0
-        */
-       lsp->lsp_header->rem_lifetime = 0;
+       lsp->age_out = ZERO_AGE_LIFETIME;
 
-       /*
-        * Add and update the authentication info if its present
-        */
-       lsp_auth_add(lsp);
-       lsp_auth_update(lsp);
+       memcpy(&lsp->hdr, hdr, sizeof(lsp->hdr));
+       lsp->hdr.rem_lifetime = 0;
 
-       /*
-        * Update the PDU length to header plus any authentication TLV.
-        */
-       lsp->lsp_header->pdu_len = htons(stream_get_endp(lsp->pdu));
+       lsp_pack_pdu(lsp);
 
-       /*
-        * Put the lsp into LSPdb
-        */
        lsp_insert(lsp, area->lspdb[lsp->level - 1]);
-
-       /*
-        * Send in to whole area
-        */
        lsp_set_all_srmflags(lsp);
 
        return;
index 7bec162719cedafd4025980083837c8c39398483..0f9c749949710402cde9ab4da6466c5f6e009dac 100644 (file)
 #ifndef _ZEBRA_ISIS_LSP_H
 #define _ZEBRA_ISIS_LSP_H
 
+#include "isisd/isis_pdu.h"
+
 /* Structure for isis_lsp, this structure will only support the fixed
  * System ID (Currently 6) (atleast for now). In order to support more
  * We will have to split the header into two parts, and for readability
  * sake it should better be avoided */
 struct isis_lsp {
-       struct isis_fixed_hdr *isis_header;     /* normally equals pdu */
-       struct isis_link_state_hdr *lsp_header; /* pdu + isis_header_len */
-       struct stream *pdu;                     /* full pdu lsp */
+       struct isis_lsp_hdr hdr;
+       struct stream *pdu; /* full pdu lsp */
        union {
                struct list *frags;
                struct isis_lsp *zero_lsp;
        } lspu;
-       u_int32_t auth_tlv_offset; /* authentication TLV position in the pdu */
        u_int32_t SRMflags[ISIS_MAX_CIRCUITS];
        u_int32_t SSNflags[ISIS_MAX_CIRCUITS];
        int level;     /* L1 or L2? */
@@ -47,7 +47,7 @@ struct isis_lsp {
        /* used for 60 second counting when rem_lifetime is zero */
        int age_out;
        struct isis_area *area;
-       struct tlvs tlv_data; /* Simplifies TLV access */
+       struct isis_tlvs *tlvs;
 };
 
 dict_t *lsp_db_init(void);
@@ -59,13 +59,13 @@ int lsp_regenerate_schedule(struct isis_area *area, int level, int all_pseudo);
 int lsp_generate_pseudo(struct isis_circuit *circuit, int level);
 int lsp_regenerate_schedule_pseudo(struct isis_circuit *circuit, int level);
 
-struct isis_lsp *lsp_new(struct isis_area *area, u_char *lsp_id,
-                        u_int16_t rem_lifetime, u_int32_t seq_num,
-                        u_int8_t lsp_bits, u_int16_t checksum, int level);
-struct isis_lsp *lsp_new_from_stream_ptr(struct stream *stream,
-                                        u_int16_t pdu_len,
-                                        struct isis_lsp *lsp0,
-                                        struct isis_area *area, int level);
+struct isis_lsp *lsp_new(struct isis_area *area, uint8_t *lsp_id,
+                        uint16_t rem_lifetime, uint32_t seq_num,
+                        uint8_t lsp_bits, uint16_t checksum, int level);
+struct isis_lsp *lsp_new_from_recv(struct isis_lsp_hdr *hdr,
+                                  struct isis_tlvs *tlvs,
+                                  struct stream *stream, struct isis_lsp *lsp0,
+                                  struct isis_area *area, int level);
 void lsp_insert(struct isis_lsp *lsp, dict_t *lspdb);
 struct isis_lsp *lsp_search(u_char *id, dict_t *lspdb);
 
@@ -73,12 +73,9 @@ void lsp_build_list(u_char *start_id, u_char *stop_id, u_char num_lsps,
                    struct list *list, dict_t *lspdb);
 void lsp_build_list_nonzero_ht(u_char *start_id, u_char *stop_id,
                               struct list *list, dict_t *lspdb);
-void lsp_build_list_ssn(struct isis_circuit *circuit, u_char num_lsps,
-                       struct list *list, dict_t *lspdb);
-
 void lsp_search_and_destroy(u_char *id, dict_t *lspdb);
 void lsp_purge_pseudo(u_char *id, struct isis_circuit *circuit, int level);
-void lsp_purge_non_exist(int level, struct isis_link_state_hdr *lsp_hdr,
+void lsp_purge_non_exist(int level, struct isis_lsp_hdr *hdr,
                         struct isis_area *area);
 
 #define LSP_EQUAL 1
@@ -92,16 +89,15 @@ void lsp_purge_non_exist(int level, struct isis_link_state_hdr *lsp_hdr,
        (I)[ISIS_SYS_ID_LEN] = 0;                                              \
        (I)[ISIS_SYS_ID_LEN + 1] = 0
 int lsp_id_cmp(u_char *id1, u_char *id2);
-int lsp_compare(char *areatag, struct isis_lsp *lsp, u_int32_t seq_num,
-               u_int16_t checksum, u_int16_t rem_lifetime);
-void lsp_update(struct isis_lsp *lsp, struct stream *stream,
-               struct isis_area *area, int level);
-void lsp_inc_seqnum(struct isis_lsp *lsp, u_int32_t seq_num);
+int lsp_compare(char *areatag, struct isis_lsp *lsp, uint32_t seqno,
+               uint16_t checksum, uint16_t rem_lifetime);
+void lsp_update(struct isis_lsp *lsp, struct isis_lsp_hdr *hdr,
+               struct isis_tlvs *tlvs, struct stream *stream,
+               struct isis_area *area, int level, bool confusion);
+void lsp_inc_seqno(struct isis_lsp *lsp, uint32_t seqno);
 void lsp_print(struct isis_lsp *lsp, struct vty *vty, char dynhost);
 void lsp_print_detail(struct isis_lsp *lsp, struct vty *vty, char dynhost);
 int lsp_print_all(struct vty *vty, dict_t *lspdb, char detail, char dynhost);
-const char *lsp_bits2string(u_char *);
-
 /* sets SRMflags for all active circuits of an lsp */
 void lsp_set_all_srmflags(struct isis_lsp *lsp);
 
index 463e3abcf3471ad788594868c8c532f35635f8f5..40ceb99fb259ff647461f90d4b2eae3863ebd22a 100644 (file)
@@ -52,7 +52,6 @@
 #include "isisd/isis_route.h"
 #include "isisd/isis_routemap.h"
 #include "isisd/isis_zebra.h"
-#include "isisd/isis_tlv.h"
 #include "isisd/isis_te.h"
 
 /* Default configuration file name */
index 4ad26cf91f4daaea7991bc5a3ca79d9f5331dd37..7d1ad6b049a5382d4d0f4eac74c46aa915570bc1 100644 (file)
@@ -31,9 +31,9 @@ DEFINE_MTYPE(ISISD, ISIS_TMP, "ISIS TMP")
 DEFINE_MTYPE(ISISD, ISIS_CIRCUIT, "ISIS circuit")
 DEFINE_MTYPE(ISISD, ISIS_LSP, "ISIS LSP")
 DEFINE_MTYPE(ISISD, ISIS_ADJACENCY, "ISIS adjacency")
+DEFINE_MTYPE(ISISD, ISIS_ADJACENCY_INFO, "ISIS adjacency info")
 DEFINE_MTYPE(ISISD, ISIS_AREA, "ISIS area")
 DEFINE_MTYPE(ISISD, ISIS_AREA_ADDR, "ISIS area address")
-DEFINE_MTYPE(ISISD, ISIS_TLV, "ISIS TLV")
 DEFINE_MTYPE(ISISD, ISIS_DYNHN, "ISIS dyn hostname")
 DEFINE_MTYPE(ISISD, ISIS_SPFTREE, "ISIS SPFtree")
 DEFINE_MTYPE(ISISD, ISIS_VERTEX, "ISIS vertex")
index 7729ebac33098a0a3a5fc78574642e191f3ebbfd..4078c7a67114ff9f4fc703bbc15a7ae1085bf9e7 100644 (file)
@@ -30,9 +30,9 @@ DECLARE_MTYPE(ISIS_TMP)
 DECLARE_MTYPE(ISIS_CIRCUIT)
 DECLARE_MTYPE(ISIS_LSP)
 DECLARE_MTYPE(ISIS_ADJACENCY)
+DECLARE_MTYPE(ISIS_ADJACENCY_INFO)
 DECLARE_MTYPE(ISIS_AREA)
 DECLARE_MTYPE(ISIS_AREA_ADDR)
-DECLARE_MTYPE(ISIS_TLV)
 DECLARE_MTYPE(ISIS_DYNHN)
 DECLARE_MTYPE(ISIS_SPFTREE)
 DECLARE_MTYPE(ISIS_VERTEX)
index 16c789ff5993875dc33263803747ea1d77e9330c..e8888a5f5bc0a379009a0bfa318b106cd9a57b09 100644 (file)
@@ -28,6 +28,7 @@
 #include "hash.h"
 #include "if.h"
 #include "command.h"
+#include "log_int.h"
 
 #include "isisd/dict.h"
 #include "isisd/isis_constants.h"
@@ -38,7 +39,6 @@
 #include "isisd/isisd.h"
 #include "isisd/isis_misc.h"
 
-#include "isisd/isis_tlv.h"
 #include "isisd/isis_lsp.h"
 #include "isisd/isis_constants.h"
 #include "isisd/isis_adjacency.h"
 
 /* staticly assigned vars for printing purposes */
 struct in_addr new_prefix;
-/* len of xxxx.xxxx.xxxx + place for #0 termination */
-char sysid[15];
-/* len of xxxx.xxxx.xxxx + place for #0 termination */
-char snpa[15];
 /* len of xx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.xx */
-char isonet[51];
 /* + place for #0 termination */
-/* len of xxxx.xxxx.xxxx.xx.xx + place for #0 termination */
-char lspid[21];
+char isonet[51];
 /* len of xxYxxMxWxdxxhxxmxxs + place for #0 termination */
 char datestring[20];
 char nlpidstring[30];
@@ -179,6 +173,26 @@ int sysid2buff(u_char *buff, const char *dotted)
        return len;
 }
 
+const char *nlpid2str(uint8_t nlpid)
+{
+       static char buf[4];
+       switch (nlpid) {
+       case NLPID_IP:
+               return "IPv4";
+       case NLPID_IPV6:
+               return "IPv6";
+       case NLPID_SNAP:
+               return "SNAP";
+       case NLPID_CLNP:
+               return "CLNP";
+       case NLPID_ESIS:
+               return "ES-IS";
+       default:
+               snprintf(buf, sizeof(buf), "%" PRIu8, nlpid);
+               return buf;
+       }
+}
+
 /*
  * converts the nlpids struct (filled by TLV #129)
  * into a string
@@ -190,26 +204,7 @@ char *nlpid2string(struct nlpids *nlpids)
        int i;
 
        for (i = 0; i < nlpids->count; i++) {
-               switch (nlpids->nlpids[i]) {
-               case NLPID_IP:
-                       pos += sprintf(pos, "IPv4");
-                       break;
-               case NLPID_IPV6:
-                       pos += sprintf(pos, "IPv6");
-                       break;
-               case NLPID_SNAP:
-                       pos += sprintf(pos, "SNAP");
-                       break;
-               case NLPID_CLNP:
-                       pos += sprintf(pos, "CLNP");
-                       break;
-               case NLPID_ESIS:
-                       pos += sprintf(pos, "ES-IS");
-                       break;
-               default:
-                       pos += sprintf(pos, "unknown");
-                       break;
-               }
+               pos += sprintf(pos, "%s", nlpid2str(nlpids->nlpids[i]));
                if (nlpids->count - i > 1)
                        pos += sprintf(pos, ", ");
        }
@@ -219,25 +214,6 @@ char *nlpid2string(struct nlpids *nlpids)
        return nlpidstring;
 }
 
-/*
- *  supports the given af ?
- */
-int speaks(struct nlpids *nlpids, int family)
-{
-       int i, speaks = 0;
-
-       if (nlpids == (struct nlpids *)NULL)
-               return speaks;
-       for (i = 0; i < nlpids->count; i++) {
-               if (family == AF_INET && nlpids->nlpids[i] == NLPID_IP)
-                       speaks = 1;
-               if (family == AF_INET6 && nlpids->nlpids[i] == NLPID_IPV6)
-                       speaks = 1;
-       }
-
-       return speaks;
-}
-
 /*
  * Returns 0 on error, IS-IS Circuit Type on ok
  */
@@ -330,71 +306,53 @@ const char *syst2string(int type)
  */
 const char *snpa_print(const u_char *from)
 {
-       int i = 0;
-       u_char *pos = (u_char *)snpa;
-
-       if (!from)
-               return "unknown";
-
-       while (i < ETH_ALEN - 1) {
-               if (i & 1) {
-                       sprintf((char *)pos, "%02x.", *(from + i));
-                       pos += 3;
-               } else {
-                       sprintf((char *)pos, "%02x", *(from + i));
-                       pos += 2;
-               }
-               i++;
-       }
+       return isis_format_id(from, ISIS_SYS_ID_LEN);
+}
 
-       sprintf((char *)pos, "%02x", *(from + (ISIS_SYS_ID_LEN - 1)));
-       pos += 2;
-       *(pos) = '\0';
+const char *sysid_print(const u_char *from)
+{
+       return isis_format_id(from, ISIS_SYS_ID_LEN);
+}
 
-       return snpa;
+const char *rawlspid_print(const u_char *from)
+{
+       return isis_format_id(from, 8);
 }
 
-const char *sysid_print(const u_char *from)
+#define FORMAT_ID_SIZE sizeof("0000.0000.0000.00-00")
+const char *isis_format_id(const uint8_t *id, size_t len)
 {
-       int i = 0;
-       char *pos = sysid;
+#define FORMAT_BUF_COUNT 4
+       static char buf_ring[FORMAT_BUF_COUNT][FORMAT_ID_SIZE];
+       static size_t cur_buf = 0;
 
-       if (!from)
-               return "unknown";
+       char *rv;
 
-       while (i < ISIS_SYS_ID_LEN - 1) {
-               if (i & 1) {
-                       sprintf(pos, "%02x.", *(from + i));
-                       pos += 3;
-               } else {
-                       sprintf(pos, "%02x", *(from + i));
-                       pos += 2;
-               }
-               i++;
-       }
+       cur_buf++;
+       if (cur_buf >= FORMAT_BUF_COUNT)
+               cur_buf = 0;
 
-       sprintf(pos, "%02x", *(from + (ISIS_SYS_ID_LEN - 1)));
-       pos += 2;
-       *(pos) = '\0';
+       rv = buf_ring[cur_buf];
 
-       return sysid;
-}
+       if (!id) {
+               snprintf(rv, FORMAT_ID_SIZE, "unknown");
+               return rv;
+       }
 
-const char *rawlspid_print(const u_char *from)
-{
-       char *pos = lspid;
-       if (!from)
-               return "unknown";
-       memcpy(pos, sysid_print(from), 15);
-       pos += 14;
-       sprintf(pos, ".%02x", LSP_PSEUDO_ID(from));
-       pos += 3;
-       sprintf(pos, "-%02x", LSP_FRAGMENT(from));
-       pos += 3;
+       if (len < 6) {
+               snprintf(rv, FORMAT_ID_SIZE, "Short ID");
+               return rv;
+       }
 
-       *(pos) = '\0';
+       snprintf(rv, FORMAT_ID_SIZE, "%02x%02x.%02x%02x.%02x%02x", id[0], id[1],
+                id[2], id[3], id[4], id[5]);
+
+       if (len > 6)
+               snprintf(rv + 14, FORMAT_ID_SIZE - 14, ".%02x", id[6]);
+       if (len > 7)
+               snprintf(rv + 17, FORMAT_ID_SIZE - 17, "-%02x", id[7]);
 
-       return lspid;
+       return rv;
 }
 
 const char *time2string(u_int32_t time)
@@ -508,7 +466,7 @@ const char *print_sys_hostname(const u_char *sysid)
 
        dyn = dynhn_find_by_id(sysid);
        if (dyn)
-               return (const char *)dyn->name.name;
+               return dyn->hostname;
 
        return sysid_print(sysid);
 }
@@ -572,3 +530,93 @@ void zlog_dump_data(void *data, int len)
                zlog_debug("[%8.8s]   %-50.50s  %s", addrstr, hexstr, charstr);
        return;
 }
+
+static char *qasprintf(const char *format, va_list ap)
+{
+       va_list aq;
+       va_copy(aq, ap);
+
+       int size = 0;
+       char *p = NULL;
+
+       size = vsnprintf(p, size, format, ap);
+
+       if (size < 0) {
+               va_end(aq);
+               return NULL;
+       }
+
+       size++;
+       p = XMALLOC(MTYPE_TMP, size);
+
+       size = vsnprintf(p, size, format, aq);
+       va_end(aq);
+
+       if (size < 0) {
+               XFREE(MTYPE_TMP, p);
+               return NULL;
+       }
+
+       return p;
+}
+
+void log_multiline(int priority, const char *prefix, const char *format, ...)
+{
+       va_list ap;
+       char *p;
+
+       va_start(ap, format);
+       p = qasprintf(format, ap);
+       va_end(ap);
+
+       if (!p)
+               return;
+
+       char *saveptr = NULL;
+       for (char *line = strtok_r(p, "\n", &saveptr); line;
+            line = strtok_r(NULL, "\n", &saveptr)) {
+               zlog(priority, "%s%s", prefix, line);
+       }
+
+       XFREE(MTYPE_TMP, p);
+}
+
+void vty_multiline(struct vty *vty, const char *prefix, const char *format, ...)
+{
+       va_list ap;
+       char *p;
+
+       va_start(ap, format);
+       p = qasprintf(format, ap);
+       va_end(ap);
+
+       if (!p)
+               return;
+
+       char *saveptr = NULL;
+       for (char *line = strtok_r(p, "\n", &saveptr); line;
+            line = strtok_r(NULL, "\n", &saveptr)) {
+               vty_out(vty, "%s%s\n", prefix, line);
+       }
+
+       XFREE(MTYPE_TMP, p);
+}
+
+void vty_out_timestr(struct vty *vty, time_t uptime)
+{
+       struct tm *tm;
+       time_t difftime = time(NULL);
+       difftime -= uptime;
+       tm = gmtime(&difftime);
+
+       if (difftime < ONE_DAY_SECOND)
+               vty_out(vty, "%02d:%02d:%02d", tm->tm_hour, tm->tm_min,
+                       tm->tm_sec);
+       else if (difftime < ONE_WEEK_SECOND)
+               vty_out(vty, "%dd%02dh%02dm", tm->tm_yday, tm->tm_hour,
+                       tm->tm_min);
+       else
+               vty_out(vty, "%02dw%dd%02dh", tm->tm_yday / 7,
+                       tm->tm_yday - ((tm->tm_yday / 7) * 7), tm->tm_hour);
+       vty_out(vty, " ago");
+}
index 12ab0fac1ca849585f5750ab3233f28cbf2227c2..5a19a1ffa0debe6bd5d78df4c0e4bd8b3f0da7e9 100644 (file)
@@ -44,7 +44,9 @@ const char *isonet_print(const u_char *, int len);
 const char *sysid_print(const u_char *);
 const char *snpa_print(const u_char *);
 const char *rawlspid_print(const u_char *);
+const char *isis_format_id(const uint8_t *id, size_t len);
 const char *time2string(u_int32_t);
+const char *nlpid2str(uint8_t nlpid);
 /* typedef struct nlpids nlpids; */
 char *nlpid2string(struct nlpids *);
 const char *print_sys_hostname(const u_char *sysid);
@@ -53,7 +55,6 @@ void zlog_dump_data(void *data, int len);
 /*
  * misc functions
  */
-int speaks(struct nlpids *nlpids, int family);
 unsigned long isis_jitter(unsigned long timer, unsigned long jitter);
 const char *unix_hostname(void);
 
@@ -77,4 +78,11 @@ enum { ISIS_UI_LEVEL_BRIEF,
        ISIS_UI_LEVEL_EXTENSIVE,
 };
 
+#include "lib/log.h"
+void log_multiline(int priority, const char *prefix, const char *format, ...)
+       PRINTF_ATTRIBUTE(3, 4);
+struct vty;
+void vty_multiline(struct vty *vty, const char *prefix, const char *format, ...)
+       PRINTF_ATTRIBUTE(3, 4);
+void vty_out_timestr(struct vty *vty, time_t uptime);
 #endif
index 46b57510ac531bf35372f77f323685e202f3efd3..52646c26245b03379e9e175b1f06a6bbd1ad1365 100644 (file)
 #include "isisd/isis_memory.h"
 #include "isisd/isis_circuit.h"
 #include "isisd/isis_adjacency.h"
-#include "isisd/isis_tlv.h"
 #include "isisd/isis_misc.h"
 #include "isisd/isis_lsp.h"
 #include "isisd/isis_mt.h"
+#include "isisd/isis_tlvs.h"
 
 DEFINE_MTYPE_STATIC(ISISD, MT_AREA_SETTING, "ISIS MT Area Setting")
 DEFINE_MTYPE_STATIC(ISISD, MT_CIRCUIT_SETTING, "ISIS MT Circuit Setting")
 DEFINE_MTYPE_STATIC(ISISD, MT_ADJ_INFO, "ISIS MT Adjacency Info")
-DEFINE_MTYPE_STATIC(ISISD, MT_NEIGHBORS, "ISIS MT Neighbors for TLV")
-DEFINE_MTYPE_STATIC(ISISD, MT_IPV4_REACHS,
-                   "ISIS MT IPv4 Reachabilities for TLV")
-DEFINE_MTYPE_STATIC(ISISD, MT_IPV6_REACHS,
-                   "ISIS MT IPv6 Reachabilities for TLV")
 
 uint16_t isis_area_ipv6_topology(struct isis_area *area)
 {
@@ -367,7 +362,7 @@ static void adj_mt_set(struct isis_adjacency *adj, unsigned int index,
        adj->mt_set[index] = mtid;
 }
 
-bool tlvs_to_adj_mt_set(struct tlvs *tlvs, bool v4_usable, bool v6_usable,
+bool tlvs_to_adj_mt_set(struct isis_tlvs *tlvs, bool v4_usable, bool v6_usable,
                        struct isis_adjacency *adj)
 {
        struct isis_circuit_mt_setting **mt_settings;
@@ -388,17 +383,20 @@ bool tlvs_to_adj_mt_set(struct tlvs *tlvs, bool v4_usable, bool v6_usable,
 
        mt_settings = circuit_mt_settings(adj->circuit, &circuit_mt_count);
        for (unsigned int i = 0; i < circuit_mt_count; i++) {
-               if (!tlvs->mt_router_info) {
+               if (!tlvs->mt_router_info.count
+                   && !tlvs->mt_router_info_empty) {
                        /* Other end does not have MT enabled */
                        if (mt_settings[i]->mtid == ISIS_MT_IPV4_UNICAST
                            && v4_usable)
                                adj_mt_set(adj, intersect_count++,
                                           ISIS_MT_IPV4_UNICAST);
                } else {
-                       struct listnode *node;
-                       struct mt_router_info *info;
-                       for (ALL_LIST_ELEMENTS_RO(tlvs->mt_router_info, node,
-                                                 info)) {
+                       struct isis_mt_router_info *info_head;
+
+                       info_head = (struct isis_mt_router_info *)
+                                           tlvs->mt_router_info.head;
+                       for (struct isis_mt_router_info *info = info_head; info;
+                            info = info->next) {
                                if (mt_settings[i]->mtid == info->mtid) {
                                        bool usable;
                                        switch (info->mtid) {
@@ -456,153 +454,6 @@ void adj_mt_finish(struct isis_adjacency *adj)
        adj->mt_count = 0;
 }
 
-/* TLV Router info api */
-struct mt_router_info *tlvs_lookup_mt_router_info(struct tlvs *tlvs,
-                                                 uint16_t mtid)
-{
-       return lookup_mt_setting(tlvs->mt_router_info, mtid);
-}
-
-/* TLV MT Neighbors api */
-struct tlv_mt_neighbors *tlvs_lookup_mt_neighbors(struct tlvs *tlvs,
-                                                 uint16_t mtid)
-{
-       return lookup_mt_setting(tlvs->mt_is_neighs, mtid);
-}
-
-static struct tlv_mt_neighbors *tlvs_new_mt_neighbors(uint16_t mtid)
-{
-       struct tlv_mt_neighbors *rv;
-
-       rv = XCALLOC(MTYPE_MT_NEIGHBORS, sizeof(*rv));
-       rv->mtid = mtid;
-       rv->list = list_new();
-
-       return rv;
-};
-
-static void tlvs_free_mt_neighbors(void *arg)
-{
-       struct tlv_mt_neighbors *neighbors = arg;
-
-       if (neighbors && neighbors->list)
-               list_delete(neighbors->list);
-       XFREE(MTYPE_MT_NEIGHBORS, neighbors);
-}
-
-static void tlvs_add_mt_neighbors(struct tlvs *tlvs,
-                                 struct tlv_mt_neighbors *neighbors)
-{
-       add_mt_setting(&tlvs->mt_is_neighs, neighbors);
-       tlvs->mt_is_neighs->del = tlvs_free_mt_neighbors;
-}
-
-struct tlv_mt_neighbors *tlvs_get_mt_neighbors(struct tlvs *tlvs, uint16_t mtid)
-{
-       struct tlv_mt_neighbors *neighbors;
-
-       neighbors = tlvs_lookup_mt_neighbors(tlvs, mtid);
-       if (!neighbors) {
-               neighbors = tlvs_new_mt_neighbors(mtid);
-               tlvs_add_mt_neighbors(tlvs, neighbors);
-       }
-       return neighbors;
-}
-
-/* TLV MT IPv4 reach api */
-struct tlv_mt_ipv4_reachs *tlvs_lookup_mt_ipv4_reachs(struct tlvs *tlvs,
-                                                     uint16_t mtid)
-{
-       return lookup_mt_setting(tlvs->mt_ipv4_reachs, mtid);
-}
-
-static struct tlv_mt_ipv4_reachs *tlvs_new_mt_ipv4_reachs(uint16_t mtid)
-{
-       struct tlv_mt_ipv4_reachs *rv;
-
-       rv = XCALLOC(MTYPE_MT_IPV4_REACHS, sizeof(*rv));
-       rv->mtid = mtid;
-       rv->list = list_new();
-
-       return rv;
-};
-
-static void tlvs_free_mt_ipv4_reachs(void *arg)
-{
-       struct tlv_mt_ipv4_reachs *reachs = arg;
-
-       if (reachs && reachs->list)
-               list_delete(reachs->list);
-       XFREE(MTYPE_MT_IPV4_REACHS, reachs);
-}
-
-static void tlvs_add_mt_ipv4_reachs(struct tlvs *tlvs,
-                                   struct tlv_mt_ipv4_reachs *reachs)
-{
-       add_mt_setting(&tlvs->mt_ipv4_reachs, reachs);
-       tlvs->mt_ipv4_reachs->del = tlvs_free_mt_ipv4_reachs;
-}
-
-struct tlv_mt_ipv4_reachs *tlvs_get_mt_ipv4_reachs(struct tlvs *tlvs,
-                                                  uint16_t mtid)
-{
-       struct tlv_mt_ipv4_reachs *reachs;
-
-       reachs = tlvs_lookup_mt_ipv4_reachs(tlvs, mtid);
-       if (!reachs) {
-               reachs = tlvs_new_mt_ipv4_reachs(mtid);
-               tlvs_add_mt_ipv4_reachs(tlvs, reachs);
-       }
-       return reachs;
-}
-
-/* TLV MT IPv6 reach api */
-struct tlv_mt_ipv6_reachs *tlvs_lookup_mt_ipv6_reachs(struct tlvs *tlvs,
-                                                     uint16_t mtid)
-{
-       return lookup_mt_setting(tlvs->mt_ipv6_reachs, mtid);
-}
-
-static struct tlv_mt_ipv6_reachs *tlvs_new_mt_ipv6_reachs(uint16_t mtid)
-{
-       struct tlv_mt_ipv6_reachs *rv;
-
-       rv = XCALLOC(MTYPE_MT_IPV6_REACHS, sizeof(*rv));
-       rv->mtid = mtid;
-       rv->list = list_new();
-
-       return rv;
-};
-
-static void tlvs_free_mt_ipv6_reachs(void *arg)
-{
-       struct tlv_mt_ipv6_reachs *reachs = arg;
-
-       if (reachs && reachs->list)
-               list_delete(reachs->list);
-       XFREE(MTYPE_MT_IPV6_REACHS, reachs);
-}
-
-static void tlvs_add_mt_ipv6_reachs(struct tlvs *tlvs,
-                                   struct tlv_mt_ipv6_reachs *reachs)
-{
-       add_mt_setting(&tlvs->mt_ipv6_reachs, reachs);
-       tlvs->mt_ipv6_reachs->del = tlvs_free_mt_ipv6_reachs;
-}
-
-struct tlv_mt_ipv6_reachs *tlvs_get_mt_ipv6_reachs(struct tlvs *tlvs,
-                                                  uint16_t mtid)
-{
-       struct tlv_mt_ipv6_reachs *reachs;
-
-       reachs = tlvs_lookup_mt_ipv6_reachs(tlvs, mtid);
-       if (!reachs) {
-               reachs = tlvs_new_mt_ipv6_reachs(mtid);
-               tlvs_add_mt_ipv6_reachs(tlvs, reachs);
-       }
-       return reachs;
-}
-
 static void mt_set_add(uint16_t **mt_set, unsigned int *size,
                       unsigned int *index, uint16_t mtid)
 {
@@ -647,51 +498,46 @@ static uint16_t *circuit_bcast_mt_set(struct isis_circuit *circuit, int level,
        return rv;
 }
 
-static void tlvs_add_mt_set(struct isis_area *area, struct tlvs *tlvs,
+static void tlvs_add_mt_set(struct isis_area *area, struct isis_tlvs *tlvs,
                            unsigned int mt_count, uint16_t *mt_set,
-                           struct te_is_neigh *neigh)
+                           uint8_t *id, uint32_t metric, uint8_t *subtlvs,
+                           uint8_t subtlv_len)
 {
        for (unsigned int i = 0; i < mt_count; i++) {
                uint16_t mtid = mt_set[i];
-               struct te_is_neigh *ne_copy;
-
-               ne_copy = XCALLOC(MTYPE_ISIS_TLV, sizeof(*ne_copy));
-               memcpy(ne_copy, neigh, sizeof(*ne_copy));
-
                if (mt_set[i] == ISIS_MT_IPV4_UNICAST) {
-                       listnode_add(tlvs->te_is_neighs, ne_copy);
                        lsp_debug(
                                "ISIS (%s): Adding %s.%02x as te-style neighbor",
-                               area->area_tag, sysid_print(ne_copy->neigh_id),
-                               LSP_PSEUDO_ID(ne_copy->neigh_id));
+                               area->area_tag, sysid_print(id),
+                               LSP_PSEUDO_ID(id));
                } else {
-                       struct tlv_mt_neighbors *neighbors;
-
-                       neighbors = tlvs_get_mt_neighbors(tlvs, mtid);
-                       neighbors->list->del = free_tlv;
-                       listnode_add(neighbors->list, ne_copy);
                        lsp_debug(
                                "ISIS (%s): Adding %s.%02x as mt-style neighbor for %s",
-                               area->area_tag, sysid_print(ne_copy->neigh_id),
-                               LSP_PSEUDO_ID(ne_copy->neigh_id),
-                               isis_mtid2str(mtid));
+                               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);
        }
 }
 
-void tlvs_add_mt_bcast(struct tlvs *tlvs, struct isis_circuit *circuit,
-                      int level, struct te_is_neigh *neigh)
+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)
 {
        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, neigh);
+       tlvs_add_mt_set(circuit->area, tlvs, mt_count, mt_set, id, metric,
+                       subtlvs, subtlv_len);
 }
 
-void tlvs_add_mt_p2p(struct tlvs *tlvs, struct isis_circuit *circuit,
-                    struct te_is_neigh *neigh)
+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)
 {
        struct isis_adjacency *adj = circuit->u.p2p.neighbor;
 
-       tlvs_add_mt_set(circuit->area, tlvs, adj->mt_count, adj->mt_set, neigh);
+       tlvs_add_mt_set(circuit->area, tlvs, adj->mt_count, adj->mt_set, id,
+                       metric, subtlvs, subtlv_len);
 }
index eec089228ef989124926b673eed7ee7629a7a6ba..95aa99dba0bd6be1b87be4bb9028020b24512e70 100644 (file)
@@ -24,6 +24,7 @@
 
 #define ISIS_MT_MASK           0x0fff
 #define ISIS_MT_OL_MASK        0x8000
+#define ISIS_MT_AT_MASK        0x4000
 
 #define ISIS_MT_IPV4_UNICAST   0
 #define ISIS_MT_IPV4_MGMT      1
@@ -64,21 +65,6 @@ struct isis_circuit_mt_setting {
        bool enabled;
 };
 
-struct tlv_mt_neighbors {
-       ISIS_MT_INFO_FIELDS
-       struct list *list;
-};
-
-struct tlv_mt_ipv4_reachs {
-       ISIS_MT_INFO_FIELDS
-       struct list *list;
-};
-
-struct tlv_mt_ipv6_reachs {
-       ISIS_MT_INFO_FIELDS
-       struct list *list;
-};
-
 const char *isis_mtid2str(uint16_t mtid);
 uint16_t isis_str2mtid(const char *name);
 
@@ -87,27 +73,10 @@ struct isis_area;
 struct isis_circuit;
 struct tlvs;
 struct te_is_neigh;
+struct isis_tlvs;
 
 uint16_t isis_area_ipv6_topology(struct isis_area *area);
 
-struct mt_router_info *tlvs_lookup_mt_router_info(struct tlvs *tlvs,
-                                                 uint16_t mtid);
-
-struct tlv_mt_neighbors *tlvs_lookup_mt_neighbors(struct tlvs *tlvs,
-                                                 uint16_t mtid);
-struct tlv_mt_neighbors *tlvs_get_mt_neighbors(struct tlvs *tlvs,
-                                              uint16_t mtid);
-
-struct tlv_mt_ipv4_reachs *tlvs_lookup_mt_ipv4_reachs(struct tlvs *tlvs,
-                                                     uint16_t mtid);
-struct tlv_mt_ipv4_reachs *tlvs_get_mt_ipv4_reachs(struct tlvs *tlvs,
-                                                  uint16_t mtid);
-
-struct tlv_mt_ipv6_reachs *tlvs_lookup_mt_ipv6_reachs(struct tlvs *tlvs,
-                                                     uint16_t mtid);
-struct tlv_mt_ipv6_reachs *tlvs_get_mt_ipv6_reachs(struct tlvs *tlvs,
-                                                  uint16_t mtid);
-
 struct isis_area_mt_setting *area_lookup_mt_setting(struct isis_area *area,
                                                    uint16_t mtid);
 struct isis_area_mt_setting *area_new_mt_setting(struct isis_area *area,
@@ -137,12 +106,14 @@ circuit_get_mt_setting(struct isis_circuit *circuit, uint16_t mtid);
 int circuit_write_mt_settings(struct isis_circuit *circuit, struct vty *vty);
 struct isis_circuit_mt_setting **
 circuit_mt_settings(struct isis_circuit *circuit, unsigned int *mt_count);
-bool tlvs_to_adj_mt_set(struct tlvs *tlvs, bool v4_usable, bool v6_usable,
+bool tlvs_to_adj_mt_set(struct isis_tlvs *tlvs, bool v4_usable, bool v6_usable,
                        struct isis_adjacency *adj);
 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 tlvs *tlvs, struct isis_circuit *circuit,
-                      int level, struct te_is_neigh *neigh);
-void tlvs_add_mt_p2p(struct tlvs *tlvs, struct isis_circuit *circuit,
-                    struct te_is_neigh *neigh);
+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);
+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);
 #endif
index a3706179a6b305a06f66d16c5025ac90e4f02835..17ef8935d8d4e3fe5815f1bd12a4824af35073a2 100644 (file)
@@ -44,7 +44,6 @@
 #include "isisd/isis_network.h"
 #include "isisd/isis_misc.h"
 #include "isisd/isis_dr.h"
-#include "isisd/isis_tlv.h"
 #include "isisd/isisd.h"
 #include "isisd/isis_dynhn.h"
 #include "isisd/isis_lsp.h"
 #include "isisd/isis_events.h"
 #include "isisd/isis_te.h"
 #include "isisd/isis_mt.h"
+#include "isisd/isis_tlvs.h"
 
-#define ISIS_MINIMUM_FIXED_HDR_LEN 15
-#define ISIS_MIN_PDU_LEN           13  /* partial seqnum pdu with id_len=2 */
-
-#ifndef PNBBY
-#define PNBBY 8
-#endif /* PNBBY */
-
-/*
- * HELPER FUNCS
- */
-
-/*
- * Compares two sets of area addresses
- */
-static int area_match(struct list *left, struct list *right)
-{
-       struct area_addr *addr1, *addr2;
-       struct listnode *node1, *node2;
-
-       for (ALL_LIST_ELEMENTS_RO(left, node1, addr1)) {
-               for (ALL_LIST_ELEMENTS_RO(right, node2, addr2)) {
-                       if (addr1->addr_len == addr2->addr_len
-                           && !memcmp(addr1->area_addr, addr2->area_addr,
-                                      (int)addr1->addr_len))
-                               return 1; /* match */
-               }
-       }
-
-       return 0; /* mismatch */
-}
-
-/*
- * Checks whether we should accept a PDU of given level
- */
-static int accept_level(int level, int circuit_t)
-{
-       int retval = ((circuit_t & level) == level); /* simple approach */
-
-       return retval;
-}
-
-/*
- * Verify authentication information
- * Support cleartext and HMAC MD5 authentication
- */
-static int authentication_check(struct isis_passwd *remote,
-                               struct isis_passwd *local,
-                               struct stream *stream, uint32_t auth_tlv_offset)
+static int ack_lsp(struct isis_lsp_hdr *hdr, struct isis_circuit *circuit,
+                  int level)
 {
-       unsigned char digest[ISIS_AUTH_MD5_SIZE];
-
-       /* Auth fail () - passwd type mismatch */
-       if (local->type != remote->type)
-               return ISIS_ERROR;
-
-       switch (local->type) {
-       /* No authentication required */
-       case ISIS_PASSWD_TYPE_UNUSED:
-               break;
-
-       /* Cleartext (ISO 10589) */
-       case ISIS_PASSWD_TYPE_CLEARTXT:
-               /* Auth fail () - passwd len mismatch */
-               if (remote->len != local->len)
-                       return ISIS_ERROR;
-               return memcmp(local->passwd, remote->passwd, local->len);
-
-       /* HMAC MD5 (RFC 3567) */
-       case ISIS_PASSWD_TYPE_HMAC_MD5:
-               /* Auth fail () - passwd len mismatch */
-               if (remote->len != ISIS_AUTH_MD5_SIZE)
-                       return ISIS_ERROR;
-               /* Set the authentication value to 0 before the check */
-               memset(STREAM_DATA(stream) + auth_tlv_offset + 3, 0,
-                      ISIS_AUTH_MD5_SIZE);
-               /* Compute the digest */
-               hmac_md5(STREAM_DATA(stream), stream_get_endp(stream),
-                        (unsigned char *)&(local->passwd), local->len,
-                        (unsigned char *)&digest);
-               /* Copy back the authentication value after the check */
-               memcpy(STREAM_DATA(stream) + auth_tlv_offset + 3,
-                      remote->passwd, ISIS_AUTH_MD5_SIZE);
-               return memcmp(digest, remote->passwd, ISIS_AUTH_MD5_SIZE);
+       unsigned long lenp;
+       int retval;
+       u_int16_t length;
+       uint8_t pdu_type =
+               (level == IS_LEVEL_1) ? L1_PARTIAL_SEQ_NUM : L2_PARTIAL_SEQ_NUM;
 
-       default:
-               zlog_err("Unsupported authentication type");
-               return ISIS_ERROR;
-       }
+       isis_circuit_stream(circuit, &circuit->snd_stream);
 
-       /* Authentication pass when no authentication is configured */
-       return ISIS_OK;
-}
+       fill_fixed_hdr(pdu_type, circuit->snd_stream);
 
-static int lsp_authentication_check(struct stream *stream,
-                                   struct isis_area *area, int level,
-                                   struct isis_passwd *passwd)
-{
-       struct isis_link_state_hdr *hdr;
-       uint32_t expected = 0, found = 0, auth_tlv_offset = 0;
-       uint16_t checksum, rem_lifetime, pdu_len;
-       struct tlvs tlvs;
-       int retval = ISIS_OK;
-
-       hdr = (struct isis_link_state_hdr *)(STREAM_PNT(stream));
-       pdu_len = ntohs(hdr->pdu_len);
-       expected |= TLVFLAG_AUTH_INFO;
-       auth_tlv_offset = stream_get_getp(stream) + ISIS_LSP_HDR_LEN;
-       retval = parse_tlvs(area->area_tag,
-                           STREAM_PNT(stream) + ISIS_LSP_HDR_LEN,
-                           pdu_len - ISIS_FIXED_HDR_LEN - ISIS_LSP_HDR_LEN,
-                           &expected, &found, &tlvs, &auth_tlv_offset);
+       lenp = stream_get_endp(circuit->snd_stream);
+       stream_putw(circuit->snd_stream, 0); /* PDU length  */
+       stream_put(circuit->snd_stream, isis->sysid, ISIS_SYS_ID_LEN);
+       stream_putc(circuit->snd_stream, circuit->idx);
+       stream_putc(circuit->snd_stream, 9);  /* code */
+       stream_putc(circuit->snd_stream, 16); /* len */
 
-       if (retval != ISIS_OK) {
-               zlog_err(
-                       "ISIS-Upd (%s): Parse failed L%d LSP %s, seq 0x%08x, "
-                       "cksum 0x%04x, lifetime %us, len %u",
-                       area->area_tag, level, rawlspid_print(hdr->lsp_id),
-                       ntohl(hdr->seq_num), ntohs(hdr->checksum),
-                       ntohs(hdr->rem_lifetime), pdu_len);
-               if ((isis->debugs & DEBUG_UPDATE_PACKETS)
-                   && (isis->debugs & DEBUG_PACKET_DUMP))
-                       zlog_dump_data(STREAM_DATA(stream),
-                                      stream_get_endp(stream));
-               return retval;
-       }
-
-       if (!(found & TLVFLAG_AUTH_INFO)) {
-               zlog_err("No authentication tlv in LSP");
-               return ISIS_ERROR;
-       }
+       stream_putw(circuit->snd_stream, hdr->rem_lifetime);
+       stream_put(circuit->snd_stream, hdr->lsp_id, ISIS_SYS_ID_LEN + 2);
+       stream_putl(circuit->snd_stream, hdr->seqno);
+       stream_putw(circuit->snd_stream, hdr->checksum);
 
-       if (tlvs.auth_info.type != ISIS_PASSWD_TYPE_CLEARTXT
-           && tlvs.auth_info.type != ISIS_PASSWD_TYPE_HMAC_MD5) {
-               zlog_err("Unknown authentication type in LSP");
-               return ISIS_ERROR;
-       }
+       length = (u_int16_t)stream_get_endp(circuit->snd_stream);
+       /* Update PDU length */
+       stream_putw_at(circuit->snd_stream, lenp, length);
 
-       /*
-        * RFC 5304 set checksum and remaining lifetime to zero before
-        * verification and reset to old values after verification.
-        */
-       checksum = hdr->checksum;
-       rem_lifetime = hdr->rem_lifetime;
-       hdr->checksum = 0;
-       hdr->rem_lifetime = 0;
-       retval = authentication_check(&tlvs.auth_info, passwd, stream,
-                                     auth_tlv_offset);
-       hdr->checksum = checksum;
-       hdr->rem_lifetime = rem_lifetime;
+       retval = circuit->tx(circuit, level);
+       if (retval != ISIS_OK)
+               zlog_err("ISIS-Upd (%s): Send L%d LSP PSNP on %s failed",
+                        circuit->area->area_tag, level,
+                        circuit->interface->name);
 
        return retval;
 }
 
-/*
- * Processing helper functions
- */
-static void del_addr(void *val)
-{
-       XFREE(MTYPE_ISIS_TMP, val);
-}
-
-static void tlvs_to_adj_area_addrs(struct tlvs *tlvs,
-                                  struct isis_adjacency *adj)
-{
-       struct listnode *node;
-       struct area_addr *area_addr, *malloced;
-
-       if (adj->area_addrs) {
-               adj->area_addrs->del = del_addr;
-               list_delete(adj->area_addrs);
-       }
-       adj->area_addrs = list_new();
-       if (tlvs->area_addrs) {
-               for (ALL_LIST_ELEMENTS_RO(tlvs->area_addrs, node, area_addr)) {
-                       malloced = XMALLOC(MTYPE_ISIS_TMP,
-                                          sizeof(struct area_addr));
-                       memcpy(malloced, area_addr, sizeof(struct area_addr));
-                       listnode_add(adj->area_addrs, malloced);
-               }
-       }
-}
-
-static int tlvs_to_adj_nlpids(struct tlvs *tlvs, struct isis_adjacency *adj)
-{
-       int i;
-       struct nlpids *tlv_nlpids;
-
-       if (tlvs->nlpids) {
-
-               tlv_nlpids = tlvs->nlpids;
-               if (tlv_nlpids->count > array_size(adj->nlpids.nlpids))
-                       return 1;
-
-               adj->nlpids.count = tlv_nlpids->count;
-
-               for (i = 0; i < tlv_nlpids->count; i++) {
-                       adj->nlpids.nlpids[i] = tlv_nlpids->nlpids[i];
-               }
-       }
-       return 0;
-}
-
-static void tlvs_to_adj_ipv4_addrs(struct tlvs *tlvs,
-                                  struct isis_adjacency *adj)
-{
-       struct listnode *node;
-       struct in_addr *ipv4_addr, *malloced;
-
-       if (adj->ipv4_addrs) {
-               adj->ipv4_addrs->del = del_addr;
-               list_delete(adj->ipv4_addrs);
-       }
-       adj->ipv4_addrs = list_new();
-       if (tlvs->ipv4_addrs) {
-               for (ALL_LIST_ELEMENTS_RO(tlvs->ipv4_addrs, node, ipv4_addr)) {
-                       malloced =
-                               XMALLOC(MTYPE_ISIS_TMP, sizeof(struct in_addr));
-                       memcpy(malloced, ipv4_addr, sizeof(struct in_addr));
-                       listnode_add(adj->ipv4_addrs, malloced);
-               }
-       }
-}
-
-static void tlvs_to_adj_ipv6_addrs(struct tlvs *tlvs,
-                                  struct isis_adjacency *adj)
-{
-       struct listnode *node;
-       struct in6_addr *ipv6_addr, *malloced;
-
-       if (adj->ipv6_addrs) {
-               adj->ipv6_addrs->del = del_addr;
-               list_delete(adj->ipv6_addrs);
-       }
-       adj->ipv6_addrs = list_new();
-       if (tlvs->ipv6_addrs) {
-               for (ALL_LIST_ELEMENTS_RO(tlvs->ipv6_addrs, node, ipv6_addr)) {
-                       malloced = XMALLOC(MTYPE_ISIS_TMP,
-                                          sizeof(struct in6_addr));
-                       memcpy(malloced, ipv6_addr, sizeof(struct in6_addr));
-                       listnode_add(adj->ipv6_addrs, malloced);
-               }
-       }
-}
-
 /*
  *  RECEIVE SIDE
  */
 
-/*
- * Process P2P IIH
- * ISO - 10589
- * Section 8.2.5 - Receiving point-to-point IIH PDUs
- *
- */
-static int process_p2p_hello(struct isis_circuit *circuit)
-{
-       int retval = ISIS_OK;
-       struct isis_p2p_hello_hdr *hdr;
-       struct isis_adjacency *adj;
-       u_int32_t expected = 0, found = 0, auth_tlv_offset = 0;
-       uint16_t pdu_len;
-       struct tlvs tlvs;
-       int v4_usable = 0, v6_usable = 0;
-
-       if (isis->debugs & DEBUG_ADJ_PACKETS) {
-               zlog_debug(
-                       "ISIS-Adj (%s): Rcvd P2P IIH on %s, cirType %s, cirID %u",
-                       circuit->area->area_tag, circuit->interface->name,
-                       circuit_t2string(circuit->is_type),
-                       circuit->circuit_id);
-               if (isis->debugs & DEBUG_PACKET_DUMP)
-                       zlog_dump_data(STREAM_DATA(circuit->rcv_stream),
-                                      stream_get_endp(circuit->rcv_stream));
-       }
-
-       if (circuit->circ_type != CIRCUIT_T_P2P) {
-               zlog_warn("p2p hello on non p2p circuit");
-               return ISIS_WARNING;
-       }
-
-       if ((stream_get_endp(circuit->rcv_stream)
-            - stream_get_getp(circuit->rcv_stream))
-           < ISIS_P2PHELLO_HDRLEN) {
-               zlog_warn("Packet too short");
-               return ISIS_WARNING;
-       }
-
-       /* 8.2.5.1 PDU acceptance tests */
-
-       /* 8.2.5.1 a) external domain untrue */
-       /* FIXME: not useful at all?         */
-
-       /* 8.2.5.1 b) ID Length mismatch */
-       /* checked at the handle_pdu     */
-
-       /* 8.2.5.2 IIH PDU Processing */
-
-       /* 8.2.5.2 a) 1) Maximum Area Addresses */
-       /* Already checked, and can also be ommited */
-
-       /*
-        * Get the header
-        */
-       hdr = (struct isis_p2p_hello_hdr *)STREAM_PNT(circuit->rcv_stream);
-       pdu_len = ntohs(hdr->pdu_len);
-
-       if (pdu_len < (ISIS_FIXED_HDR_LEN + ISIS_P2PHELLO_HDRLEN)
-           || pdu_len > ISO_MTU(circuit)
-           || pdu_len > stream_get_endp(circuit->rcv_stream)) {
-               zlog_warn(
-                       "ISIS-Adj (%s): Rcvd P2P IIH from (%s) with "
-                       "invalid pdu length %d",
-                       circuit->area->area_tag, circuit->interface->name,
-                       pdu_len);
-               return ISIS_WARNING;
-       }
-
-       /*
-        * Set the stream endp to PDU length, ignoring additional padding
-        * introduced by transport chips.
-        */
-       if (pdu_len < stream_get_endp(circuit->rcv_stream))
-               stream_set_endp(circuit->rcv_stream, pdu_len);
-
-       stream_forward_getp(circuit->rcv_stream, ISIS_P2PHELLO_HDRLEN);
-
-       /*
-        * Lets get the TLVS now
-        */
-       expected |= TLVFLAG_AREA_ADDRS;
-       expected |= TLVFLAG_AUTH_INFO;
-       expected |= TLVFLAG_NLPID;
-       expected |= TLVFLAG_IPV4_ADDR;
-       expected |= TLVFLAG_IPV6_ADDR;
-       expected |= TLVFLAG_MT_ROUTER_INFORMATION;
-
-       auth_tlv_offset = stream_get_getp(circuit->rcv_stream);
-       retval = parse_tlvs(circuit->area->area_tag,
-                           STREAM_PNT(circuit->rcv_stream),
-                           pdu_len - ISIS_P2PHELLO_HDRLEN - ISIS_FIXED_HDR_LEN,
-                           &expected, &found, &tlvs, &auth_tlv_offset);
-
-       if (retval > ISIS_WARNING) {
-               zlog_warn("parse_tlvs() failed");
-               free_tlvs(&tlvs);
-               return retval;
-       };
-
-       if (!(found & TLVFLAG_AREA_ADDRS)) {
-               zlog_warn("No Area addresses TLV in P2P IS to IS hello");
-               free_tlvs(&tlvs);
-               return ISIS_WARNING;
-       }
-
-       if (!(found & TLVFLAG_NLPID)) {
-               zlog_warn("No supported protocols TLV in P2P IS to IS hello");
-               free_tlvs(&tlvs);
-               return ISIS_WARNING;
-       }
-
-       /* 8.2.5.1 c) Authentication */
-       if (circuit->passwd.type) {
-               if (!(found & TLVFLAG_AUTH_INFO)
-                   || authentication_check(&tlvs.auth_info, &circuit->passwd,
-                                           circuit->rcv_stream,
-                                           auth_tlv_offset)) {
-                       isis_event_auth_failure(
-                               circuit->area->area_tag,
-                               "P2P hello authentication failure",
-                               hdr->source_id);
-                       free_tlvs(&tlvs);
-                       return ISIS_OK;
-               }
-       }
+struct iih_info {
+       struct isis_circuit *circuit;
+       u_char *ssnpa;
+       int level;
 
-       /*
-        * check if both ends have an IPv4 address
-        */
-       if (circuit->ip_addrs && listcount(circuit->ip_addrs) && tlvs.ipv4_addrs
-           && listcount(tlvs.ipv4_addrs)) {
-               v4_usable = 1;
-       }
-
-       if (found & TLVFLAG_IPV6_ADDR) {
-               /* TBA: check that we have a linklocal ourselves? */
-               struct listnode *node;
-               struct in6_addr *ip;
-               for (ALL_LIST_ELEMENTS_RO(tlvs.ipv6_addrs, node, ip))
-                       if (IN6_IS_ADDR_LINKLOCAL(ip)) {
-                               v6_usable = 1;
-                               break;
-                       }
+       uint8_t circ_type;
+       uint8_t sys_id[ISIS_SYS_ID_LEN];
+       uint16_t holdtime;
+       uint16_t pdu_len;
 
-               if (!v6_usable)
-                       zlog_warn(
-                               "ISIS-Adj: IPv6 addresses present but no link-local "
-                               "in P2P IIH from %s\n",
-                               circuit->interface->name);
-       }
+       uint8_t circuit_id;
 
-       if (!(found & (TLVFLAG_IPV4_ADDR | TLVFLAG_IPV6_ADDR)))
-               zlog_warn(
-                       "ISIS-Adj: neither IPv4 nor IPv6 addr in P2P IIH from %s\n",
-                       circuit->interface->name);
+       uint8_t priority;
+       uint8_t dis[ISIS_SYS_ID_LEN + 1];
 
-       if (!v6_usable && !v4_usable) {
-               free_tlvs(&tlvs);
-               return ISIS_WARNING;
-       }
+       bool v4_usable;
+       bool v6_usable;
 
-       /*
-        * it's own p2p IIH PDU - discard
-        */
-       if (!memcmp(hdr->source_id, isis->sysid, ISIS_SYS_ID_LEN)) {
-               zlog_warn("ISIS-Adj (%s): it's own IIH PDU - discarded",
-                         circuit->area->area_tag);
-               free_tlvs(&tlvs);
-               return ISIS_WARNING;
-       }
+       struct isis_tlvs *tlvs;
+};
 
+static int process_p2p_hello(struct iih_info *iih)
+{
        /*
         * My interpertation of the ISO, if no adj exists we will create one for
         * the circuit
         */
-       adj = circuit->u.p2p.neighbor;
+       struct isis_adjacency *adj = iih->circuit->u.p2p.neighbor;
        /* If an adjacency exists, check it is with the source of the hello
         * packets */
        if (adj) {
-               if (memcmp(hdr->source_id, adj->sysid, ISIS_SYS_ID_LEN)) {
+               if (memcmp(iih->sys_id, adj->sysid, ISIS_SYS_ID_LEN)) {
                        zlog_debug(
                                "hello source and adjacency do not match, set adj down\n");
                        isis_adj_state_change(adj, ISIS_ADJ_DOWN,
                                              "adj do not exist");
-                       return 0;
+                       return ISIS_OK;
                }
        }
-       if (!adj || adj->level != hdr->circuit_t) {
+       if (!adj || adj->level != iih->circ_type) {
                if (!adj) {
-                       adj = isis_new_adj(hdr->source_id, NULL, hdr->circuit_t,
-                                          circuit);
-                       if (adj == NULL)
-                               return ISIS_ERROR;
+                       adj = isis_new_adj(iih->sys_id, NULL, iih->circ_type,
+                                          iih->circuit);
                } else {
-                       adj->level = hdr->circuit_t;
+                       adj->level = iih->circ_type;
                }
-               circuit->u.p2p.neighbor = adj;
+               iih->circuit->u.p2p.neighbor = adj;
                /* Build lsp with the new neighbor entry when a new
                 * adjacency is formed. Set adjacency circuit type to
                 * IIH PDU header circuit type before lsp is regenerated
                 * when an adjacency is up. This will result in the new
                 * adjacency entry getting added to the lsp tlv neighbor list.
                 */
-               adj->circuit_t = hdr->circuit_t;
+               adj->circuit_t = iih->circ_type;
                isis_adj_state_change(adj, ISIS_ADJ_INITIALIZING, NULL);
                adj->sys_type = ISIS_SYSTYPE_UNKNOWN;
        }
 
        /* 8.2.6 Monitoring point-to-point adjacencies */
-       adj->hold_time = ntohs(hdr->hold_time);
+       adj->hold_time = iih->holdtime;
        adj->last_upd = time(NULL);
 
-       /* we do this now because the adj may not survive till the end... */
-       tlvs_to_adj_area_addrs(&tlvs, adj);
-
-       /* which protocol are spoken ??? */
-       if (tlvs_to_adj_nlpids(&tlvs, adj)) {
-               free_tlvs(&tlvs);
-               return ISIS_WARNING;
-       }
-
-       /* we need to copy addresses to the adj */
-       if (found & TLVFLAG_IPV4_ADDR)
-               tlvs_to_adj_ipv4_addrs(&tlvs, adj);
+       bool changed;
+       isis_tlvs_to_adj(iih->tlvs, adj, &changed);
+       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(isisMplsTE) && circuit->mtc
-           && IS_CIRCUIT_TE(circuit->mtc))
-               if (adj->ipv4_addrs != NULL
-                   && listcount(adj->ipv4_addrs) != 0) {
-                       struct in_addr *ip_addr;
-                       ip_addr = (struct in_addr *)listgetdata(
-                               (struct listnode *)listhead(adj->ipv4_addrs));
-                       set_circuitparams_rmt_ipaddr(circuit->mtc, *ip_addr);
-               }
-
-       if (found & TLVFLAG_IPV6_ADDR)
-               tlvs_to_adj_ipv6_addrs(&tlvs, adj);
-
-       bool mt_set_changed =
-               tlvs_to_adj_mt_set(&tlvs, v4_usable, v6_usable, adj);
+       if (IS_MPLS_TE(isisMplsTE) && iih->circuit->mtc
+           && IS_CIRCUIT_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);
@@ -552,10 +176,11 @@ static int process_p2p_hello(struct isis_circuit *circuit)
                         &adj->t_expire);
 
        /* 8.2.5.2 a) a match was detected */
-       if (area_match(circuit->area->area_addrs, tlvs.area_addrs)) {
+       if (isis_tlvs_area_addresses_match(iih->tlvs,
+                                          iih->circuit->area->area_addrs)) {
                /* 8.2.5.2 a) 2) If the system is L1 - table 5 */
-               if (circuit->area->is_type == IS_LEVEL_1) {
-                       switch (hdr->circuit_t) {
+               if (iih->circuit->area->is_type == IS_LEVEL_1) {
+                       switch (iih->circ_type) {
                        case IS_LEVEL_1:
                        case IS_LEVEL_1_AND_2:
                                if (adj->adj_state != ISIS_ADJ_UP) {
@@ -573,8 +198,7 @@ static int process_p2p_hello(struct isis_circuit *circuit)
                                        /* (7) reject - wrong system type event
                                         */
                                        zlog_warn("wrongSystemType");
-                                       free_tlvs(&tlvs);
-                                       return ISIS_WARNING; /* Reject */
+                                       return ISIS_WARNING;
                                } else if (adj->adj_usage == ISIS_ADJ_LEVEL1) {
                                        /* (6) down - wrong system */
                                        isis_adj_state_change(adj,
@@ -586,8 +210,8 @@ static int process_p2p_hello(struct isis_circuit *circuit)
                }
 
                /* 8.2.5.2 a) 3) If the system is L1L2 - table 6 */
-               if (circuit->area->is_type == IS_LEVEL_1_AND_2) {
-                       switch (hdr->circuit_t) {
+               if (iih->circuit->area->is_type == IS_LEVEL_1_AND_2) {
+                       switch (iih->circ_type) {
                        case IS_LEVEL_1:
                                if (adj->adj_state != ISIS_ADJ_UP) {
                                        /* (6) adj state up */
@@ -648,15 +272,14 @@ static int process_p2p_hello(struct isis_circuit *circuit)
                }
 
                /* 8.2.5.2 a) 4) If the system is L2 - table 7 */
-               if (circuit->area->is_type == IS_LEVEL_2) {
-                       switch (hdr->circuit_t) {
+               if (iih->circuit->area->is_type == IS_LEVEL_2) {
+                       switch (iih->circ_type) {
                        case IS_LEVEL_1:
                                if (adj->adj_state != ISIS_ADJ_UP) {
                                        /* (5) reject - wrong system type event
                                         */
                                        zlog_warn("wrongSystemType");
-                                       free_tlvs(&tlvs);
-                                       return ISIS_WARNING; /* Reject */
+                                       return ISIS_WARNING;
                                } else if ((adj->adj_usage
                                            == ISIS_ADJ_LEVEL1AND2)
                                           || (adj->adj_usage
@@ -689,8 +312,8 @@ static int process_p2p_hello(struct isis_circuit *circuit)
                }
        }
        /* 8.2.5.2 b) if no match was detected */
-       else if (listcount(circuit->area->area_addrs) > 0) {
-               if (circuit->area->is_type == IS_LEVEL_1) {
+       else if (listcount(iih->circuit->area->area_addrs) > 0) {
+               if (iih->circuit->area->is_type == IS_LEVEL_1) {
                        /* 8.2.5.2 b) 1) is_type L1 and adj is not up */
                        if (adj->adj_state != ISIS_ADJ_UP) {
                                isis_adj_state_change(adj, ISIS_ADJ_DOWN,
@@ -703,13 +326,12 @@ static int process_p2p_hello(struct isis_circuit *circuit)
                }
                /* 8.2.5.2 b 3 If the system is L2 or L1L2 - table 8 */
                else {
-                       switch (hdr->circuit_t) {
+                       switch (iih->circ_type) {
                        case IS_LEVEL_1:
                                if (adj->adj_state != ISIS_ADJ_UP) {
                                        /* (6) reject - Area Mismatch event */
                                        zlog_warn("AreaMismatch");
-                                       free_tlvs(&tlvs);
-                                       return ISIS_WARNING; /* Reject */
+                                       return ISIS_WARNING;
                                } else if (adj->adj_usage == ISIS_ADJ_LEVEL1) {
                                        /* (7) down - area mismatch */
                                        isis_adj_state_change(adj,
@@ -741,7 +363,7 @@ static int process_p2p_hello(struct isis_circuit *circuit)
                                                              "Wrong System");
                                } else if (adj->adj_usage
                                           == ISIS_ADJ_LEVEL1AND2) {
-                                       if (hdr->circuit_t == IS_LEVEL_2) {
+                                       if (iih->circ_type == IS_LEVEL_2) {
                                                /* (7) down - wrong system */
                                                isis_adj_state_change(
                                                        adj, ISIS_ADJ_DOWN,
@@ -763,7 +385,7 @@ static int process_p2p_hello(struct isis_circuit *circuit)
                isis_adj_state_change(adj, ISIS_ADJ_DOWN, "Area Mismatch");
        }
 
-       if (adj->adj_state == ISIS_ADJ_UP && mt_set_changed) {
+       if (adj->adj_state == ISIS_ADJ_UP && changed) {
                lsp_regenerate_schedule(adj->circuit->area,
                                        isis_adj_usage2levels(adj->adj_usage),
                                        0);
@@ -790,387 +412,269 @@ static int process_p2p_hello(struct isis_circuit *circuit)
                break;
        }
 
-
        if (isis->debugs & DEBUG_ADJ_PACKETS) {
                zlog_debug(
                        "ISIS-Adj (%s): Rcvd P2P IIH from (%s), cir type %s,"
                        " cir id %02d, length %d",
-                       circuit->area->area_tag, circuit->interface->name,
-                       circuit_t2string(circuit->is_type), circuit->circuit_id,
-                       pdu_len);
+                       iih->circuit->area->area_tag,
+                       iih->circuit->interface->name,
+                       circuit_t2string(iih->circuit->is_type),
+                       iih->circuit->circuit_id, iih->pdu_len);
        }
 
-       free_tlvs(&tlvs);
-
-       return retval;
+       return ISIS_OK;
 }
 
-/*
- * Process IS-IS LAN Level 1/2 Hello PDU
- */
-static int process_lan_hello(int level, struct isis_circuit *circuit,
-                            const u_char *ssnpa)
+static int process_lan_hello(struct iih_info *iih)
 {
-       int retval = ISIS_OK;
-       struct isis_lan_hello_hdr hdr;
        struct isis_adjacency *adj;
-       u_int32_t expected = 0, found = 0, auth_tlv_offset = 0;
-       struct tlvs tlvs;
-       u_char *snpa;
-       struct listnode *node;
-       int v4_usable = 0, v6_usable = 0;
-
-       if (isis->debugs & DEBUG_ADJ_PACKETS) {
-               zlog_debug(
-                       "ISIS-Adj (%s): Rcvd L%d LAN IIH on %s, cirType %s, "
-                       "cirID %u",
-                       circuit->area->area_tag, level,
-                       circuit->interface->name,
-                       circuit_t2string(circuit->is_type),
-                       circuit->circuit_id);
-               if (isis->debugs & DEBUG_PACKET_DUMP)
-                       zlog_dump_data(STREAM_DATA(circuit->rcv_stream),
-                                      stream_get_endp(circuit->rcv_stream));
-       }
-
-       if (circuit->circ_type != CIRCUIT_T_BROADCAST) {
-               zlog_warn("lan hello on non broadcast circuit");
-               return ISIS_WARNING;
-       }
-
-       if ((stream_get_endp(circuit->rcv_stream)
-            - stream_get_getp(circuit->rcv_stream))
-           < ISIS_LANHELLO_HDRLEN) {
-               zlog_warn("Packet too short");
-               return ISIS_WARNING;
-       }
-
-       if (circuit->ext_domain) {
-               zlog_debug(
-                       "level %d LAN Hello received over circuit with "
-                       "externalDomain = true",
-                       level);
-               return ISIS_WARNING;
-       }
-
-       if (!accept_level(level, circuit->is_type)) {
-               if (isis->debugs & DEBUG_ADJ_PACKETS) {
-                       zlog_debug(
-                               "ISIS-Adj (%s): Interface level mismatch, %s",
-                               circuit->area->area_tag,
-                               circuit->interface->name);
+       adj = isis_adj_lookup(iih->sys_id,
+                             iih->circuit->u.bc.adjdb[iih->level - 1]);
+       if ((adj == NULL) || (memcmp(adj->snpa, iih->ssnpa, ETH_ALEN))
+           || (adj->level != iih->level)) {
+               if (!adj) {
+                       /* Do as in 8.4.2.5 */
+                       adj = isis_new_adj(iih->sys_id, iih->ssnpa, iih->level,
+                                          iih->circuit);
+               } else {
+                       if (iih->ssnpa) {
+                               memcpy(adj->snpa, iih->ssnpa, 6);
+                       } else {
+                               memset(adj->snpa, ' ', 6);
+                       }
+                       adj->level = iih->level;
                }
-               return ISIS_WARNING;
-       }
+               isis_adj_state_change(adj, ISIS_ADJ_INITIALIZING, NULL);
 
-#if 0
-  /* Cisco's debug message compatability */
-  if (!accept_level (level, circuit->area->is_type))
-    {
-      if (isis->debugs & DEBUG_ADJ_PACKETS)
-       {
-         zlog_debug ("ISIS-Adj (%s): is type mismatch",
-                     circuit->area->area_tag);
+               if (iih->level == IS_LEVEL_1)
+                       adj->sys_type = ISIS_SYSTYPE_L1_IS;
+               else
+                       adj->sys_type = ISIS_SYSTYPE_L2_IS;
+               list_delete_all_node(
+                       iih->circuit->u.bc.lan_neighs[iih->level - 1]);
+               isis_adj_build_neigh_list(
+                       iih->circuit->u.bc.adjdb[iih->level - 1],
+                       iih->circuit->u.bc.lan_neighs[iih->level - 1]);
+       }
+
+       if (adj->dis_record[iih->level - 1].dis == ISIS_IS_DIS) {
+               u_char *dis = (iih->level == 1)
+                                     ? iih->circuit->u.bc.l1_desig_is
+                                     : iih->circuit->u.bc.l2_desig_is;
+
+               if (memcmp(dis, iih->dis, ISIS_SYS_ID_LEN + 1)) {
+                       thread_add_event(master, isis_event_dis_status_change,
+                                        iih->circuit, 0, NULL);
+                       memcpy(dis, iih->dis, ISIS_SYS_ID_LEN + 1);
+               }
        }
-      return ISIS_WARNING;
-    }
-#endif
-       /*
-        * Fill the header
-        */
-       hdr.circuit_t = stream_getc(circuit->rcv_stream);
-       stream_get(hdr.source_id, circuit->rcv_stream, ISIS_SYS_ID_LEN);
-       hdr.hold_time = stream_getw(circuit->rcv_stream);
-       hdr.pdu_len = stream_getw(circuit->rcv_stream);
-       hdr.prio = stream_getc(circuit->rcv_stream);
-       stream_get(hdr.lan_id, circuit->rcv_stream, ISIS_SYS_ID_LEN + 1);
 
-       if (hdr.pdu_len < (ISIS_FIXED_HDR_LEN + ISIS_LANHELLO_HDRLEN)
-           || hdr.pdu_len > ISO_MTU(circuit)
-           || hdr.pdu_len > stream_get_endp(circuit->rcv_stream)) {
-               zlog_warn(
-                       "ISIS-Adj (%s): Rcvd LAN IIH from (%s) with "
-                       "invalid pdu length %d",
-                       circuit->area->area_tag, circuit->interface->name,
-                       hdr.pdu_len);
-               return ISIS_WARNING;
-       }
+       adj->circuit_t = iih->circ_type;
+       adj->hold_time = iih->holdtime;
+       adj->last_upd = time(NULL);
+       adj->prio[iih->level - 1] = iih->priority;
+       memcpy(adj->lanid, iih->dis, ISIS_SYS_ID_LEN + 1);
 
-       /*
-        * Set the stream endp to PDU length, ignoring additional padding
-        * introduced by transport chips.
-        */
-       if (hdr.pdu_len < stream_get_endp(circuit->rcv_stream))
-               stream_set_endp(circuit->rcv_stream, hdr.pdu_len);
+       bool changed;
+       isis_tlvs_to_adj(iih->tlvs, adj, &changed);
+       changed |= tlvs_to_adj_mt_set(iih->tlvs, iih->v4_usable, iih->v6_usable,
+                                     adj);
 
-       if (hdr.circuit_t != IS_LEVEL_1 && hdr.circuit_t != IS_LEVEL_2
-           && hdr.circuit_t != IS_LEVEL_1_AND_2
-           && (level & hdr.circuit_t) == 0) {
-               zlog_err("Level %d LAN Hello with Circuit Type %d", level,
-                        hdr.circuit_t);
-               return ISIS_ERROR;
-       }
+       /* lets take care of the expiry */
+       THREAD_TIMER_OFF(adj->t_expire);
+       thread_add_timer(master, isis_adj_expire, adj, (long)adj->hold_time,
+                        &adj->t_expire);
 
        /*
-        * Then get the tlvs
+        * If the snpa for this circuit is found from LAN Neighbours TLV
+        * we have two-way communication -> adjacency can be put to state "up"
         */
-       expected |= TLVFLAG_AUTH_INFO;
-       expected |= TLVFLAG_AREA_ADDRS;
-       expected |= TLVFLAG_LAN_NEIGHS;
-       expected |= TLVFLAG_NLPID;
-       expected |= TLVFLAG_IPV4_ADDR;
-       expected |= TLVFLAG_IPV6_ADDR;
-       expected |= TLVFLAG_MT_ROUTER_INFORMATION;
-
-       auth_tlv_offset = stream_get_getp(circuit->rcv_stream);
-       retval = parse_tlvs(
-               circuit->area->area_tag, STREAM_PNT(circuit->rcv_stream),
-               hdr.pdu_len - ISIS_LANHELLO_HDRLEN - ISIS_FIXED_HDR_LEN,
-               &expected, &found, &tlvs, &auth_tlv_offset);
-
-       if (retval > ISIS_WARNING) {
-               zlog_warn("parse_tlvs() failed");
-               goto out;
-       }
-
-       if (!(found & TLVFLAG_AREA_ADDRS)) {
-               zlog_warn(
-                       "No Area addresses TLV in Level %d LAN IS to IS hello",
-                       level);
-               retval = ISIS_WARNING;
-               goto out;
-       }
-
-       if (!(found & TLVFLAG_NLPID)) {
-               zlog_warn(
-                       "No supported protocols TLV in Level %d LAN IS to IS hello",
-                       level);
-               retval = ISIS_WARNING;
-               goto out;
-       }
-
-       /* Verify authentication, either cleartext of HMAC MD5 */
-       if (circuit->passwd.type) {
-               if (!(found & TLVFLAG_AUTH_INFO)
-                   || authentication_check(&tlvs.auth_info, &circuit->passwd,
-                                           circuit->rcv_stream,
-                                           auth_tlv_offset)) {
-                       isis_event_auth_failure(
-                               circuit->area->area_tag,
-                               "LAN hello authentication failure",
-                               hdr.source_id);
-                       retval = ISIS_WARNING;
-                       goto out;
+       bool own_snpa_found =
+               isis_tlvs_own_snpa_found(iih->tlvs, iih->circuit->u.bc.snpa);
+
+       if (adj->adj_state != ISIS_ADJ_UP) {
+               if (own_snpa_found) {
+                       isis_adj_state_change(
+                               adj, ISIS_ADJ_UP,
+                               "own SNPA found in LAN Neighbours TLV");
                }
-       }
-
-       if (!memcmp(hdr.source_id, isis->sysid, ISIS_SYS_ID_LEN)) {
-               zlog_warn("ISIS-Adj (%s): duplicate system ID on interface %s",
-                         circuit->area->area_tag, circuit->interface->name);
-               return ISIS_WARNING;
-       }
-
-       /*
-        * Accept the level 1 adjacency only if a match between local and
-        * remote area addresses is found
-        */
-       if (listcount(circuit->area->area_addrs) == 0
-           || (level == IS_LEVEL_1
-               && area_match(circuit->area->area_addrs, tlvs.area_addrs)
-                          == 0)) {
-               if (isis->debugs & DEBUG_ADJ_PACKETS) {
-                       zlog_debug(
-                               "ISIS-Adj (%s): Area mismatch, level %d IIH on %s",
-                               circuit->area->area_tag, level,
-                               circuit->interface->name);
+       } else {
+               if (!own_snpa_found) {
+                       isis_adj_state_change(
+                               adj, ISIS_ADJ_INITIALIZING,
+                               "own SNPA not found in LAN Neighbours TLV");
                }
-               retval = ISIS_OK;
-               goto out;
        }
 
-       /*
-        * it's own IIH PDU - discard silently
-        */
-       if (!memcmp(circuit->u.bc.snpa, ssnpa, ETH_ALEN)) {
-               zlog_debug("ISIS-Adj (%s): it's own IIH PDU - discarded",
-                          circuit->area->area_tag);
+       if (adj->adj_state == ISIS_ADJ_UP && changed)
+               lsp_regenerate_schedule(adj->circuit->area, iih->level, 0);
 
-               retval = ISIS_OK;
-               goto out;
+       if (isis->debugs & DEBUG_ADJ_PACKETS) {
+               zlog_debug(
+                       "ISIS-Adj (%s): Rcvd L%d LAN IIH from %s on %s, cirType %s, cirID %u, length %zd",
+                       iih->circuit->area->area_tag, iih->level,
+                       snpa_print(iih->ssnpa), iih->circuit->interface->name,
+                       circuit_t2string(iih->circuit->is_type),
+                       iih->circuit->circuit_id,
+                       stream_get_endp(iih->circuit->rcv_stream));
        }
+       return ISIS_OK;
+}
 
-       /*
-        * check if both ends have an IPv4 address
-        */
-       if (circuit->ip_addrs && listcount(circuit->ip_addrs) && tlvs.ipv4_addrs
-           && listcount(tlvs.ipv4_addrs)) {
-               v4_usable = 1;
-       }
-
-       if (found & TLVFLAG_IPV6_ADDR) {
-               /* TBA: check that we have a linklocal ourselves? */
-               struct listnode *node;
-               struct in6_addr *ip;
-               for (ALL_LIST_ELEMENTS_RO(tlvs.ipv6_addrs, node, ip))
-                       if (IN6_IS_ADDR_LINKLOCAL(ip)) {
-                               v6_usable = 1;
-                               break;
-                       }
+static int pdu_len_validate(uint16_t pdu_len, struct isis_circuit *circuit)
+{
+       if (pdu_len < stream_get_getp(circuit->rcv_stream)
+           || pdu_len > ISO_MTU(circuit)
+           || pdu_len > stream_get_endp(circuit->rcv_stream))
+               return 1;
 
-               if (!v6_usable)
-                       zlog_warn(
-                               "ISIS-Adj: IPv6 addresses present but no link-local "
-                               "in LAN IIH from %s\n",
-                               circuit->interface->name);
-       }
+       if (pdu_len < stream_get_endp(circuit->rcv_stream))
+               stream_set_endp(circuit->rcv_stream, pdu_len);
+       return 0;
+}
 
-       if (!(found & (TLVFLAG_IPV4_ADDR | TLVFLAG_IPV6_ADDR)))
-               zlog_warn(
-                       "ISIS-Adj: neither IPv4 nor IPv6 addr in LAN IIH from %s\n",
-                       circuit->interface->name);
+static int process_hello(uint8_t pdu_type, struct isis_circuit *circuit,
+                        u_char *ssnpa)
+{
+       bool p2p_hello = (pdu_type == P2P_HELLO);
+       int level = p2p_hello ? 0
+                             : (pdu_type == L1_LAN_HELLO) ? ISIS_LEVEL1
+                                                          : ISIS_LEVEL2;
+       const char *pdu_name =
+               p2p_hello
+                       ? "P2P IIH"
+                       : (level == ISIS_LEVEL1) ? "L1 LAN IIH" : "L2 LAN IIH";
 
-       if (!v6_usable && !v4_usable) {
-               free_tlvs(&tlvs);
-               return ISIS_WARNING;
+       if (isis->debugs & DEBUG_ADJ_PACKETS) {
+               zlog_debug("ISIS-Adj (%s): Rcvd %s on %s, cirType %s, cirID %u",
+                          circuit->area->area_tag, pdu_name,
+                          circuit->interface->name,
+                          circuit_t2string(circuit->is_type),
+                          circuit->circuit_id);
+               if (isis->debugs & DEBUG_PACKET_DUMP)
+                       zlog_dump_data(STREAM_DATA(circuit->rcv_stream),
+                                      stream_get_endp(circuit->rcv_stream));
        }
 
+       if (p2p_hello) {
+               if (circuit->circ_type != CIRCUIT_T_P2P) {
+                       zlog_warn("p2p hello on non p2p circuit");
+                       return ISIS_WARNING;
+               }
+       } else {
+               if (circuit->circ_type != CIRCUIT_T_BROADCAST) {
+                       zlog_warn("lan hello on non broadcast circuit");
+                       return ISIS_WARNING;
+               }
 
-       adj = isis_adj_lookup(hdr.source_id, circuit->u.bc.adjdb[level - 1]);
-       if ((adj == NULL) || (memcmp(adj->snpa, ssnpa, ETH_ALEN))
-           || (adj->level != level)) {
-               if (!adj) {
-                       /*
-                        * Do as in 8.4.2.5
-                        */
-                       adj = isis_new_adj(hdr.source_id, ssnpa, level,
-                                          circuit);
-                       if (adj == NULL) {
-                               retval = ISIS_ERROR;
-                               goto out;
-                       }
-               } else {
-                       if (ssnpa) {
-                               memcpy(adj->snpa, ssnpa, 6);
-                       } else {
-                               memset(adj->snpa, ' ', 6);
-                       }
-                       adj->level = level;
+               if (circuit->ext_domain) {
+                       zlog_debug(
+                               "level %d LAN Hello received over circuit with externalDomain = true",
+                               level);
+                       return ISIS_WARNING;
                }
-               isis_adj_state_change(adj, ISIS_ADJ_INITIALIZING, NULL);
 
-               if (level == IS_LEVEL_1)
-                       adj->sys_type = ISIS_SYSTYPE_L1_IS;
-               else
-                       adj->sys_type = ISIS_SYSTYPE_L2_IS;
-               list_delete_all_node(circuit->u.bc.lan_neighs[level - 1]);
-               isis_adj_build_neigh_list(circuit->u.bc.adjdb[level - 1],
-                                         circuit->u.bc.lan_neighs[level - 1]);
-       }
-
-       if (adj->dis_record[level - 1].dis == ISIS_IS_DIS)
-               switch (level) {
-               case 1:
-                       if (memcmp(circuit->u.bc.l1_desig_is, hdr.lan_id,
-                                  ISIS_SYS_ID_LEN + 1)) {
-                               thread_add_event(master,
-                                                isis_event_dis_status_change,
-                                                circuit, 0, NULL);
-                               memcpy(&circuit->u.bc.l1_desig_is, hdr.lan_id,
-                                      ISIS_SYS_ID_LEN + 1);
-                       }
-                       break;
-               case 2:
-                       if (memcmp(circuit->u.bc.l2_desig_is, hdr.lan_id,
-                                  ISIS_SYS_ID_LEN + 1)) {
-                               thread_add_event(master,
-                                                isis_event_dis_status_change,
-                                                circuit, 0, NULL);
-                               memcpy(&circuit->u.bc.l2_desig_is, hdr.lan_id,
-                                      ISIS_SYS_ID_LEN + 1);
+               if (!(circuit->is_type & level)) {
+                       if (isis->debugs & DEBUG_ADJ_PACKETS) {
+                               zlog_debug(
+                                       "ISIS-Adj (%s): Interface level mismatch, %s",
+                                       circuit->area->area_tag,
+                                       circuit->interface->name);
                        }
-                       break;
+                       return ISIS_WARNING;
                }
+       }
 
-       adj->hold_time = hdr.hold_time;
-       adj->last_upd = time(NULL);
-       adj->prio[level - 1] = hdr.prio;
+       struct iih_info iih = {
+               .circuit = circuit, .ssnpa = ssnpa, .level = level};
 
-       memcpy(adj->lanid, hdr.lan_id, ISIS_SYS_ID_LEN + 1);
+       /* Generic IIH Header */
+       iih.circ_type = stream_getc(circuit->rcv_stream) & 0x03;
+       stream_get(iih.sys_id, circuit->rcv_stream, ISIS_SYS_ID_LEN);
+       iih.holdtime = stream_getw(circuit->rcv_stream);
+       iih.pdu_len = stream_getw(circuit->rcv_stream);
 
-       tlvs_to_adj_area_addrs(&tlvs, adj);
+       if (p2p_hello) {
+               iih.circuit_id = stream_getc(circuit->rcv_stream);
+       } else {
+               iih.priority = stream_getc(circuit->rcv_stream);
+               stream_get(iih.dis, circuit->rcv_stream, ISIS_SYS_ID_LEN + 1);
+       }
 
-       /* which protocol are spoken ??? */
-       if (tlvs_to_adj_nlpids(&tlvs, adj)) {
-               retval = ISIS_WARNING;
-               goto out;
+       if (pdu_len_validate(iih.pdu_len, circuit)) {
+               zlog_warn(
+                       "ISIS-Adj (%s): Rcvd %s from (%s) with invalid pdu length %" PRIu16,
+                       circuit->area->area_tag, pdu_name,
+                       circuit->interface->name, iih.pdu_len);
+               return ISIS_WARNING;
        }
 
-       /* we need to copy addresses to the adj */
-       if (found & TLVFLAG_IPV4_ADDR)
-               tlvs_to_adj_ipv4_addrs(&tlvs, adj);
+       if (!p2p_hello && !(level & iih.circ_type)) {
+               zlog_err("Level %d LAN Hello with Circuit Type %d", level,
+                        iih.circ_type);
+               return ISIS_ERROR;
+       }
 
-       if (found & TLVFLAG_IPV6_ADDR)
-               tlvs_to_adj_ipv6_addrs(&tlvs, adj);
+       const char *error_log;
+       int retval = ISIS_WARNING;
 
-       adj->circuit_t = hdr.circuit_t;
+       if (isis_unpack_tlvs(STREAM_READABLE(circuit->rcv_stream),
+                            circuit->rcv_stream, &iih.tlvs, &error_log)) {
+               zlog_warn("isis_unpack_tlvs() failed: %s", error_log);
+               goto out;
+       }
 
-       bool mt_set_changed =
-               tlvs_to_adj_mt_set(&tlvs, v4_usable, v6_usable, adj);
+       if (!iih.tlvs->area_addresses.count) {
+               zlog_warn("No Area addresses TLV in %s", pdu_name);
+               goto out;
+       }
 
-       /* lets take care of the expiry */
-       THREAD_TIMER_OFF(adj->t_expire);
-       thread_add_timer(master, isis_adj_expire, adj, (long)adj->hold_time,
-                        &adj->t_expire);
+       if (!iih.tlvs->protocols_supported.count) {
+               zlog_warn("No supported protocols TLV in %s", pdu_name);
+               goto out;
+       }
 
-       /*
-        * If the snpa for this circuit is found from LAN Neighbours TLV
-        * we have two-way communication -> adjacency can be put to state "up"
-        */
+       if (!isis_tlvs_auth_is_valid(iih.tlvs, &circuit->passwd,
+                                    circuit->rcv_stream, false)) {
+               isis_event_auth_failure(circuit->area->area_tag,
+                                       "IIH authentication failure",
+                                       iih.sys_id);
+               goto out;
+       }
 
-       if (found & TLVFLAG_LAN_NEIGHS) {
-               if (adj->adj_state != ISIS_ADJ_UP) {
-                       for (ALL_LIST_ELEMENTS_RO(tlvs.lan_neighs, node,
-                                                 snpa)) {
-                               if (!memcmp(snpa, circuit->u.bc.snpa,
-                                           ETH_ALEN)) {
-                                       isis_adj_state_change(
-                                               adj, ISIS_ADJ_UP,
-                                               "own SNPA found in LAN Neighbours TLV");
-                               }
-                       }
-               } else {
-                       int found = 0;
-                       for (ALL_LIST_ELEMENTS_RO(tlvs.lan_neighs, node, snpa))
-                               if (!memcmp(snpa, circuit->u.bc.snpa,
-                                           ETH_ALEN)) {
-                                       found = 1;
-                                       break;
-                               }
-                       if (found == 0)
-                               isis_adj_state_change(
-                                       adj, ISIS_ADJ_INITIALIZING,
-                                       "own SNPA not found in LAN Neighbours TLV");
+       if (!memcmp(iih.sys_id, isis->sysid, ISIS_SYS_ID_LEN)) {
+               zlog_warn(
+                       "ISIS-Adj (%s): Received IIH with own sysid - discard",
+                       circuit->area->area_tag);
+               goto out;
+       }
+
+       if (!p2p_hello
+           && (listcount(circuit->area->area_addrs) == 0
+               || (level == ISIS_LEVEL1
+                   && !isis_tlvs_area_addresses_match(
+                              iih.tlvs, circuit->area->area_addrs)))) {
+               if (isis->debugs & DEBUG_ADJ_PACKETS) {
+                       zlog_debug(
+                               "ISIS-Adj (%s): Area mismatch, level %d IIH on %s",
+                               circuit->area->area_tag, level,
+                               circuit->interface->name);
                }
-       } else if (adj->adj_state == ISIS_ADJ_UP) {
-               isis_adj_state_change(adj, ISIS_ADJ_INITIALIZING,
-                                     "no LAN Neighbours TLV found");
+               goto out;
        }
 
-       if (adj->adj_state == ISIS_ADJ_UP && mt_set_changed)
-               lsp_regenerate_schedule(adj->circuit->area, level, 0);
+       iih.v4_usable = (circuit->ip_addrs && listcount(circuit->ip_addrs)
+                        && iih.tlvs->ipv4_address.count);
 
-out:
-       if (isis->debugs & DEBUG_ADJ_PACKETS) {
-               zlog_debug(
-                       "ISIS-Adj (%s): Rcvd L%d LAN IIH from %s on %s, cirType %s, "
-                       "cirID %u, length %zd",
-                       circuit->area->area_tag, level, snpa_print(ssnpa),
-                       circuit->interface->name,
-                       circuit_t2string(circuit->is_type), circuit->circuit_id,
-                       stream_get_endp(circuit->rcv_stream));
-       }
+       iih.v6_usable = (circuit->ipv6_link && listcount(circuit->ipv6_link)
+                        && iih.tlvs->ipv6_address.count);
+
+       if (!iih.v4_usable && !iih.v6_usable)
+               goto out;
 
-       free_tlvs(&tlvs);
+       retval = p2p_hello ? process_p2p_hello(&iih) : process_lan_hello(&iih);
+out:
+       isis_free_tlvs(iih.tlvs);
 
        return retval;
 }
@@ -1180,17 +684,10 @@ out:
  * ISO - 10589
  * Section 7.3.15.1 - Action on receipt of a link state PDU
  */
-static int process_lsp(int level, struct isis_circuit *circuit,
+static int process_lsp(uint8_t pdu_type, struct isis_circuit *circuit,
                       const u_char *ssnpa)
 {
-       struct isis_link_state_hdr *hdr;
-       struct isis_adjacency *adj = NULL;
-       struct isis_lsp *lsp, *lsp0 = NULL;
-       int retval = ISIS_OK, comp = 0;
-       u_char lspid[ISIS_SYS_ID_LEN + 2];
-       struct isis_passwd *passwd;
-       uint16_t pdu_len;
-       int lsp_confusion;
+       int level = (pdu_type == L1_LINK_STATE) ? ISIS_LEVEL1 : ISIS_LEVEL2;
 
        if (isis->debugs & DEBUG_UPDATE_PACKETS) {
                zlog_debug(
@@ -1204,65 +701,50 @@ static int process_lsp(int level, struct isis_circuit *circuit,
                                       stream_get_endp(circuit->rcv_stream));
        }
 
-       if ((stream_get_endp(circuit->rcv_stream)
-            - stream_get_getp(circuit->rcv_stream))
-           < ISIS_LSP_HDR_LEN) {
-               zlog_warn("Packet too short");
-               return ISIS_WARNING;
-       }
-
-       /* Reference the header   */
-       hdr = (struct isis_link_state_hdr *)STREAM_PNT(circuit->rcv_stream);
-       pdu_len = ntohs(hdr->pdu_len);
-
-       /* lsp length check */
-       if (pdu_len < (ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN)
-           || pdu_len > ISO_MTU(circuit)
-           || pdu_len > stream_get_endp(circuit->rcv_stream)) {
-               zlog_debug("ISIS-Upd (%s): LSP %s invalid LSP length %d",
-                          circuit->area->area_tag, rawlspid_print(hdr->lsp_id),
-                          pdu_len);
+       struct isis_lsp_hdr hdr = {};
 
+       hdr.pdu_len = stream_getw(circuit->rcv_stream);
+       hdr.rem_lifetime = stream_getw(circuit->rcv_stream);
+       stream_get(hdr.lsp_id, circuit->rcv_stream, sizeof(hdr.lsp_id));
+       hdr.seqno = stream_getl(circuit->rcv_stream);
+       hdr.checksum = stream_getw(circuit->rcv_stream);
+       hdr.lsp_bits = stream_getc(circuit->rcv_stream);
+
+       if (pdu_len_validate(hdr.pdu_len, circuit)) {
+               zlog_debug("ISIS-Upd (%s): LSP %s invalid LSP length %" PRIu16,
+                          circuit->area->area_tag, rawlspid_print(hdr.lsp_id),
+                          hdr.pdu_len);
                return ISIS_WARNING;
        }
 
-       /*
-        * Set the stream endp to PDU length, ignoring additional padding
-        * introduced by transport chips.
-        */
-       if (pdu_len < stream_get_endp(circuit->rcv_stream))
-               stream_set_endp(circuit->rcv_stream, pdu_len);
-
        if (isis->debugs & DEBUG_UPDATE_PACKETS) {
-               zlog_debug(
-                       "ISIS-Upd (%s): Rcvd L%d LSP %s, seq 0x%08x, cksum 0x%04x, "
-                       "lifetime %us, len %u, on %s",
-                       circuit->area->area_tag, level,
-                       rawlspid_print(hdr->lsp_id), ntohl(hdr->seq_num),
-                       ntohs(hdr->checksum), ntohs(hdr->rem_lifetime), pdu_len,
-                       circuit->interface->name);
+               zlog_debug("ISIS-Upd (%s): Rcvd L%d LSP %s, seq 0x%08" PRIx32
+                          ", cksum 0x%04" PRIx16 ", lifetime %" PRIu16
+                          "s, len %" PRIu16 ", on %s",
+                          circuit->area->area_tag, level,
+                          rawlspid_print(hdr.lsp_id), hdr.seqno, hdr.checksum,
+                          hdr.rem_lifetime, hdr.pdu_len,
+                          circuit->interface->name);
        }
 
        /* lsp is_type check */
-       if ((hdr->lsp_bits & IS_LEVEL_1_AND_2) != IS_LEVEL_1
-           && (hdr->lsp_bits & IS_LEVEL_1_AND_2) != IS_LEVEL_1_AND_2) {
-               zlog_debug("ISIS-Upd (%s): LSP %s invalid LSP is type %x",
-                          circuit->area->area_tag, rawlspid_print(hdr->lsp_id),
-                          hdr->lsp_bits);
+       if ((hdr.lsp_bits & IS_LEVEL_1) != IS_LEVEL_1) {
+               zlog_debug(
+                       "ISIS-Upd (%s): LSP %s invalid LSP is type 0x%" PRIx8,
+                       circuit->area->area_tag, rawlspid_print(hdr.lsp_id),
+                       hdr.lsp_bits & IS_LEVEL_1_AND_2);
                /* continue as per RFC1122 Be liberal in what you accept, and
                 * conservative in what you send */
        }
 
        /* Checksum sanity check - FIXME: move to correct place */
        /* 12 = sysid+pdu+remtime */
-       if (iso_csum_verify(STREAM_PNT(circuit->rcv_stream) + 4, pdu_len - 12,
-                           hdr->checksum,
-                           offsetof(struct isis_link_state_hdr, checksum)
-                                   - 4)) {
-               zlog_debug("ISIS-Upd (%s): LSP %s invalid LSP checksum 0x%04x",
-                          circuit->area->area_tag, rawlspid_print(hdr->lsp_id),
-                          ntohs(hdr->checksum));
-
+       if (iso_csum_verify(STREAM_DATA(circuit->rcv_stream) + 12,
+                           hdr.pdu_len - 12, hdr.checksum, 12)) {
+               zlog_debug(
+                       "ISIS-Upd (%s): LSP %s invalid LSP checksum 0x%04" PRIx16,
+                       circuit->area->area_tag, rawlspid_print(hdr.lsp_id),
+                       hdr.checksum);
                return ISIS_WARNING;
        }
 
@@ -1271,46 +753,56 @@ static int process_lsp(int level, struct isis_circuit *circuit,
                zlog_debug(
                        "ISIS-Upd (%s): LSP %s received at level %d over circuit with "
                        "externalDomain = true",
-                       circuit->area->area_tag, rawlspid_print(hdr->lsp_id),
+                       circuit->area->area_tag, rawlspid_print(hdr.lsp_id),
                        level);
-
                return ISIS_WARNING;
        }
 
        /* 7.3.15.1 a) 2,3 - manualL2OnlyMode not implemented */
-       if (!accept_level(level, circuit->is_type)) {
+       if (!(circuit->is_type & level)) {
                zlog_debug(
                        "ISIS-Upd (%s): LSP %s received at level %d over circuit of"
                        " type %s",
-                       circuit->area->area_tag, rawlspid_print(hdr->lsp_id),
+                       circuit->area->area_tag, rawlspid_print(hdr.lsp_id),
                        level, circuit_t2string(circuit->is_type));
-
                return ISIS_WARNING;
        }
 
+       struct isis_tlvs *tlvs = NULL;
+       int retval = ISIS_WARNING;
+       const char *error_log;
+
+       if (isis_unpack_tlvs(STREAM_READABLE(circuit->rcv_stream),
+                            circuit->rcv_stream, &tlvs, &error_log)) {
+               zlog_warn("Something went wrong unpacking the LSP: %s",
+                         error_log);
+               goto out;
+       }
+
        /* 7.3.15.1 a) 4 - need to make sure IDLength matches */
 
        /* 7.3.15.1 a) 5 - maximum area match, can be ommited since we only use
         * 3 */
 
        /* 7.3.15.1 a) 7 - password check */
-       (level == IS_LEVEL_1) ? (passwd = &circuit->area->area_passwd)
-                             : (passwd = &circuit->area->domain_passwd);
-       if (passwd->type) {
-               if (lsp_authentication_check(circuit->rcv_stream, circuit->area,
-                                            level, passwd)) {
-                       isis_event_auth_failure(circuit->area->area_tag,
-                                               "LSP authentication failure",
-                                               hdr->lsp_id);
-                       return ISIS_WARNING;
-               }
+       struct isis_passwd *passwd = (level == ISIS_LEVEL1)
+                                            ? &circuit->area->area_passwd
+                                            : &circuit->area->domain_passwd;
+       if (!isis_tlvs_auth_is_valid(tlvs, passwd, circuit->rcv_stream, true)) {
+               isis_event_auth_failure(circuit->area->area_tag,
+                                       "LSP authentication failure",
+                                       hdr.lsp_id);
+               goto out;
        }
+
        /* Find the LSP in our database and compare it to this Link State header
         */
-       lsp = lsp_search(hdr->lsp_id, circuit->area->lspdb[level - 1]);
+       struct isis_lsp *lsp =
+               lsp_search(hdr.lsp_id, circuit->area->lspdb[level - 1]);
+       int comp = 0;
        if (lsp)
-               comp = lsp_compare(circuit->area->area_tag, lsp, hdr->seq_num,
-                                  hdr->checksum, hdr->rem_lifetime);
+               comp = lsp_compare(circuit->area->area_tag, lsp, hdr.seqno,
+                                  hdr.checksum, hdr.rem_lifetime);
        if (lsp && (lsp->own_lsp))
                goto dontcheckadj;
 
@@ -1319,25 +811,24 @@ static int process_lsp(int level, struct isis_circuit *circuit,
        /* for broadcast circuits, snpa should be compared */
 
        if (circuit->circ_type == CIRCUIT_T_BROADCAST) {
-               adj = isis_adj_lookup_snpa(ssnpa,
-                                          circuit->u.bc.adjdb[level - 1]);
-               if (!adj) {
-                       zlog_debug(
-                               "(%s): DS ======= LSP %s, seq 0x%08x, cksum 0x%04x, "
-                               "lifetime %us on %s",
-                               circuit->area->area_tag,
-                               rawlspid_print(hdr->lsp_id),
-                               ntohl(hdr->seq_num), ntohs(hdr->checksum),
-                               ntohs(hdr->rem_lifetime),
-                               circuit->interface->name);
-                       return ISIS_WARNING; /* Silently discard */
+               if (!isis_adj_lookup_snpa(ssnpa,
+                                         circuit->u.bc.adjdb[level - 1])) {
+                       zlog_debug("(%s): DS ======= LSP %s, seq 0x%08" PRIx32
+                                  ", cksum 0x%04" PRIx16 ", lifetime %" PRIu16
+                                  "s on %s",
+                                  circuit->area->area_tag,
+                                  rawlspid_print(hdr.lsp_id), hdr.seqno,
+                                  hdr.checksum, hdr.rem_lifetime,
+                                  circuit->interface->name);
+                       goto out; /* Silently discard */
                }
        }
        /* for non broadcast, we just need to find same level adj */
        else {
                /* If no adj, or no sharing of level */
                if (!circuit->u.p2p.neighbor) {
-                       return ISIS_OK; /* Silently discard */
+                       retval = ISIS_OK;
+                       goto out;
                } else {
                        if (((level == IS_LEVEL_1)
                             && (circuit->u.p2p.neighbor->adj_usage
@@ -1345,10 +836,12 @@ static int process_lsp(int level, struct isis_circuit *circuit,
                            || ((level == IS_LEVEL_2)
                                && (circuit->u.p2p.neighbor->adj_usage
                                    == ISIS_ADJ_LEVEL1)))
-                               return ISIS_WARNING; /* Silently discard */
+                               goto out;
                }
        }
 
+       bool lsp_confusion;
+
 dontcheckadj:
        /* 7.3.15.1 a) 7 - Passwords for level 1 - not implemented  */
 
@@ -1360,33 +853,36 @@ dontcheckadj:
        /* 7.3.16.2 - If this is an LSP from another IS with identical seq_num
         * but
         *            wrong checksum, initiate a purge. */
-       if (lsp && (lsp->lsp_header->seq_num == hdr->seq_num)
-           && (lsp->lsp_header->checksum != hdr->checksum)) {
-               zlog_warn(
-                       "ISIS-Upd (%s): LSP %s seq 0x%08x with confused checksum received.",
-                       circuit->area->area_tag, rawlspid_print(hdr->lsp_id),
-                       ntohl(hdr->seq_num));
-               hdr->rem_lifetime = 0;
-               lsp_confusion = 1;
+       if (lsp && (lsp->hdr.seqno == hdr.seqno)
+           && (lsp->hdr.checksum != hdr.checksum)) {
+               zlog_warn("ISIS-Upd (%s): LSP %s seq 0x%08" PRIx32
+                         " with confused checksum received.",
+                         circuit->area->area_tag, rawlspid_print(hdr.lsp_id),
+                         hdr.seqno);
+               hdr.rem_lifetime = 0;
+               lsp_confusion = true;
        } else
-               lsp_confusion = 0;
+               lsp_confusion = false;
 
        /* 7.3.15.1 b) - If the remaining life time is 0, we perform 7.3.16.4 */
-       if (hdr->rem_lifetime == 0) {
+       if (hdr.rem_lifetime == 0) {
                if (!lsp) {
                        /* 7.3.16.4 a) 1) No LSP in db -> send an ack, but don't
                         * save */
                        /* only needed on explicit update, eg - p2p */
                        if (circuit->circ_type == CIRCUIT_T_P2P)
-                               ack_lsp(hdr, circuit, level);
-                       return retval; /* FIXME: do we need a purge? */
+                               ack_lsp(&hdr, circuit, level);
+                       goto out; /* FIXME: do we need a purge? */
                } else {
-                       if (memcmp(hdr->lsp_id, isis->sysid, ISIS_SYS_ID_LEN)) {
+                       if (memcmp(hdr.lsp_id, isis->sysid, ISIS_SYS_ID_LEN)) {
                                /* LSP by some other system -> do 7.3.16.4 b) */
                                /* 7.3.16.4 b) 1)  */
                                if (comp == LSP_NEWER) {
-                                       lsp_update(lsp, circuit->rcv_stream,
-                                                  circuit->area, level);
+                                       lsp_update(lsp, &hdr, tlvs,
+                                                  circuit->rcv_stream,
+                                                  circuit->area, level,
+                                                  lsp_confusion);
+                                       tlvs = NULL;
                                        /* ii */
                                        lsp_set_all_srmflags(lsp);
                                        /* v */
@@ -1427,11 +923,10 @@ dontcheckadj:
                                        ISIS_SET_FLAG(lsp->SRMflags, circuit);
                                        ISIS_CLEAR_FLAG(lsp->SSNflags, circuit);
                                }
-                       } else if (lsp->lsp_header->rem_lifetime != 0) {
+                       } else if (lsp->hdr.rem_lifetime != 0) {
                                /* our own LSP -> 7.3.16.4 c) */
                                if (comp == LSP_NEWER) {
-                                       lsp_inc_seqnum(lsp,
-                                                      ntohl(hdr->seq_num));
+                                       lsp_inc_seqno(lsp, hdr.seqno);
                                        lsp_set_all_srmflags(lsp);
                                } else {
                                        ISIS_SET_FLAG(lsp->SRMflags, circuit);
@@ -1439,23 +934,22 @@ dontcheckadj:
                                }
                                if (isis->debugs & DEBUG_UPDATE_PACKETS)
                                        zlog_debug(
-                                               "ISIS-Upd (%s): (1) re-originating LSP %s new "
-                                               "seq 0x%08x",
+                                               "ISIS-Upd (%s): (1) re-originating LSP %s new seq 0x%08" PRIx32,
                                                circuit->area->area_tag,
-                                               rawlspid_print(hdr->lsp_id),
-                                               ntohl(lsp->lsp_header
-                                                             ->seq_num));
+                                               rawlspid_print(hdr.lsp_id),
+                                               lsp->hdr.seqno);
                        }
                }
-               return retval;
+               goto out;
        }
        /* 7.3.15.1 c) - If this is our own lsp and we don't have it initiate a
         * purge */
-       if (memcmp(hdr->lsp_id, isis->sysid, ISIS_SYS_ID_LEN) == 0) {
+       if (memcmp(hdr.lsp_id, isis->sysid, ISIS_SYS_ID_LEN) == 0) {
                if (!lsp) {
                        /* 7.3.16.4: initiate a purge */
-                       lsp_purge_non_exist(level, hdr, circuit->area);
-                       return ISIS_OK;
+                       lsp_purge_non_exist(level, &hdr, circuit->area);
+                       retval = ISIS_OK;
+                       goto out;
                }
                /* 7.3.15.1 d) - If this is our own lsp and we have it */
 
@@ -1465,16 +959,15 @@ dontcheckadj:
                 * is
                 * "greater" than that held by S, ... */
 
-               if (ntohl(hdr->seq_num) > ntohl(lsp->lsp_header->seq_num)) {
+               if (hdr.seqno > lsp->hdr.seqno) {
                        /* 7.3.16.1  */
-                       lsp_inc_seqnum(lsp, ntohl(hdr->seq_num));
+                       lsp_inc_seqno(lsp, hdr.seqno);
                        if (isis->debugs & DEBUG_UPDATE_PACKETS)
                                zlog_debug(
-                                       "ISIS-Upd (%s): (2) re-originating LSP %s new seq "
-                                       "0x%08x",
+                                       "ISIS-Upd (%s): (2) re-originating LSP %s new seq 0x%08" PRIx32,
                                        circuit->area->area_tag,
-                                       rawlspid_print(hdr->lsp_id),
-                                       ntohl(lsp->lsp_header->seq_num));
+                                       rawlspid_print(hdr.lsp_id),
+                                       lsp->hdr.seqno);
                }
                /* If the received LSP is older or equal,
                 * resend the LSP which will act as ACK */
@@ -1489,8 +982,10 @@ dontcheckadj:
                         * If this lsp is a frag, need to see if we have zero
                         * lsp present
                         */
-                       if (LSP_FRAGMENT(hdr->lsp_id) != 0) {
-                               memcpy(lspid, hdr->lsp_id, ISIS_SYS_ID_LEN + 1);
+                       struct isis_lsp *lsp0 = NULL;
+                       if (LSP_FRAGMENT(hdr.lsp_id) != 0) {
+                               uint8_t lspid[ISIS_SYS_ID_LEN + 2];
+                               memcpy(lspid, hdr.lsp_id, ISIS_SYS_ID_LEN + 1);
                                LSP_FRAGMENT(lspid) = 0;
                                lsp0 = lsp_search(
                                        lspid, circuit->area->lspdb[level - 1]);
@@ -1502,15 +997,17 @@ dontcheckadj:
                        }
                        /* i */
                        if (!lsp) {
-                               lsp = lsp_new_from_stream_ptr(
-                                       circuit->rcv_stream, pdu_len, lsp0,
+                               lsp = lsp_new_from_recv(
+                                       &hdr, tlvs, circuit->rcv_stream, lsp0,
                                        circuit->area, level);
+                               tlvs = NULL;
                                lsp_insert(lsp,
                                           circuit->area->lspdb[level - 1]);
                        } else /* exists, so we overwrite */
                        {
-                               lsp_update(lsp, circuit->rcv_stream,
-                                          circuit->area, level);
+                               lsp_update(lsp, &hdr, tlvs, circuit->rcv_stream,
+                                          circuit->area, level, false);
+                               tlvs = NULL;
                        }
                        /* ii */
                        lsp_set_all_srmflags(lsp);
@@ -1525,8 +1022,9 @@ dontcheckadj:
                /* 7.3.15.1 e) 2) LSP equal to the one in db */
                else if (comp == LSP_EQUAL) {
                        ISIS_CLEAR_FLAG(lsp->SRMflags, circuit);
-                       lsp_update(lsp, circuit->rcv_stream, circuit->area,
-                                  level);
+                       lsp_update(lsp, &hdr, tlvs, circuit->rcv_stream,
+                                  circuit->area, level, false);
+                       tlvs = NULL;
                        if (circuit->circ_type != CIRCUIT_T_BROADCAST)
                                ISIS_SET_FLAG(lsp->SSNflags, circuit);
                }
@@ -1536,6 +1034,11 @@ dontcheckadj:
                        ISIS_CLEAR_FLAG(lsp->SSNflags, circuit);
                }
        }
+
+       retval = ISIS_OK;
+
+out:
+       isis_free_tlvs(tlvs);
        return retval;
 }
 
@@ -1545,60 +1048,48 @@ dontcheckadj:
  * Section 7.3.15.2 - Action on receipt of a sequence numbers PDU
  */
 
-static int process_snp(int snp_type, int level, struct isis_circuit *circuit,
+static int process_snp(uint8_t pdu_type, struct isis_circuit *circuit,
                       const u_char *ssnpa)
 {
-       int retval = ISIS_OK;
-       int cmp, own_lsp;
-       char typechar = ' ';
-       uint16_t pdu_len;
-       struct isis_adjacency *adj;
-       struct isis_complete_seqnum_hdr *chdr = NULL;
-       struct isis_partial_seqnum_hdr *phdr = NULL;
-       uint32_t found = 0, expected = 0, auth_tlv_offset = 0;
-       struct isis_lsp *lsp;
-       struct lsp_entry *entry;
-       struct listnode *node, *nnode;
-       struct listnode *node2, *nnode2;
-       struct tlvs tlvs;
-       struct list *lsp_list = NULL;
-       struct isis_passwd *passwd;
-
-       if (snp_type == ISIS_SNP_CSNP_FLAG) {
-               /* getting the header info */
-               typechar = 'C';
-               chdr = (struct isis_complete_seqnum_hdr *)STREAM_PNT(
-                       circuit->rcv_stream);
-               stream_forward_getp(circuit->rcv_stream, ISIS_CSNP_HDRLEN);
-               pdu_len = ntohs(chdr->pdu_len);
-               if (pdu_len < (ISIS_FIXED_HDR_LEN + ISIS_CSNP_HDRLEN)
-                   || pdu_len > ISO_MTU(circuit)
-                   || pdu_len > stream_get_endp(circuit->rcv_stream)) {
-                       zlog_warn("Received a CSNP with bogus length %d",
-                                 pdu_len);
-                       return ISIS_WARNING;
-               }
-       } else {
-               typechar = 'P';
-               phdr = (struct isis_partial_seqnum_hdr *)STREAM_PNT(
-                       circuit->rcv_stream);
-               stream_forward_getp(circuit->rcv_stream, ISIS_PSNP_HDRLEN);
-               pdu_len = ntohs(phdr->pdu_len);
-               if (pdu_len < (ISIS_FIXED_HDR_LEN + ISIS_PSNP_HDRLEN)
-                   || pdu_len > ISO_MTU(circuit)
-                   || pdu_len > stream_get_endp(circuit->rcv_stream)) {
-                       zlog_warn("Received a PSNP with bogus length %d",
-                                 pdu_len);
-                       return ISIS_WARNING;
-               }
+       bool is_csnp = (pdu_type == L1_COMPLETE_SEQ_NUM
+                       || pdu_type == L2_COMPLETE_SEQ_NUM);
+       char typechar = is_csnp ? 'C' : 'P';
+       int level = (pdu_type == L1_COMPLETE_SEQ_NUM
+                    || pdu_type == L1_PARTIAL_SEQ_NUM)
+                           ? ISIS_LEVEL1
+                           : ISIS_LEVEL2;
+
+       uint16_t pdu_len = stream_getw(circuit->rcv_stream);
+       uint8_t rem_sys_id[ISIS_SYS_ID_LEN];
+       stream_get(rem_sys_id, circuit->rcv_stream, ISIS_SYS_ID_LEN);
+       stream_forward_getp(circuit->rcv_stream, 1); /* Circuit ID - unused */
+
+       uint8_t start_lsp_id[ISIS_SYS_ID_LEN + 2] = {};
+       uint8_t stop_lsp_id[ISIS_SYS_ID_LEN + 2] = {};
+
+       if (is_csnp) {
+               stream_get(start_lsp_id, circuit->rcv_stream,
+                          ISIS_SYS_ID_LEN + 2);
+               stream_get(stop_lsp_id, circuit->rcv_stream,
+                          ISIS_SYS_ID_LEN + 2);
+       }
+
+       if (pdu_len_validate(pdu_len, circuit)) {
+               zlog_warn("Received a CSNP with bogus length %d", pdu_len);
+               return ISIS_WARNING;
        }
 
-       /*
-        * Set the stream endp to PDU length, ignoring additional padding
-        * introduced by transport chips.
-        */
-       if (pdu_len < stream_get_endp(circuit->rcv_stream))
-               stream_set_endp(circuit->rcv_stream, pdu_len);
+       if (isis->debugs & DEBUG_SNP_PACKETS) {
+               zlog_debug(
+                       "ISIS-Snp (%s): Rcvd L%d %cSNP on %s, cirType %s, cirID %u",
+                       circuit->area->area_tag, level, typechar,
+                       circuit->interface->name,
+                       circuit_t2string(circuit->is_type),
+                       circuit->circuit_id);
+               if (isis->debugs & DEBUG_PACKET_DUMP)
+                       zlog_dump_data(STREAM_DATA(circuit->rcv_stream),
+                                      stream_get_endp(circuit->rcv_stream));
+       }
 
        /* 7.3.15.2 a) 1 - external domain circuit will discard snp pdu */
        if (circuit->ext_domain) {
@@ -1613,8 +1104,7 @@ static int process_snp(int snp_type, int level, struct isis_circuit *circuit,
        }
 
        /* 7.3.15.2 a) 2,3 - manualL2OnlyMode not implemented */
-       if (!accept_level(level, circuit->is_type)) {
-
+       if (!(circuit->is_type & level)) {
                zlog_debug(
                        "ISIS-Snp (%s): Rcvd L%d %cSNP on %s, "
                        "skipping: circuit type %s does not match level %d",
@@ -1626,9 +1116,8 @@ static int process_snp(int snp_type, int level, struct isis_circuit *circuit,
        }
 
        /* 7.3.15.2 a) 4 - not applicable for CSNP  only PSNPs on broadcast */
-       if ((snp_type == ISIS_SNP_PSNP_FLAG)
-           && (circuit->circ_type == CIRCUIT_T_BROADCAST)
-           && (!circuit->u.bc.is_dr[level - 1])) {
+       if (!is_csnp && (circuit->circ_type == CIRCUIT_T_BROADCAST)
+           && !circuit->u.bc.is_dr[level - 1]) {
                zlog_debug(
                        "ISIS-Snp (%s): Rcvd L%d %cSNP from %s on %s, "
                        "skipping: we are not the DIS",
@@ -1650,15 +1139,8 @@ static int process_snp(int snp_type, int level, struct isis_circuit *circuit,
        /* for broadcast circuits, snpa should be compared */
        /* FIXME : Do we need to check SNPA? */
        if (circuit->circ_type == CIRCUIT_T_BROADCAST) {
-               if (snp_type == ISIS_SNP_CSNP_FLAG) {
-                       adj = isis_adj_lookup(chdr->source_id,
-                                             circuit->u.bc.adjdb[level - 1]);
-               } else {
-                       /* a psnp on a broadcast, how lovely of Juniper :) */
-                       adj = isis_adj_lookup(phdr->source_id,
-                                             circuit->u.bc.adjdb[level - 1]);
-               }
-               if (!adj)
+               if (!isis_adj_lookup(rem_sys_id,
+                                    circuit->u.bc.adjdb[level - 1]))
                        return ISIS_OK; /* Silently discard */
        } else {
                if (!circuit->u.p2p.neighbor) {
@@ -1668,164 +1150,128 @@ static int process_snp(int snp_type, int level, struct isis_circuit *circuit,
                }
        }
 
-       /* 7.3.15.2 a) 8 - Passwords for level 1 - not implemented  */
-
-       /* 7.3.15.2 a) 9 - Passwords for level 2 - not implemented  */
-
-       memset(&tlvs, 0, sizeof(struct tlvs));
+       struct isis_tlvs *tlvs;
+       int retval = ISIS_WARNING;
+       const char *error_log;
 
-       /* parse the SNP */
-       expected |= TLVFLAG_LSP_ENTRIES;
-       expected |= TLVFLAG_AUTH_INFO;
-
-       auth_tlv_offset = stream_get_getp(circuit->rcv_stream);
-       retval = parse_tlvs(circuit->area->area_tag,
-                           STREAM_PNT(circuit->rcv_stream),
-                           pdu_len - stream_get_getp(circuit->rcv_stream),
-                           &expected, &found, &tlvs, &auth_tlv_offset);
-
-       if (retval > ISIS_WARNING) {
-               zlog_warn("something went very wrong processing SNP");
-               free_tlvs(&tlvs);
-               return retval;
+       if (isis_unpack_tlvs(STREAM_READABLE(circuit->rcv_stream),
+                            circuit->rcv_stream, &tlvs, &error_log)) {
+               zlog_warn("Something went wrong unpacking the SNP: %s",
+                         error_log);
+               goto out;
        }
 
-       if (level == IS_LEVEL_1)
-               passwd = &circuit->area->area_passwd;
-       else
-               passwd = &circuit->area->domain_passwd;
-
-       if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_RECV)) {
-               if (passwd->type) {
-                       if (!(found & TLVFLAG_AUTH_INFO)
-                           || authentication_check(&tlvs.auth_info, passwd,
-                                                   circuit->rcv_stream,
-                                                   auth_tlv_offset)) {
-                               isis_event_auth_failure(circuit->area->area_tag,
-                                                       "SNP authentication"
-                                                       " failure",
-                                                       phdr ? phdr->source_id
-                                                            : chdr->source_id);
-                               free_tlvs(&tlvs);
-                               return ISIS_OK;
-                       }
-               }
+       struct isis_passwd *passwd = (level == IS_LEVEL_1)
+                                            ? &circuit->area->area_passwd
+                                            : &circuit->area->domain_passwd;
+       if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_RECV)
+           && !isis_tlvs_auth_is_valid(tlvs, passwd, circuit->rcv_stream,
+                                       false)) {
+               isis_event_auth_failure(circuit->area->area_tag,
+                                       "SNP authentication failure",
+                                       rem_sys_id);
+               goto out;
        }
 
+       struct isis_lsp_entry *entry_head =
+               (struct isis_lsp_entry *)tlvs->lsp_entries.head;
+
        /* debug isis snp-packets */
        if (isis->debugs & DEBUG_SNP_PACKETS) {
                zlog_debug("ISIS-Snp (%s): Rcvd L%d %cSNP from %s on %s",
                           circuit->area->area_tag, level, typechar,
                           snpa_print(ssnpa), circuit->interface->name);
-               if (tlvs.lsp_entries) {
-                       for (ALL_LIST_ELEMENTS_RO(tlvs.lsp_entries, node,
-                                                 entry)) {
-                               zlog_debug(
-                                       "ISIS-Snp (%s):         %cSNP entry %s, seq 0x%08x,"
-                                       " cksum 0x%04x, lifetime %us",
-                                       circuit->area->area_tag, typechar,
-                                       rawlspid_print(entry->lsp_id),
-                                       ntohl(entry->seq_num),
-                                       ntohs(entry->checksum),
-                                       ntohs(entry->rem_lifetime));
-                       }
+               for (struct isis_lsp_entry *entry = entry_head; entry;
+                    entry = entry->next) {
+                       zlog_debug(
+                               "ISIS-Snp (%s):         %cSNP entry %s, seq 0x%08" PRIx32
+                               ", cksum 0x%04" PRIx16 ", lifetime %" PRIu16 "s",
+                               circuit->area->area_tag, typechar,
+                               rawlspid_print(entry->id), entry->seqno,
+                               entry->checksum, entry->rem_lifetime);
                }
        }
 
        /* 7.3.15.2 b) Actions on LSP_ENTRIES reported */
-       if (tlvs.lsp_entries) {
-               for (ALL_LIST_ELEMENTS_RO(tlvs.lsp_entries, node, entry)) {
-                       lsp = lsp_search(entry->lsp_id,
-                                        circuit->area->lspdb[level - 1]);
-                       own_lsp = !memcmp(entry->lsp_id, isis->sysid,
-                                         ISIS_SYS_ID_LEN);
-                       if (lsp) {
-                               /* 7.3.15.2 b) 1) is this LSP newer */
-                               cmp = lsp_compare(circuit->area->area_tag, lsp,
-                                                 entry->seq_num,
-                                                 entry->checksum,
-                                                 entry->rem_lifetime);
-                               /* 7.3.15.2 b) 2) if it equals, clear SRM on p2p
-                                */
-                               if (cmp == LSP_EQUAL) {
+       for (struct isis_lsp_entry *entry = entry_head; entry;
+            entry = entry->next) {
+               struct isis_lsp *lsp =
+                       lsp_search(entry->id, circuit->area->lspdb[level - 1]);
+               bool own_lsp = !memcmp(entry->id, isis->sysid, ISIS_SYS_ID_LEN);
+               if (lsp) {
+                       /* 7.3.15.2 b) 1) is this LSP newer */
+                       int cmp = lsp_compare(circuit->area->area_tag, lsp,
+                                             entry->seqno, entry->checksum,
+                                             entry->rem_lifetime);
+                       /* 7.3.15.2 b) 2) if it equals, clear SRM on p2p */
+                       if (cmp == LSP_EQUAL) {
+                               /* if (circuit->circ_type !=
+                                * CIRCUIT_T_BROADCAST) */
+                               ISIS_CLEAR_FLAG(lsp->SRMflags, circuit);
+                       }
+                       /* 7.3.15.2 b) 3) if it is older, clear SSN and set SRM
+                          */
+                       else if (cmp == LSP_OLDER) {
+                               ISIS_CLEAR_FLAG(lsp->SSNflags, circuit);
+                               ISIS_SET_FLAG(lsp->SRMflags, circuit);
+                       }
+                       /* 7.3.15.2 b) 4) if it is newer, set SSN and clear SRM
+                          on p2p */
+                       else {
+                               if (own_lsp) {
+                                       lsp_inc_seqno(lsp, entry->seqno);
+                                       ISIS_SET_FLAG(lsp->SRMflags, circuit);
+                               } else {
+                                       ISIS_SET_FLAG(lsp->SSNflags, circuit);
                                        /* if (circuit->circ_type !=
                                         * CIRCUIT_T_BROADCAST) */
                                        ISIS_CLEAR_FLAG(lsp->SRMflags, circuit);
                                }
-                               /* 7.3.15.2 b) 3) if it is older, clear SSN and
-                                  set SRM */
-                               else if (cmp == LSP_OLDER) {
-                                       ISIS_CLEAR_FLAG(lsp->SSNflags, circuit);
-                                       ISIS_SET_FLAG(lsp->SRMflags, circuit);
-                               }
-                               /* 7.3.15.2 b) 4) if it is newer, set SSN and
-                                  clear SRM on p2p */
-                               else {
-                                       if (own_lsp) {
-                                               lsp_inc_seqnum(
-                                                       lsp,
-                                                       ntohl(entry->seq_num));
-                                               ISIS_SET_FLAG(lsp->SRMflags,
-                                                             circuit);
-                                       } else {
-                                               ISIS_SET_FLAG(lsp->SSNflags,
-                                                             circuit);
-                                               /* if (circuit->circ_type !=
-                                                * CIRCUIT_T_BROADCAST) */
-                                               ISIS_CLEAR_FLAG(lsp->SRMflags,
-                                                               circuit);
-                                       }
-                               }
-                       } else {
-                               /* 7.3.15.2 b) 5) if it was not found, and all
-                                * of those are not 0,
-                                * insert it and set SSN on it */
-                               if (entry->rem_lifetime && entry->checksum
-                                   && entry->seq_num
-                                   && memcmp(entry->lsp_id, isis->sysid,
-                                             ISIS_SYS_ID_LEN)) {
-                                       lsp = lsp_new(
-                                               circuit->area, entry->lsp_id,
-                                               ntohs(entry->rem_lifetime), 0,
-                                               0, entry->checksum, level);
-                                       lsp_insert(lsp,
-                                                  circuit->area
-                                                          ->lspdb[level - 1]);
-                                       ISIS_FLAGS_CLEAR_ALL(lsp->SRMflags);
-                                       ISIS_SET_FLAG(lsp->SSNflags, circuit);
-                               }
+                       }
+               } else {
+                       /* 7.3.15.2 b) 5) if it was not found, and all of those
+                        * are not 0,
+                        * insert it and set SSN on it */
+                       if (entry->rem_lifetime && entry->checksum
+                           && entry->seqno && memcmp(entry->id, isis->sysid,
+                                                     ISIS_SYS_ID_LEN)) {
+                               struct isis_lsp *lsp =
+                                       lsp_new(circuit->area, entry->id,
+                                               entry->rem_lifetime, 0, 0,
+                                               entry->checksum, level);
+                               lsp_insert(lsp,
+                                          circuit->area->lspdb[level - 1]);
+                               ISIS_FLAGS_CLEAR_ALL(lsp->SRMflags);
+                               ISIS_SET_FLAG(lsp->SSNflags, circuit);
                        }
                }
        }
 
        /* 7.3.15.2 c) on CSNP set SRM for all in range which were not reported
         */
-       if (snp_type == ISIS_SNP_CSNP_FLAG) {
+       if (is_csnp) {
                /*
                 * Build a list from our own LSP db bounded with
                 * start_lsp_id and stop_lsp_id
                 */
-               lsp_list = list_new();
-               lsp_build_list_nonzero_ht(chdr->start_lsp_id, chdr->stop_lsp_id,
-                                         lsp_list,
+               struct list *lsp_list = list_new();
+               lsp_build_list_nonzero_ht(start_lsp_id, stop_lsp_id, lsp_list,
                                          circuit->area->lspdb[level - 1]);
 
                /* Fixme: Find a better solution */
-               if (tlvs.lsp_entries) {
-                       for (ALL_LIST_ELEMENTS(tlvs.lsp_entries, node, nnode,
-                                              entry)) {
-                               for (ALL_LIST_ELEMENTS(lsp_list, node2, nnode2,
-                                                      lsp)) {
-                                       if (lsp_id_cmp(lsp->lsp_header->lsp_id,
-                                                      entry->lsp_id)
-                                           == 0) {
-                                               list_delete_node(lsp_list,
-                                                                node2);
-                                               break;
-                                       }
+               struct listnode *node, *nnode;
+               struct isis_lsp *lsp;
+               for (struct isis_lsp_entry *entry = entry_head; entry;
+                    entry = entry->next) {
+                       for (ALL_LIST_ELEMENTS(lsp_list, node, nnode, lsp)) {
+                               if (lsp_id_cmp(lsp->hdr.lsp_id, entry->id)
+                                   == 0) {
+                                       list_delete_node(lsp_list, node);
+                                       break;
                                }
                        }
                }
+
                /* on remaining LSPs we set SRM (neighbor knew not of) */
                for (ALL_LIST_ELEMENTS_RO(lsp_list, node, lsp))
                        ISIS_SET_FLAG(lsp->SRMflags, circuit);
@@ -1833,59 +1279,39 @@ static int process_snp(int snp_type, int level, struct isis_circuit *circuit,
                list_delete(lsp_list);
        }
 
-       free_tlvs(&tlvs);
+       retval = ISIS_OK;
+out:
+       isis_free_tlvs(tlvs);
        return retval;
 }
 
-static int process_csnp(int level, struct isis_circuit *circuit,
-                       const u_char *ssnpa)
-{
-       if (isis->debugs & DEBUG_SNP_PACKETS) {
-               zlog_debug(
-                       "ISIS-Snp (%s): Rcvd L%d CSNP on %s, cirType %s, cirID %u",
-                       circuit->area->area_tag, level,
-                       circuit->interface->name,
-                       circuit_t2string(circuit->is_type),
-                       circuit->circuit_id);
-               if (isis->debugs & DEBUG_PACKET_DUMP)
-                       zlog_dump_data(STREAM_DATA(circuit->rcv_stream),
-                                      stream_get_endp(circuit->rcv_stream));
-       }
-
-       /* Sanity check - FIXME: move to correct place */
-       if ((stream_get_endp(circuit->rcv_stream)
-            - stream_get_getp(circuit->rcv_stream))
-           < ISIS_CSNP_HDRLEN) {
-               zlog_warn("Packet too short ( < %d)", ISIS_CSNP_HDRLEN);
-               return ISIS_WARNING;
-       }
-
-       return process_snp(ISIS_SNP_CSNP_FLAG, level, circuit, ssnpa);
-}
-
-static int process_psnp(int level, struct isis_circuit *circuit,
-                       const u_char *ssnpa)
+static int pdu_size(uint8_t pdu_type, uint8_t *size)
 {
-       if (isis->debugs & DEBUG_SNP_PACKETS) {
-               zlog_debug(
-                       "ISIS-Snp (%s): Rcvd L%d PSNP on %s, cirType %s, cirID %u",
-                       circuit->area->area_tag, level,
-                       circuit->interface->name,
-                       circuit_t2string(circuit->is_type),
-                       circuit->circuit_id);
-               if (isis->debugs & DEBUG_PACKET_DUMP)
-                       zlog_dump_data(STREAM_DATA(circuit->rcv_stream),
-                                      stream_get_endp(circuit->rcv_stream));
-       }
-
-       if ((stream_get_endp(circuit->rcv_stream)
-            - stream_get_getp(circuit->rcv_stream))
-           < ISIS_PSNP_HDRLEN) {
-               zlog_warn("Packet too short ( < %d)", ISIS_PSNP_HDRLEN);
-               return ISIS_WARNING;
+       switch (pdu_type) {
+       case L1_LAN_HELLO:
+       case L2_LAN_HELLO:
+               *size = ISIS_LANHELLO_HDRLEN;
+               break;
+       case P2P_HELLO:
+               *size = ISIS_P2PHELLO_HDRLEN;
+               break;
+       case L1_LINK_STATE:
+       case L2_LINK_STATE:
+               *size = ISIS_LSP_HDR_LEN;
+               break;
+       case L1_COMPLETE_SEQ_NUM:
+       case L2_COMPLETE_SEQ_NUM:
+               *size = ISIS_CSNP_HDRLEN;
+               break;
+       case L1_PARTIAL_SEQ_NUM:
+       case L2_PARTIAL_SEQ_NUM:
+               *size = ISIS_PSNP_HDRLEN;
+               break;
+       default:
+               return 1;
        }
-
-       return process_snp(ISIS_SNP_PSNP_FLAG, level, circuit, ssnpa);
+       *size += ISIS_FIXED_HDR_LEN;
+       return 0;
 }
 
 /*
@@ -1894,53 +1320,68 @@ static int process_psnp(int level, struct isis_circuit *circuit,
 
 static int isis_handle_pdu(struct isis_circuit *circuit, u_char *ssnpa)
 {
-       struct isis_fixed_hdr *hdr;
-
        int retval = ISIS_OK;
 
-       /*
-        * Let's first read data from stream to the header
-        */
-       hdr = (struct isis_fixed_hdr *)STREAM_DATA(circuit->rcv_stream);
+       /* Verify that at least the 8 bytes fixed header have been received */
+       if (stream_get_endp(circuit->rcv_stream) < ISIS_FIXED_HDR_LEN) {
+               zlog_err("PDU is too short to be IS-IS.");
+               return ISIS_ERROR;
+       }
+
+       uint8_t idrp = stream_getc(circuit->rcv_stream);
+       uint8_t length = stream_getc(circuit->rcv_stream);
+       uint8_t version1 = stream_getc(circuit->rcv_stream);
+       uint8_t id_len = stream_getc(circuit->rcv_stream);
+       uint8_t pdu_type = stream_getc(circuit->rcv_stream)
+                          & 0x1f; /* bits 6-8 are reserved */
+       uint8_t version2 = stream_getc(circuit->rcv_stream);
+       stream_forward_getp(circuit->rcv_stream, 1); /* reserved */
+       uint8_t max_area_addrs = stream_getc(circuit->rcv_stream);
 
-       if ((hdr->idrp != ISO10589_ISIS) && (hdr->idrp != ISO9542_ESIS)) {
-               zlog_err("Not an IS-IS or ES-IS packet IDRP=%02x", hdr->idrp);
+       if (idrp == ISO9542_ESIS) {
+               zlog_err("No support for ES-IS packet IDRP=%" PRIx8, idrp);
                return ISIS_ERROR;
        }
 
-       /* now we need to know if this is an ISO 9542 packet and
-        * take real good care of it, waaa!
-        */
-       if (hdr->idrp == ISO9542_ESIS) {
-               zlog_err("No support for ES-IS packet IDRP=%02x", hdr->idrp);
+       if (idrp != ISO10589_ISIS) {
+               zlog_err("Not an IS-IS packet IDRP=%" PRIx8, idrp);
                return ISIS_ERROR;
        }
-       stream_set_getp(circuit->rcv_stream, ISIS_FIXED_HDR_LEN);
 
-       /*
-        * and then process it
-        */
+       if (version1 != 1) {
+               zlog_warn("Unsupported ISIS version %" PRIu8, version1);
+               return ISIS_WARNING;
+       }
 
-       if (hdr->length < ISIS_MINIMUM_FIXED_HDR_LEN) {
-               zlog_err("Fixed header length = %d", hdr->length);
+       if (id_len != 0 && id_len != ISIS_SYS_ID_LEN) {
+               zlog_err(
+                       "IDFieldLengthMismatch: ID Length field in a received PDU  %" PRIu8
+                       ", while the parameter for this IS is %u",
+                       id_len, ISIS_SYS_ID_LEN);
                return ISIS_ERROR;
        }
 
-       if (hdr->version1 != 1) {
-               zlog_warn("Unsupported ISIS version %u", hdr->version1);
+       uint8_t expected_length;
+       if (pdu_size(pdu_type, &expected_length)) {
+               zlog_warn("Unsupported ISIS PDU %" PRIu8, pdu_type);
                return ISIS_WARNING;
        }
-       /* either 6 or 0 */
-       if ((hdr->id_len != 0) && (hdr->id_len != ISIS_SYS_ID_LEN)) {
+
+       if (length != expected_length) {
+               zlog_err("Exepected fixed header length = %" PRIu8
+                        " but got %" PRIu8,
+                        expected_length, length);
+               return ISIS_ERROR;
+       }
+
+       if (stream_get_endp(circuit->rcv_stream) < length) {
                zlog_err(
-                       "IDFieldLengthMismatch: ID Length field in a received PDU  %u, "
-                       "while the parameter for this IS is %u",
-                       hdr->id_len, ISIS_SYS_ID_LEN);
+                       "PDU is too short to contain fixed header of given PDU type.");
                return ISIS_ERROR;
        }
 
-       if (hdr->version2 != 1) {
-               zlog_warn("Unsupported ISIS version %u", hdr->version2);
+       if (version2 != 1) {
+               zlog_warn("Unsupported ISIS PDU version %" PRIu8, version2);
                return ISIS_WARNING;
        }
 
@@ -1951,42 +1392,29 @@ static int isis_handle_pdu(struct isis_circuit *circuit, u_char *ssnpa)
        }
 
        /* either 3 or 0 */
-       if ((hdr->max_area_addrs != 0)
-           && (hdr->max_area_addrs != isis->max_area_addrs)) {
+       if (max_area_addrs != 0 && max_area_addrs != isis->max_area_addrs) {
                zlog_err(
-                       "maximumAreaAddressesMismatch: maximumAreaAdresses in a "
-                       "received PDU %u while the parameter for this IS is %u",
-                       hdr->max_area_addrs, isis->max_area_addrs);
+                       "maximumAreaAddressesMismatch: maximumAreaAdresses in a received PDU %" PRIu8
+                       " while the parameter for this IS is %u",
+                       max_area_addrs, isis->max_area_addrs);
                return ISIS_ERROR;
        }
 
-       switch (hdr->pdu_type) {
+       switch (pdu_type) {
        case L1_LAN_HELLO:
-               retval = process_lan_hello(ISIS_LEVEL1, circuit, ssnpa);
-               break;
        case L2_LAN_HELLO:
-               retval = process_lan_hello(ISIS_LEVEL2, circuit, ssnpa);
-               break;
        case P2P_HELLO:
-               retval = process_p2p_hello(circuit);
+               retval = process_hello(pdu_type, circuit, ssnpa);
                break;
        case L1_LINK_STATE:
-               retval = process_lsp(ISIS_LEVEL1, circuit, ssnpa);
-               break;
        case L2_LINK_STATE:
-               retval = process_lsp(ISIS_LEVEL2, circuit, ssnpa);
+               retval = process_lsp(pdu_type, circuit, ssnpa);
                break;
        case L1_COMPLETE_SEQ_NUM:
-               retval = process_csnp(ISIS_LEVEL1, circuit, ssnpa);
-               break;
        case L2_COMPLETE_SEQ_NUM:
-               retval = process_csnp(ISIS_LEVEL2, circuit, ssnpa);
-               break;
        case L1_PARTIAL_SEQ_NUM:
-               retval = process_psnp(ISIS_LEVEL1, circuit, ssnpa);
-               break;
        case L2_PARTIAL_SEQ_NUM:
-               retval = process_psnp(ISIS_LEVEL2, circuit, ssnpa);
+               retval = process_snp(pdu_type, circuit, ssnpa);
                break;
        default:
                return ISIS_ERROR;
@@ -2025,73 +1453,67 @@ int isis_receive(struct thread *thread)
        return retval;
 }
 
-/* filling of the fixed isis header */
-void fill_fixed_hdr(struct isis_fixed_hdr *hdr, u_char pdu_type)
-{
-       memset(hdr, 0, sizeof(struct isis_fixed_hdr));
-
-       hdr->idrp = ISO10589_ISIS;
-
-       switch (pdu_type) {
-       case L1_LAN_HELLO:
-       case L2_LAN_HELLO:
-               hdr->length = ISIS_LANHELLO_HDRLEN;
-               break;
-       case P2P_HELLO:
-               hdr->length = ISIS_P2PHELLO_HDRLEN;
-               break;
-       case L1_LINK_STATE:
-       case L2_LINK_STATE:
-               hdr->length = ISIS_LSP_HDR_LEN;
-               break;
-       case L1_COMPLETE_SEQ_NUM:
-       case L2_COMPLETE_SEQ_NUM:
-               hdr->length = ISIS_CSNP_HDRLEN;
-               break;
-       case L1_PARTIAL_SEQ_NUM:
-       case L2_PARTIAL_SEQ_NUM:
-               hdr->length = ISIS_PSNP_HDRLEN;
-               break;
-       default:
-               zlog_warn("fill_fixed_hdr(): unknown pdu type %d", pdu_type);
-               return;
-       }
-       hdr->length += ISIS_FIXED_HDR_LEN;
-       hdr->pdu_type = pdu_type;
-       hdr->version1 = 1;
-       hdr->id_len = 0; /* ISIS_SYS_ID_LEN -  0==6 */
-       hdr->version2 = 1;
-       hdr->max_area_addrs = 0; /* isis->max_area_addrs -  0==3 */
-}
-
 /*
  * SEND SIDE
  */
-static void fill_fixed_hdr_andstream(struct isis_fixed_hdr *hdr,
-                                    u_char pdu_type, struct stream *stream)
+void fill_fixed_hdr(uint8_t pdu_type, struct stream *stream)
 {
-       fill_fixed_hdr(hdr, pdu_type);
-
-       stream_putc(stream, hdr->idrp);
-       stream_putc(stream, hdr->length);
-       stream_putc(stream, hdr->version1);
-       stream_putc(stream, hdr->id_len);
-       stream_putc(stream, hdr->pdu_type);
-       stream_putc(stream, hdr->version2);
-       stream_putc(stream, hdr->reserved);
-       stream_putc(stream, hdr->max_area_addrs);
-
-       return;
+       uint8_t length;
+
+       if (pdu_size(pdu_type, &length))
+               assert(!"Unknown PDU Type");
+
+       stream_putc(stream, ISO10589_ISIS); /* IDRP */
+       stream_putc(stream, length);    /* Length of fixed header */
+       stream_putc(stream, 1); /* Version/Protocol ID Extension 1 */
+       stream_putc(stream, 0); /* ID Length, 0 => 6 */
+       stream_putc(stream, pdu_type);
+       stream_putc(stream, 1); /* Subversion */
+       stream_putc(stream, 0); /* Reserved */
+       stream_putc(stream, 0); /* Max Area Addresses 0 => 3 */
+}
+
+static void put_hello_hdr(struct isis_circuit *circuit, int level,
+                         size_t *len_pointer)
+{
+       uint8_t pdu_type;
+
+       if (circuit->circ_type == CIRCUIT_T_BROADCAST)
+               pdu_type = (level == IS_LEVEL_1) ? L1_LAN_HELLO : L2_LAN_HELLO;
+       else
+               pdu_type = P2P_HELLO;
+
+       isis_circuit_stream(circuit, &circuit->snd_stream);
+       fill_fixed_hdr(pdu_type, circuit->snd_stream);
+
+       stream_putc(circuit->snd_stream, circuit->is_type);
+       stream_put(circuit->snd_stream, circuit->area->isis->sysid,
+                  ISIS_SYS_ID_LEN);
+
+       uint32_t holdtime = circuit->hello_multiplier[level - 1]
+                           * circuit->hello_interval[level - 1];
+
+       if (holdtime > 0xffff)
+               holdtime = 0xffff;
+
+       stream_putw(circuit->snd_stream, holdtime);
+       *len_pointer = stream_get_endp(circuit->snd_stream);
+       stream_putw(circuit->snd_stream, 0); /* length is filled in later */
+
+       if (circuit->circ_type == CIRCUIT_T_BROADCAST) {
+               u_char *desig_is = (level == IS_LEVEL_1)
+                                          ? circuit->u.bc.l1_desig_is
+                                          : circuit->u.bc.l2_desig_is;
+               stream_putc(circuit->snd_stream, circuit->priority[level - 1]);
+               stream_put(circuit->snd_stream, desig_is, ISIS_SYS_ID_LEN + 1);
+       } else {
+               stream_putc(circuit->snd_stream, circuit->circuit_id);
+       }
 }
 
 int send_hello(struct isis_circuit *circuit, int level)
 {
-       struct isis_fixed_hdr fixed_hdr;
-       struct isis_lan_hello_hdr hello_hdr;
-       struct isis_p2p_hello_hdr p2p_hello_hdr;
-       unsigned char hmac_md5_hash[ISIS_AUTH_MD5_SIZE];
-       size_t len_pointer, length, auth_tlv_offset = 0;
-       u_int32_t interval;
+       size_t len_pointer;
        int retval;
 
        if (circuit->is_passive)
@@ -2102,113 +1524,21 @@ int send_hello(struct isis_circuit *circuit, int level)
                return ISIS_WARNING;
        }
 
-       isis_circuit_stream(circuit, &circuit->snd_stream);
-
-       if (circuit->circ_type == CIRCUIT_T_BROADCAST)
-               if (level == IS_LEVEL_1)
-                       fill_fixed_hdr_andstream(&fixed_hdr, L1_LAN_HELLO,
-                                                circuit->snd_stream);
-               else
-                       fill_fixed_hdr_andstream(&fixed_hdr, L2_LAN_HELLO,
-                                                circuit->snd_stream);
-       else
-               fill_fixed_hdr_andstream(&fixed_hdr, P2P_HELLO,
-                                        circuit->snd_stream);
-
-       /*
-        * Fill LAN Level 1 or 2 Hello PDU header
-        */
-       memset(&hello_hdr, 0, sizeof(struct isis_lan_hello_hdr));
-       interval = circuit->hello_multiplier[level - 1]
-                  * circuit->hello_interval[level - 1];
-       if (interval > USHRT_MAX)
-               interval = USHRT_MAX;
-       hello_hdr.circuit_t = circuit->is_type;
-       memcpy(hello_hdr.source_id, isis->sysid, ISIS_SYS_ID_LEN);
-       hello_hdr.hold_time = htons((u_int16_t)interval);
-
-       hello_hdr.pdu_len = 0; /* Update the PDU Length later */
-       len_pointer =
-               stream_get_endp(circuit->snd_stream) + 3 + ISIS_SYS_ID_LEN;
-
-       /* copy the shared part of the hello to the p2p hello if needed */
-       if (circuit->circ_type == CIRCUIT_T_P2P) {
-               memcpy(&p2p_hello_hdr, &hello_hdr, 5 + ISIS_SYS_ID_LEN);
-               p2p_hello_hdr.local_id = circuit->circuit_id;
-               /* FIXME: need better understanding */
-               stream_put(circuit->snd_stream, &p2p_hello_hdr,
-                          ISIS_P2PHELLO_HDRLEN);
-       } else {
-               hello_hdr.prio = circuit->priority[level - 1];
-               if (level == IS_LEVEL_1) {
-                       memcpy(hello_hdr.lan_id, circuit->u.bc.l1_desig_is,
-                              ISIS_SYS_ID_LEN + 1);
-               } else if (level == IS_LEVEL_2) {
-                       memcpy(hello_hdr.lan_id, circuit->u.bc.l2_desig_is,
-                              ISIS_SYS_ID_LEN + 1);
-               }
-               stream_put(circuit->snd_stream, &hello_hdr,
-                          ISIS_LANHELLO_HDRLEN);
-       }
-
-       /*
-        * Then the variable length part.
-        */
-
-       /* add circuit password */
-       switch (circuit->passwd.type) {
-       /* Cleartext */
-       case ISIS_PASSWD_TYPE_CLEARTXT:
-               if (tlv_add_authinfo(circuit->passwd.type, circuit->passwd.len,
-                                    circuit->passwd.passwd,
-                                    circuit->snd_stream))
-                       return ISIS_WARNING;
-               break;
+       put_hello_hdr(circuit, level, &len_pointer);
 
-       /* HMAC MD5 */
-       case ISIS_PASSWD_TYPE_HMAC_MD5:
-               /* Remember where TLV is written so we can later overwrite the
-                * MD5 hash */
-               auth_tlv_offset = stream_get_endp(circuit->snd_stream);
-               memset(&hmac_md5_hash, 0, ISIS_AUTH_MD5_SIZE);
-               if (tlv_add_authinfo(circuit->passwd.type, ISIS_AUTH_MD5_SIZE,
-                                    hmac_md5_hash, circuit->snd_stream))
-                       return ISIS_WARNING;
-               break;
+       struct isis_tlvs *tlvs = isis_alloc_tlvs();
 
-       default:
-               break;
-       }
+       isis_tlvs_add_auth(tlvs, &circuit->passwd);
 
-       /*  Area Addresses TLV */
-       if (listcount(circuit->area->area_addrs) == 0)
-               return ISIS_WARNING;
-       if (tlv_add_area_addrs(circuit->area->area_addrs, circuit->snd_stream))
+       if (!listcount(circuit->area->area_addrs))
                return ISIS_WARNING;
+       isis_tlvs_add_area_addresses(tlvs, circuit->area->area_addrs);
 
-       /*  LAN Neighbors TLV */
-       if (circuit->circ_type == CIRCUIT_T_BROADCAST) {
-               if (level == IS_LEVEL_1 && circuit->u.bc.lan_neighs[0]
-                   && listcount(circuit->u.bc.lan_neighs[0]) > 0)
-                       if (tlv_add_lan_neighs(circuit->u.bc.lan_neighs[0],
-                                              circuit->snd_stream))
-                               return ISIS_WARNING;
-               if (level == IS_LEVEL_2 && circuit->u.bc.lan_neighs[1]
-                   && listcount(circuit->u.bc.lan_neighs[1]) > 0)
-                       if (tlv_add_lan_neighs(circuit->u.bc.lan_neighs[1],
-                                              circuit->snd_stream))
-                               return ISIS_WARNING;
-       }
-
-       /* Protocols Supported TLV */
-       if (circuit->nlpids.count > 0)
-               if (tlv_add_nlpid(&circuit->nlpids, circuit->snd_stream))
-                       return ISIS_WARNING;
-       /* IP interface Address TLV */
-       if (circuit->ip_router && circuit->ip_addrs
-           && listcount(circuit->ip_addrs) > 0)
-               if (tlv_add_ip_addrs(circuit->ip_addrs, circuit->snd_stream))
-                       return ISIS_WARNING;
+       if (circuit->circ_type == CIRCUIT_T_BROADCAST)
+               isis_tlvs_add_lan_neighbors(
+                       tlvs, circuit->u.bc.lan_neighs[level - 1]);
+
+       isis_tlvs_set_protocols_supported(tlvs, &circuit->nlpids);
 
        /*
         * MT Supported TLV
@@ -2221,48 +1551,26 @@ int send_hello(struct isis_circuit *circuit, int level)
        unsigned int mt_count;
 
        mt_settings = circuit_mt_settings(circuit, &mt_count);
-       if ((mt_count == 0 && area_is_mt(circuit->area))
-           || (mt_count == 1 && mt_settings[0]->mtid != ISIS_MT_IPV4_UNICAST)
-           || (mt_count > 1)) {
-               struct list *mt_info = list_new();
-               mt_info->del = free_tlv;
-
-               for (unsigned int i = 0; i < mt_count; i++) {
-                       struct mt_router_info *info;
-
-                       info = XCALLOC(MTYPE_ISIS_TLV, sizeof(*info));
-                       info->mtid = mt_settings[i]->mtid;
-                       /* overload info is not valid in IIH, so it's not
-                        * included here */
-                       listnode_add(mt_info, info);
-               }
-               tlv_add_mt_router_info(mt_info, circuit->snd_stream);
-               list_free(mt_info);
+       if (mt_count == 0 && area_is_mt(circuit->area)) {
+               tlvs->mt_router_info_empty = true;
+       } else if ((mt_count == 1
+                   && mt_settings[0]->mtid != ISIS_MT_IPV4_UNICAST)
+                  || (mt_count > 1)) {
+               for (unsigned int i = 0; i < mt_count; i++)
+                       isis_tlvs_add_mt_router_info(tlvs, mt_settings[i]->mtid,
+                                                    false, false);
        }
 
-       /* IPv6 Interface Address TLV */
-       if (circuit->ipv6_router && circuit->ipv6_link
-           && listcount(circuit->ipv6_link) > 0)
-               if (tlv_add_ipv6_addrs(circuit->ipv6_link, circuit->snd_stream))
-                       return ISIS_WARNING;
-
-       if (circuit->pad_hellos)
-               if (tlv_add_padding(circuit->snd_stream))
-                       return ISIS_WARNING;
+       if (circuit->ip_router && circuit->ip_addrs)
+               isis_tlvs_add_ipv4_addresses(tlvs, circuit->ip_addrs);
 
-       length = stream_get_endp(circuit->snd_stream);
-       /* Update PDU length */
-       stream_putw_at(circuit->snd_stream, len_pointer, (u_int16_t)length);
+       if (circuit->ipv6_router && circuit->ipv6_link)
+               isis_tlvs_add_ipv6_addresses(tlvs, circuit->ipv6_link);
 
-       /* For HMAC MD5 we need to compute the md5 hash and store it */
-       if (circuit->passwd.type == ISIS_PASSWD_TYPE_HMAC_MD5) {
-               hmac_md5(STREAM_DATA(circuit->snd_stream),
-                        stream_get_endp(circuit->snd_stream),
-                        (unsigned char *)&circuit->passwd.passwd,
-                        circuit->passwd.len, (unsigned char *)&hmac_md5_hash);
-               /* Copy the hash into the stream */
-               memcpy(STREAM_DATA(circuit->snd_stream) + auth_tlv_offset + 3,
-                      hmac_md5_hash, ISIS_AUTH_MD5_SIZE);
+       if (isis_pack_tlvs(tlvs, circuit->snd_stream, len_pointer,
+                          circuit->pad_hellos, false)) {
+               isis_free_tlvs(tlvs);
+               return ISIS_WARNING; /* XXX: Maybe Log TLV structure? */
        }
 
        if (isis->debugs & DEBUG_ADJ_PACKETS) {
@@ -2270,18 +1578,22 @@ int send_hello(struct isis_circuit *circuit, int level)
                        zlog_debug(
                                "ISIS-Adj (%s): Sending L%d LAN IIH on %s, length %zd",
                                circuit->area->area_tag, level,
-                               circuit->interface->name, length);
+                               circuit->interface->name,
+                               stream_get_endp(circuit->snd_stream));
                } else {
                        zlog_debug(
                                "ISIS-Adj (%s): Sending P2P IIH on %s, length %zd",
                                circuit->area->area_tag,
-                               circuit->interface->name, length);
+                               circuit->interface->name,
+                               stream_get_endp(circuit->snd_stream));
                }
                if (isis->debugs & DEBUG_PACKET_DUMP)
                        zlog_dump_data(STREAM_DATA(circuit->snd_stream),
                                       stream_get_endp(circuit->snd_stream));
        }
 
+       isis_free_tlvs(tlvs);
+
        retval = circuit->tx(circuit, level);
        if (retval != ISIS_OK)
                zlog_err("ISIS-Adj (%s): Send L%d IIH on %s failed",
@@ -2366,101 +1678,10 @@ int send_p2p_hello(struct thread *thread)
        return ISIS_OK;
 }
 
-static int build_csnp(int level, u_char *start, u_char *stop, struct list *lsps,
-                     struct isis_circuit *circuit)
-{
-       struct isis_fixed_hdr fixed_hdr;
-       struct isis_passwd *passwd;
-       unsigned long lenp;
-       u_int16_t length;
-       unsigned char hmac_md5_hash[ISIS_AUTH_MD5_SIZE];
-       unsigned long auth_tlv_offset = 0;
-       int retval = ISIS_OK;
-
-       isis_circuit_stream(circuit, &circuit->snd_stream);
-
-       if (level == IS_LEVEL_1)
-               fill_fixed_hdr_andstream(&fixed_hdr, L1_COMPLETE_SEQ_NUM,
-                                        circuit->snd_stream);
-       else
-               fill_fixed_hdr_andstream(&fixed_hdr, L2_COMPLETE_SEQ_NUM,
-                                        circuit->snd_stream);
-
-       /*
-        * Fill Level 1 or 2 Complete Sequence Numbers header
-        */
-
-       lenp = stream_get_endp(circuit->snd_stream);
-       stream_putw(circuit->snd_stream, 0); /* PDU length - when we know it */
-       /* no need to send the source here, it is always us if we csnp */
-       stream_put(circuit->snd_stream, isis->sysid, ISIS_SYS_ID_LEN);
-       /* with zero circuit id - ref 9.10, 9.11 */
-       stream_putc(circuit->snd_stream, 0x00);
-
-       stream_put(circuit->snd_stream, start, ISIS_SYS_ID_LEN + 2);
-       stream_put(circuit->snd_stream, stop, ISIS_SYS_ID_LEN + 2);
-
-       /*
-        * And TLVs
-        */
-       if (level == IS_LEVEL_1)
-               passwd = &circuit->area->area_passwd;
-       else
-               passwd = &circuit->area->domain_passwd;
-
-       if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_SEND)) {
-               switch (passwd->type) {
-               /* Cleartext */
-               case ISIS_PASSWD_TYPE_CLEARTXT:
-                       if (tlv_add_authinfo(ISIS_PASSWD_TYPE_CLEARTXT,
-                                            passwd->len, passwd->passwd,
-                                            circuit->snd_stream))
-                               return ISIS_WARNING;
-                       break;
-
-               /* HMAC MD5 */
-               case ISIS_PASSWD_TYPE_HMAC_MD5:
-                       /* Remember where TLV is written so we can later
-                        * overwrite the MD5 hash */
-                       auth_tlv_offset = stream_get_endp(circuit->snd_stream);
-                       memset(&hmac_md5_hash, 0, ISIS_AUTH_MD5_SIZE);
-                       if (tlv_add_authinfo(ISIS_PASSWD_TYPE_HMAC_MD5,
-                                            ISIS_AUTH_MD5_SIZE, hmac_md5_hash,
-                                            circuit->snd_stream))
-                               return ISIS_WARNING;
-                       break;
-
-               default:
-                       break;
-               }
-       }
-
-       retval = tlv_add_lsp_entries(lsps, circuit->snd_stream);
-       if (retval != ISIS_OK)
-               return retval;
-
-       length = (u_int16_t)stream_get_endp(circuit->snd_stream);
-       /* Update PU length */
-       stream_putw_at(circuit->snd_stream, lenp, length);
-
-       /* For HMAC MD5 we need to compute the md5 hash and store it */
-       if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_SEND)
-           && passwd->type == ISIS_PASSWD_TYPE_HMAC_MD5) {
-               hmac_md5(STREAM_DATA(circuit->snd_stream),
-                        stream_get_endp(circuit->snd_stream),
-                        (unsigned char *)&passwd->passwd, passwd->len,
-                        (unsigned char *)&hmac_md5_hash);
-               /* Copy the hash into the stream */
-               memcpy(STREAM_DATA(circuit->snd_stream) + auth_tlv_offset + 3,
-                      hmac_md5_hash, ISIS_AUTH_MD5_SIZE);
-       }
-
-       return retval;
-}
-
 /*
  * Count the maximum number of lsps that can be accomodated by a given size.
  */
+#define LSP_ENTRIES_LEN (10 + ISIS_SYS_ID_LEN)
 static uint16_t get_max_lsp_count(uint16_t size)
 {
        uint16_t tlv_count;
@@ -2479,109 +1700,81 @@ static uint16_t get_max_lsp_count(uint16_t size)
        return lsp_count;
 }
 
-/*
- * Calculate the length of Authentication Info. TLV.
- */
-static uint16_t auth_tlv_length(int level, struct isis_circuit *circuit)
+int send_csnp(struct isis_circuit *circuit, int level)
 {
-       struct isis_passwd *passwd;
-       uint16_t length;
+       if (circuit->area->lspdb[level - 1] == NULL
+           || dict_count(circuit->area->lspdb[level - 1]) == 0)
+               return ISIS_OK;
 
-       if (level == IS_LEVEL_1)
-               passwd = &circuit->area->area_passwd;
-       else
-               passwd = &circuit->area->domain_passwd;
-
-       /* Also include the length of TLV header */
-       length = AUTH_INFO_HDRLEN;
-       if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_SEND)) {
-               switch (passwd->type) {
-               /* Cleartext */
-               case ISIS_PASSWD_TYPE_CLEARTXT:
-                       length += passwd->len;
-                       break;
-
-               /* HMAC MD5 */
-               case ISIS_PASSWD_TYPE_HMAC_MD5:
-                       length += ISIS_AUTH_MD5_SIZE;
-                       break;
-
-               default:
-                       break;
-               }
-       }
+       isis_circuit_stream(circuit, &circuit->snd_stream);
+       fill_fixed_hdr((level == ISIS_LEVEL1) ? L1_COMPLETE_SEQ_NUM
+                                             : L2_COMPLETE_SEQ_NUM,
+                      circuit->snd_stream);
 
-       return length;
-}
+       size_t len_pointer = stream_get_endp(circuit->snd_stream);
+       stream_putw(circuit->snd_stream, 0);
+       stream_put(circuit->snd_stream, isis->sysid, ISIS_SYS_ID_LEN);
+       /* with zero circuit id - ref 9.10, 9.11 */
+       stream_putc(circuit->snd_stream, 0);
 
-/*
- * Calculate the maximum number of lsps that can be accomodated in a CSNP/PSNP.
- */
-static uint16_t max_lsps_per_snp(int snp_type, int level,
-                                struct isis_circuit *circuit)
-{
-       int snp_hdr_len;
-       int auth_tlv_len;
-       uint16_t lsp_count;
+       size_t start_pointer = stream_get_endp(circuit->snd_stream);
+       stream_put(circuit->snd_stream, 0, ISIS_SYS_ID_LEN + 2);
+       size_t end_pointer = stream_get_endp(circuit->snd_stream);
+       stream_put(circuit->snd_stream, 0, ISIS_SYS_ID_LEN + 2);
 
-       snp_hdr_len = ISIS_FIXED_HDR_LEN;
-       if (snp_type == ISIS_SNP_CSNP_FLAG)
-               snp_hdr_len += ISIS_CSNP_HDRLEN;
-       else
-               snp_hdr_len += ISIS_PSNP_HDRLEN;
+       struct isis_passwd *passwd = (level == ISIS_LEVEL1)
+                                            ? &circuit->area->area_passwd
+                                            : &circuit->area->domain_passwd;
 
-       auth_tlv_len = auth_tlv_length(level, circuit);
-       lsp_count = get_max_lsp_count(stream_get_size(circuit->snd_stream)
-                                     - snp_hdr_len - auth_tlv_len);
-       return lsp_count;
-}
+       struct isis_tlvs *tlvs = isis_alloc_tlvs();
 
-/*
- * FIXME: support multiple CSNPs
- */
+       if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_SEND))
+               isis_tlvs_add_auth(tlvs, passwd);
 
-int send_csnp(struct isis_circuit *circuit, int level)
-{
-       u_char start[ISIS_SYS_ID_LEN + 2];
-       u_char stop[ISIS_SYS_ID_LEN + 2];
-       struct list *list = NULL;
-       struct listnode *node;
-       struct isis_lsp *lsp;
-       u_char num_lsps, loop = 1;
-       int i, retval = ISIS_OK;
+       size_t tlv_start = stream_get_endp(circuit->snd_stream);
+       if (isis_pack_tlvs(tlvs, circuit->snd_stream, len_pointer, false,
+                          false)) {
+               isis_free_tlvs(tlvs);
+               return ISIS_WARNING;
+       }
+       isis_free_tlvs(tlvs);
 
-       if (circuit->area->lspdb[level - 1] == NULL
-           || dict_count(circuit->area->lspdb[level - 1]) == 0)
-               return retval;
+       uint16_t num_lsps =
+               get_max_lsp_count(STREAM_WRITEABLE(circuit->snd_stream));
 
+       uint8_t start[ISIS_SYS_ID_LEN + 2];
        memset(start, 0x00, ISIS_SYS_ID_LEN + 2);
+       uint8_t stop[ISIS_SYS_ID_LEN + 2];
        memset(stop, 0xff, ISIS_SYS_ID_LEN + 2);
 
-       num_lsps = max_lsps_per_snp(ISIS_SNP_CSNP_FLAG, level, circuit);
-
+       bool loop = true;
        while (loop) {
-               list = list_new();
-               lsp_build_list(start, stop, num_lsps, list,
-                              circuit->area->lspdb[level - 1]);
+               tlvs = isis_alloc_tlvs();
+               if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_SEND))
+                       isis_tlvs_add_auth(tlvs, passwd);
+
+               struct isis_lsp *last_lsp;
+               isis_tlvs_add_csnp_entries(tlvs, start, stop, num_lsps,
+                                          circuit->area->lspdb[level - 1],
+                                          &last_lsp);
                /*
                 * Update the stop lsp_id before encoding this CSNP.
                 */
-               if (listcount(list) < num_lsps) {
+               if (tlvs->lsp_entries.count < num_lsps) {
                        memset(stop, 0xff, ISIS_SYS_ID_LEN + 2);
                } else {
-                       node = listtail(list);
-                       lsp = listgetdata(node);
-                       memcpy(stop, lsp->lsp_header->lsp_id,
-                              ISIS_SYS_ID_LEN + 2);
+                       memcpy(stop, last_lsp->hdr.lsp_id, sizeof(stop));
                }
 
-               retval = build_csnp(level, start, stop, list, circuit);
-               if (retval != ISIS_OK) {
-                       zlog_err("ISIS-Snp (%s): Build L%d CSNP on %s failed",
-                                circuit->area->area_tag, level,
-                                circuit->interface->name);
-                       list_delete(list);
-                       return retval;
+               memcpy(STREAM_DATA(circuit->snd_stream) + start_pointer, start,
+                      ISIS_SYS_ID_LEN + 2);
+               memcpy(STREAM_DATA(circuit->snd_stream) + end_pointer, stop,
+                      ISIS_SYS_ID_LEN + 2);
+               stream_set_endp(circuit->snd_stream, tlv_start);
+               if (isis_pack_tlvs(tlvs, circuit->snd_stream, len_pointer,
+                                  false, false)) {
+                       isis_free_tlvs(tlvs);
+                       return ISIS_WARNING;
                }
 
                if (isis->debugs & DEBUG_SNP_PACKETS) {
@@ -2590,28 +1783,20 @@ int send_csnp(struct isis_circuit *circuit, int level)
                                circuit->area->area_tag, level,
                                circuit->interface->name,
                                stream_get_endp(circuit->snd_stream));
-                       for (ALL_LIST_ELEMENTS_RO(list, node, lsp)) {
-                               zlog_debug(
-                                       "ISIS-Snp (%s):         CSNP entry %s, seq 0x%08x,"
-                                       " cksum 0x%04x, lifetime %us",
-                                       circuit->area->area_tag,
-                                       rawlspid_print(lsp->lsp_header->lsp_id),
-                                       ntohl(lsp->lsp_header->seq_num),
-                                       ntohs(lsp->lsp_header->checksum),
-                                       ntohs(lsp->lsp_header->rem_lifetime));
-                       }
+                       log_multiline(LOG_DEBUG, "              ", "%s",
+                                     isis_format_tlvs(tlvs));
                        if (isis->debugs & DEBUG_PACKET_DUMP)
                                zlog_dump_data(
                                        STREAM_DATA(circuit->snd_stream),
                                        stream_get_endp(circuit->snd_stream));
                }
 
-               retval = circuit->tx(circuit, level);
+               int retval = circuit->tx(circuit, level);
                if (retval != ISIS_OK) {
                        zlog_err("ISIS-Snp (%s): Send L%d CSNP on %s failed",
                                 circuit->area->area_tag, level,
                                 circuit->interface->name);
-                       list_delete(list);
+                       isis_free_tlvs(tlvs);
                        return retval;
                }
 
@@ -2621,7 +1806,7 @@ int send_csnp(struct isis_circuit *circuit, int level)
                 */
                memcpy(start, stop, ISIS_SYS_ID_LEN + 2);
                loop = 0;
-               for (i = ISIS_SYS_ID_LEN + 1; i >= 0; --i) {
+               for (int i = ISIS_SYS_ID_LEN + 1; i >= 0; --i) {
                        if (start[i] < (u_char)0xff) {
                                start[i] += 1;
                                loop = 1;
@@ -2629,10 +1814,10 @@ int send_csnp(struct isis_circuit *circuit, int level)
                        }
                }
                memset(stop, 0xff, ISIS_SYS_ID_LEN + 2);
-               list_delete(list);
+               isis_free_tlvs(tlvs);
        }
 
-       return retval;
+       return ISIS_OK;
 }
 
 int send_l1_csnp(struct thread *thread)
@@ -2679,120 +1864,12 @@ int send_l2_csnp(struct thread *thread)
        return retval;
 }
 
-static int build_psnp(int level, struct isis_circuit *circuit,
-                     struct list *lsps)
-{
-       struct isis_fixed_hdr fixed_hdr;
-       unsigned long lenp;
-       u_int16_t length;
-       struct isis_lsp *lsp;
-       struct isis_passwd *passwd;
-       struct listnode *node;
-       unsigned char hmac_md5_hash[ISIS_AUTH_MD5_SIZE];
-       unsigned long auth_tlv_offset = 0;
-       int retval = ISIS_OK;
-
-       isis_circuit_stream(circuit, &circuit->snd_stream);
-
-       if (level == IS_LEVEL_1)
-               fill_fixed_hdr_andstream(&fixed_hdr, L1_PARTIAL_SEQ_NUM,
-                                        circuit->snd_stream);
-       else
-               fill_fixed_hdr_andstream(&fixed_hdr, L2_PARTIAL_SEQ_NUM,
-                                        circuit->snd_stream);
-
-       /*
-        * Fill Level 1 or 2 Partial Sequence Numbers header
-        */
-       lenp = stream_get_endp(circuit->snd_stream);
-       stream_putw(circuit->snd_stream, 0); /* PDU length - when we know it */
-       stream_put(circuit->snd_stream, isis->sysid, ISIS_SYS_ID_LEN);
-       stream_putc(circuit->snd_stream, circuit->idx);
-
-       /*
-        * And TLVs
-        */
-
-       if (level == IS_LEVEL_1)
-               passwd = &circuit->area->area_passwd;
-       else
-               passwd = &circuit->area->domain_passwd;
-
-       if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_SEND)) {
-               switch (passwd->type) {
-               /* Cleartext */
-               case ISIS_PASSWD_TYPE_CLEARTXT:
-                       if (tlv_add_authinfo(ISIS_PASSWD_TYPE_CLEARTXT,
-                                            passwd->len, passwd->passwd,
-                                            circuit->snd_stream))
-                               return ISIS_WARNING;
-                       break;
-
-               /* HMAC MD5 */
-               case ISIS_PASSWD_TYPE_HMAC_MD5:
-                       /* Remember where TLV is written so we can later
-                        * overwrite the MD5 hash */
-                       auth_tlv_offset = stream_get_endp(circuit->snd_stream);
-                       memset(&hmac_md5_hash, 0, ISIS_AUTH_MD5_SIZE);
-                       if (tlv_add_authinfo(ISIS_PASSWD_TYPE_HMAC_MD5,
-                                            ISIS_AUTH_MD5_SIZE, hmac_md5_hash,
-                                            circuit->snd_stream))
-                               return ISIS_WARNING;
-                       break;
-
-               default:
-                       break;
-               }
-       }
-
-       retval = tlv_add_lsp_entries(lsps, circuit->snd_stream);
-       if (retval != ISIS_OK)
-               return retval;
-
-       if (isis->debugs & DEBUG_SNP_PACKETS) {
-               for (ALL_LIST_ELEMENTS_RO(lsps, node, lsp)) {
-                       zlog_debug(
-                               "ISIS-Snp (%s):         PSNP entry %s, seq 0x%08x,"
-                               " cksum 0x%04x, lifetime %us",
-                               circuit->area->area_tag,
-                               rawlspid_print(lsp->lsp_header->lsp_id),
-                               ntohl(lsp->lsp_header->seq_num),
-                               ntohs(lsp->lsp_header->checksum),
-                               ntohs(lsp->lsp_header->rem_lifetime));
-               }
-       }
-
-       length = (u_int16_t)stream_get_endp(circuit->snd_stream);
-       /* Update PDU length */
-       stream_putw_at(circuit->snd_stream, lenp, length);
-
-       /* For HMAC MD5 we need to compute the md5 hash and store it */
-       if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_SEND)
-           && passwd->type == ISIS_PASSWD_TYPE_HMAC_MD5) {
-               hmac_md5(STREAM_DATA(circuit->snd_stream),
-                        stream_get_endp(circuit->snd_stream),
-                        (unsigned char *)&passwd->passwd, passwd->len,
-                        (unsigned char *)&hmac_md5_hash);
-               /* Copy the hash into the stream */
-               memcpy(STREAM_DATA(circuit->snd_stream) + auth_tlv_offset + 3,
-                      hmac_md5_hash, ISIS_AUTH_MD5_SIZE);
-       }
-
-       return ISIS_OK;
-}
-
 /*
  *  7.3.15.4 action on expiration of partial SNP interval
  *  level 1
  */
 static int send_psnp(int level, struct isis_circuit *circuit)
 {
-       struct isis_lsp *lsp;
-       struct list *list = NULL;
-       struct listnode *node;
-       u_char num_lsps;
-       int retval = ISIS_OK;
-
        if (circuit->circ_type == CIRCUIT_T_BROADCAST
            && circuit->u.bc.is_dr[level - 1])
                return ISIS_OK;
@@ -2804,25 +1881,64 @@ static int send_psnp(int level, struct isis_circuit *circuit)
        if (!circuit->snd_stream)
                return ISIS_ERROR;
 
-       num_lsps = max_lsps_per_snp(ISIS_SNP_PSNP_FLAG, level, circuit);
+       isis_circuit_stream(circuit, &circuit->snd_stream);
+       fill_fixed_hdr((level == ISIS_LEVEL1) ? L1_PARTIAL_SEQ_NUM
+                                             : L2_PARTIAL_SEQ_NUM,
+                      circuit->snd_stream);
+
+       size_t len_pointer = stream_get_endp(circuit->snd_stream);
+       stream_putw(circuit->snd_stream, 0); /* length is filled in later */
+       stream_put(circuit->snd_stream, isis->sysid, ISIS_SYS_ID_LEN);
+       stream_putc(circuit->snd_stream, circuit->idx);
+
+       struct isis_passwd *passwd = (level == ISIS_LEVEL1)
+                                            ? &circuit->area->area_passwd
+                                            : &circuit->area->domain_passwd;
+
+       struct isis_tlvs *tlvs = isis_alloc_tlvs();
+
+       if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_SEND))
+               isis_tlvs_add_auth(tlvs, passwd);
+
+       size_t tlv_start = stream_get_endp(circuit->snd_stream);
+       if (isis_pack_tlvs(tlvs, circuit->snd_stream, len_pointer, false,
+                          false)) {
+               isis_free_tlvs(tlvs);
+               return ISIS_WARNING;
+       }
+       isis_free_tlvs(tlvs);
+
+       uint16_t num_lsps =
+               get_max_lsp_count(STREAM_WRITEABLE(circuit->snd_stream));
 
        while (1) {
-               list = list_new();
-               lsp_build_list_ssn(circuit, num_lsps, list,
-                                  circuit->area->lspdb[level - 1]);
+               tlvs = isis_alloc_tlvs();
+               if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_SEND))
+                       isis_tlvs_add_auth(tlvs, passwd);
 
-               if (listcount(list) == 0) {
-                       list_delete(list);
+               for (dnode_t *dnode =
+                            dict_first(circuit->area->lspdb[level - 1]);
+                    dnode; dnode = dict_next(circuit->area->lspdb[level - 1],
+                                             dnode)) {
+                       struct isis_lsp *lsp = dnode_get(dnode);
+
+                       if (ISIS_CHECK_FLAG(lsp->SSNflags, circuit))
+                               isis_tlvs_add_lsp_entry(tlvs, lsp);
+
+                       if (tlvs->lsp_entries.count == num_lsps)
+                               break;
+               }
+
+               if (!tlvs->lsp_entries.count) {
+                       isis_free_tlvs(tlvs);
                        return ISIS_OK;
                }
 
-               retval = build_psnp(level, circuit, list);
-               if (retval != ISIS_OK) {
-                       zlog_err("ISIS-Snp (%s): Build L%d PSNP on %s failed",
-                                circuit->area->area_tag, level,
-                                circuit->interface->name);
-                       list_delete(list);
-                       return retval;
+               stream_set_endp(circuit->snd_stream, tlv_start);
+               if (isis_pack_tlvs(tlvs, circuit->snd_stream, len_pointer,
+                                  false, false)) {
+                       isis_free_tlvs(tlvs);
+                       return ISIS_WARNING;
                }
 
                if (isis->debugs & DEBUG_SNP_PACKETS) {
@@ -2831,18 +1947,20 @@ static int send_psnp(int level, struct isis_circuit *circuit)
                                circuit->area->area_tag, level,
                                circuit->interface->name,
                                stream_get_endp(circuit->snd_stream));
+                       log_multiline(LOG_DEBUG, "              ", "%s",
+                                     isis_format_tlvs(tlvs));
                        if (isis->debugs & DEBUG_PACKET_DUMP)
                                zlog_dump_data(
                                        STREAM_DATA(circuit->snd_stream),
                                        stream_get_endp(circuit->snd_stream));
                }
 
-               retval = circuit->tx(circuit, level);
+               int retval = circuit->tx(circuit, level);
                if (retval != ISIS_OK) {
                        zlog_err("ISIS-Snp (%s): Send L%d PSNP on %s failed",
                                 circuit->area->area_tag, level,
                                 circuit->interface->name);
-                       list_delete(list);
+                       isis_free_tlvs(tlvs);
                        return retval;
                }
 
@@ -2850,12 +1968,15 @@ static int send_psnp(int level, struct isis_circuit *circuit)
                 * sending succeeded, we can clear SSN flags of this circuit
                 * for the LSPs in list
                 */
-               for (ALL_LIST_ELEMENTS_RO(list, node, lsp))
-                       ISIS_CLEAR_FLAG(lsp->SSNflags, circuit);
-               list_delete(list);
+               struct isis_lsp_entry *entry_head;
+               entry_head = (struct isis_lsp_entry *)tlvs->lsp_entries.head;
+               for (struct isis_lsp_entry *entry = entry_head; entry;
+                    entry = entry->next)
+                       ISIS_CLEAR_FLAG(entry->lsp->SSNflags, circuit);
+               isis_free_tlvs(tlvs);
        }
 
-       return retval;
+       return ISIS_OK;
 }
 
 int send_l1_psnp(struct thread *thread)
@@ -2963,14 +2084,12 @@ int send_lsp(struct thread *thread)
         * the circuit's MTU. So handle and log this case here. */
        if (stream_get_endp(lsp->pdu) > stream_get_size(circuit->snd_stream)) {
                zlog_err(
-                       "ISIS-Upd (%s): Can't send L%d LSP %s, seq 0x%08x,"
-                       " cksum 0x%04x, lifetime %us on %s. LSP Size is %zu"
-                       " while interface stream size is %zu.",
+                       "ISIS-Upd (%s): Can't send L%d LSP %s, seq 0x%08" PRIx32
+                       ", cksum 0x%04" PRIx16 ", lifetime %" PRIu16
+                       "s on %s. LSP Size is %zu while interface stream size is %zu.",
                        circuit->area->area_tag, lsp->level,
-                       rawlspid_print(lsp->lsp_header->lsp_id),
-                       ntohl(lsp->lsp_header->seq_num),
-                       ntohs(lsp->lsp_header->checksum),
-                       ntohs(lsp->lsp_header->rem_lifetime),
+                       rawlspid_print(lsp->hdr.lsp_id), lsp->hdr.seqno,
+                       lsp->hdr.checksum, lsp->hdr.rem_lifetime,
                        circuit->interface->name, stream_get_endp(lsp->pdu),
                        stream_get_size(circuit->snd_stream));
                if (isis->debugs & DEBUG_PACKET_DUMP)
@@ -2984,15 +2103,13 @@ int send_lsp(struct thread *thread)
        stream_copy(circuit->snd_stream, lsp->pdu);
 
        if (isis->debugs & DEBUG_UPDATE_PACKETS) {
-               zlog_debug(
-                       "ISIS-Upd (%s): Sending L%d LSP %s, seq 0x%08x, cksum 0x%04x,"
-                       " lifetime %us on %s",
-                       circuit->area->area_tag, lsp->level,
-                       rawlspid_print(lsp->lsp_header->lsp_id),
-                       ntohl(lsp->lsp_header->seq_num),
-                       ntohs(lsp->lsp_header->checksum),
-                       ntohs(lsp->lsp_header->rem_lifetime),
-                       circuit->interface->name);
+               zlog_debug("ISIS-Upd (%s): Sending L%d LSP %s, seq 0x%08" PRIx32
+                          ", cksum 0x%04" PRIx16 ", lifetime %" PRIu16
+                          "s on %s",
+                          circuit->area->area_tag, lsp->level,
+                          rawlspid_print(lsp->hdr.lsp_id), lsp->hdr.seqno,
+                          lsp->hdr.checksum, lsp->hdr.rem_lifetime,
+                          circuit->interface->name);
                if (isis->debugs & DEBUG_PACKET_DUMP)
                        zlog_dump_data(STREAM_DATA(circuit->snd_stream),
                                       stream_get_endp(circuit->snd_stream));
@@ -3026,47 +2143,3 @@ out:
 
        return retval;
 }
-
-int ack_lsp(struct isis_link_state_hdr *hdr, struct isis_circuit *circuit,
-           int level)
-{
-       unsigned long lenp;
-       int retval;
-       u_int16_t length;
-       struct isis_fixed_hdr fixed_hdr;
-
-       isis_circuit_stream(circuit, &circuit->snd_stream);
-
-       //  fill_llc_hdr (stream);
-       if (level == IS_LEVEL_1)
-               fill_fixed_hdr_andstream(&fixed_hdr, L1_PARTIAL_SEQ_NUM,
-                                        circuit->snd_stream);
-       else
-               fill_fixed_hdr_andstream(&fixed_hdr, L2_PARTIAL_SEQ_NUM,
-                                        circuit->snd_stream);
-
-
-       lenp = stream_get_endp(circuit->snd_stream);
-       stream_putw(circuit->snd_stream, 0); /* PDU length  */
-       stream_put(circuit->snd_stream, isis->sysid, ISIS_SYS_ID_LEN);
-       stream_putc(circuit->snd_stream, circuit->idx);
-       stream_putc(circuit->snd_stream, 9);  /* code */
-       stream_putc(circuit->snd_stream, 16); /* len */
-
-       stream_putw(circuit->snd_stream, ntohs(hdr->rem_lifetime));
-       stream_put(circuit->snd_stream, hdr->lsp_id, ISIS_SYS_ID_LEN + 2);
-       stream_putl(circuit->snd_stream, ntohl(hdr->seq_num));
-       stream_putw(circuit->snd_stream, ntohs(hdr->checksum));
-
-       length = (u_int16_t)stream_get_endp(circuit->snd_stream);
-       /* Update PDU length */
-       stream_putw_at(circuit->snd_stream, lenp, length);
-
-       retval = circuit->tx(circuit, level);
-       if (retval != ISIS_OK)
-               zlog_err("ISIS-Upd (%s): Send L%d LSP PSNP on %s failed",
-                        circuit->area->area_tag, level,
-                        circuit->interface->name);
-
-       return retval;
-}
index fa8006cda034af6e6176cb99df6717d58eff43f5..7096761879394591f830f7554d30f6d6707ed5ca 100644 (file)
@@ -65,36 +65,6 @@ struct esis_fixed_hdr {
 #define ISH_PDU              4
 #define RD_PDU               5
 
-/*
- *                       IS to IS Fixed Header
- *  +-------+-------+-------+-------+-------+-------+-------+-------+
- *  |         Intradomain Routeing Protocol Discriminator           |
- *  +-------+-------+-------+-------+-------+-------+-------+-------+
- *  |                       Length Indicator                        |
- *  +-------+-------+-------+-------+-------+-------+-------+-------+
- *  |                  Version/Protocol ID extension                |
- *  +-------+-------+-------+-------+-------+-------+-------+-------+
- *  |   R   |   R   |   R   |              PDU Type                 |
- *  +-------+-------+-------+-------+-------+-------+-------+-------+
- *  |                            Version                            |
- *  +-------+-------+-------+-------+-------+-------+-------+-------+
- *  |                            Reserved                           |
- *  +-------+-------+-------+-------+-------+-------+-------+-------+
- *  |                       Maximum Area Addresses                  |
- *  +-------+-------+-------+-------+-------+-------+-------+-------+
- */
-
-struct isis_fixed_hdr {
-       u_char idrp;
-       u_char length;
-       u_char version1;
-       u_char id_len;
-       u_char pdu_type;
-       u_char version2;
-       u_char reserved;
-       u_char max_area_addrs;
-} __attribute__((packed));
-
 #define ISIS_FIXED_HDR_LEN 8
 
 /*
@@ -155,30 +125,14 @@ struct isis_p2p_hello_hdr {
 
 #define L1_LINK_STATE        18
 #define L2_LINK_STATE        20
-/*
- *              L1 and L2 IS to IS link state PDU header
- * +-------+-------+-------+-------+-------+-------+-------+-------+
- * +                        PDU Length                             + 2
- * +-------+-------+-------+-------+-------+-------+-------+-------+
- * +                        Remaining Lifetime                     + 2
- * +-------+-------+-------+-------+-------+-------+-------+-------+
- * |                        LSP ID                                 | id_len + 2
- * +-------+-------+-------+-------+-------+-------+-------+-------+
- * +                        Sequence Number                        + 4
- * +-------+-------+-------+-------+-------+-------+-------+-------+
- * +                        Checksum                               + 2
- * +-------+-------+-------+-------+-------+-------+-------+-------+
- * |   P   |              ATT              |LSPDBOL|    ISTYPE     |
- * +-------+-------+-------+-------+-------+-------+-------+-------+
- */
-struct isis_link_state_hdr {
-       u_int16_t pdu_len;
-       u_int16_t rem_lifetime;
-       u_char lsp_id[ISIS_SYS_ID_LEN + 2];
-       u_int32_t seq_num;
-       u_int16_t checksum;
-       u_int8_t lsp_bits;
-} __attribute__((packed));
+struct isis_lsp_hdr {
+       uint16_t pdu_len;
+       uint16_t rem_lifetime;
+       uint8_t lsp_id[ISIS_SYS_ID_LEN + 2];
+       uint32_t seqno;
+       uint16_t checksum;
+       uint8_t lsp_bits;
+};
 #define ISIS_LSP_HDR_LEN 19
 
 /*
@@ -259,9 +213,7 @@ int send_l2_csnp(struct thread *thread);
 int send_l1_psnp(struct thread *thread);
 int send_l2_psnp(struct thread *thread);
 int send_lsp(struct thread *thread);
-int ack_lsp(struct isis_link_state_hdr *hdr, struct isis_circuit *circuit,
-           int level);
-void fill_fixed_hdr(struct isis_fixed_hdr *hdr, u_char pdu_type);
+void fill_fixed_hdr(uint8_t pdu_type, struct stream *stream);
 int send_hello(struct isis_circuit *circuit, int level);
 
 #endif /* _ZEBRA_ISIS_PDU_H */
index 8e329494dd5b9e903cf6c91c41d2456e1514bbb0..ea94b6580544b6550fa37edd90e727cb0eedf84c 100644 (file)
@@ -37,7 +37,6 @@
 #include "isisd/isis_flags.h"
 #include "isisd/isis_misc.h"
 #include "isisd/isis_circuit.h"
-#include "isisd/isis_tlv.h"
 #include "isisd/isisd.h"
 #include "isisd/isis_lsp.h"
 #include "isisd/isis_route.h"
index afc4f651288baeab2ff992a1c189aaa11dd67e8e..267e72002f041f352c63ae0c2990986a9f25b241 100644 (file)
@@ -42,7 +42,6 @@
 #include "isis_misc.h"
 #include "isis_adjacency.h"
 #include "isis_circuit.h"
-#include "isis_tlv.h"
 #include "isis_pdu.h"
 #include "isis_lsp.h"
 #include "isis_spf.h"
@@ -208,13 +207,12 @@ static void nexthops6_print(struct list *nhs6)
 static void adjinfo2nexthop(struct list *nexthops, struct isis_adjacency *adj)
 {
        struct isis_nexthop *nh;
-       struct listnode *node;
-       struct in_addr *ipv4_addr;
 
-       if (adj->ipv4_addrs == NULL)
+       if (!adj->ipv4_address_count)
                return;
 
-       for (ALL_LIST_ELEMENTS_RO(adj->ipv4_addrs, node, ipv4_addr)) {
+       for (unsigned int i = 0; i < adj->ipv4_address_count; i++) {
+               struct in_addr *ipv4_addr = &adj->ipv4_addresses[i];
                if (!nexthoplookup(nexthops, ipv4_addr,
                                   adj->circuit->interface->ifindex)) {
                        nh = isis_nexthop_create(
@@ -227,14 +225,13 @@ static void adjinfo2nexthop(struct list *nexthops, struct isis_adjacency *adj)
 
 static void adjinfo2nexthop6(struct list *nexthops6, struct isis_adjacency *adj)
 {
-       struct listnode *node;
-       struct in6_addr *ipv6_addr;
        struct isis_nexthop6 *nh6;
 
-       if (!adj->ipv6_addrs)
+       if (!adj->ipv6_address_count)
                return;
 
-       for (ALL_LIST_ELEMENTS_RO(adj->ipv6_addrs, node, ipv6_addr)) {
+       for (unsigned int i = 0; i < adj->ipv6_address_count; i++) {
+               struct in6_addr *ipv6_addr = &adj->ipv6_addresses[i];
                if (!nexthop6lookup(nexthops6, ipv6_addr,
                                    adj->circuit->interface->ifindex)) {
                        nh6 = isis_nexthop6_create(
index 44d7fa0403d63a1dbaf714347b7510ed22422892..d92207d57c6b7a60dcc7e6958c4102869b2482b7 100644 (file)
@@ -42,7 +42,6 @@
 #include "isis_misc.h"
 #include "isis_adjacency.h"
 #include "isis_circuit.h"
-#include "isis_tlv.h"
 #include "isis_pdu.h"
 #include "isis_lsp.h"
 #include "isis_spf.h"
index 615c2eeaa2c89ccfb00344e264ef52026e36fd8f..9acbc21838459a5d9ace187ccb8789473be3bd84 100644 (file)
@@ -35,6 +35,7 @@
 #include "if.h"
 #include "table.h"
 #include "spf_backoff.h"
+#include "jhash.h"
 
 #include "isis_constants.h"
 #include "isis_common.h"
@@ -44,7 +45,6 @@
 #include "isis_misc.h"
 #include "isis_adjacency.h"
 #include "isis_circuit.h"
-#include "isis_tlv.h"
 #include "isis_pdu.h"
 #include "isis_lsp.h"
 #include "isis_dynhn.h"
 #include "isis_route.h"
 #include "isis_csm.h"
 #include "isis_mt.h"
+#include "isis_tlvs.h"
 
 DEFINE_MTYPE_STATIC(ISISD, ISIS_SPF_RUN, "ISIS SPF Run Info");
 
+enum vertextype {
+       VTYPE_PSEUDO_IS = 1,
+       VTYPE_PSEUDO_TE_IS,
+       VTYPE_NONPSEUDO_IS,
+       VTYPE_NONPSEUDO_TE_IS,
+       VTYPE_ES,
+       VTYPE_IPREACH_INTERNAL,
+       VTYPE_IPREACH_EXTERNAL,
+       VTYPE_IPREACH_TE,
+       VTYPE_IP6REACH_INTERNAL,
+       VTYPE_IP6REACH_EXTERNAL
+};
+
+#define VTYPE_IS(t) ((t) >= VTYPE_PSEUDO_IS && (t) <= VTYPE_NONPSEUDO_TE_IS)
+#define VTYPE_ES(t) ((t) == VTYPE_ES)
+#define VTYPE_IP(t) ((t) >= VTYPE_IPREACH_INTERNAL && (t) <= VTYPE_IP6REACH_EXTERNAL)
+
+/*
+ * Triple <N, d(N), {Adj(N)}>
+ */
+struct isis_vertex {
+       enum vertextype type;
+
+       union {
+               u_char id[ISIS_SYS_ID_LEN + 1];
+               struct prefix prefix;
+       } N;
+
+       u_int32_t d_N;         /* d(N) Distance from this IS      */
+       u_int16_t depth;       /* The depth in the imaginary tree */
+       struct list *Adj_N;    /* {Adj(N)} next hop or neighbor list */
+       struct list *parents;  /* list of parents for ECMP */
+       struct list *children; /* list of children used for tree dump */
+};
+
+/* Vertex Queue and associated functions */
+
+struct isis_vertex_queue {
+       struct list *list;
+       struct hash *hash;
+};
+
+static unsigned isis_vertex_queue_hash_key(void *vp)
+{
+       struct isis_vertex *vertex = vp;
+
+       if (VTYPE_IP(vertex->type))
+               return prefix_hash_key(&vertex->N.prefix);
+
+       return jhash(vertex->N.id, ISIS_SYS_ID_LEN + 1, 0x55aa5a5a);
+}
+
+static int isis_vertex_queue_hash_cmp(const void *a, const void *b)
+{
+       const struct isis_vertex *va = a, *vb = b;
+
+       if (va->type != vb->type)
+               return 0;
+
+       if (VTYPE_IP(va->type))
+               return prefix_cmp(&va->N.prefix, &vb->N.prefix) == 0;
+
+       return memcmp(va->N.id, vb->N.id, ISIS_SYS_ID_LEN + 1) == 0;
+}
+
+static void isis_vertex_queue_init(struct isis_vertex_queue *queue, const char *name)
+{
+       queue->list = list_new();
+       queue->hash = hash_create(isis_vertex_queue_hash_key,
+                                 isis_vertex_queue_hash_cmp,
+                                 name);
+}
+
+static void isis_vertex_del(struct isis_vertex *vertex);
+
+static void isis_vertex_queue_clear(struct isis_vertex_queue *queue)
+{
+       hash_clean(queue->hash, NULL);
+
+       queue->list->del = (void (*)(void *))isis_vertex_del;
+       list_delete_all_node(queue->list);
+       queue->list->del = NULL;
+}
+
+static void isis_vertex_queue_free(struct isis_vertex_queue *queue)
+{
+       isis_vertex_queue_clear(queue);
+
+       hash_free(queue->hash);
+       queue->hash = NULL;
+
+       list_delete(queue->list);
+       queue->list = NULL;
+}
+
+static unsigned int isis_vertex_queue_count(struct isis_vertex_queue *queue)
+{
+       return listcount(queue->list);
+}
+
+static void isis_vertex_queue_add(struct isis_vertex_queue *queue,
+                                 struct isis_vertex *vertex)
+{
+       listnode_add(queue->list, vertex);
+
+       struct isis_vertex *inserted;
+
+       inserted = hash_get(queue->hash, vertex, hash_alloc_intern);
+       assert(inserted == vertex);
+}
+
+static struct isis_vertex *isis_vertex_queue_pop(struct isis_vertex_queue *queue)
+{
+       struct listnode *node;
+
+       node = listhead(queue->list);
+       if (!node)
+               return NULL;
+
+       struct isis_vertex *rv = listgetdata(node);
+
+       list_delete_node(queue->list, node);
+       hash_release(queue->hash, rv);
+
+       return rv;
+}
+
+static void isis_vertex_queue_delete(struct isis_vertex_queue *queue,
+                                    struct isis_vertex *vertex)
+{
+       listnode_delete(queue->list, vertex);
+       hash_release(queue->hash, vertex);
+}
+
+#define ALL_QUEUE_ELEMENTS_RO(queue, node, data) \
+               ALL_LIST_ELEMENTS_RO((queue)->list, node, data)
+
+
+/* End of vertex queue definitions */
+
+struct isis_spftree {
+       struct isis_vertex_queue paths; /* the SPT */
+       struct isis_vertex_queue tents; /* TENT */
+       struct isis_area *area;    /* back pointer to area */
+       unsigned int runcount;     /* number of runs since uptime */
+       time_t last_run_timestamp; /* last run timestamp for scheduling */
+       time_t last_run_duration;  /* last run duration in msec */
+
+       uint16_t mtid;
+       int family;
+       int level;
+};
+
+
+/*
+ *  supports the given af ?
+ */
+static bool speaks(uint8_t *protocols, uint8_t count, int family)
+{
+       for (uint8_t i = 0; i < count; i++) {
+               if (family == AF_INET && protocols[i] == NLPID_IP)
+                       return true;
+               if (family == AF_INET6 && protocols[i] == NLPID_IPV6)
+                       return true;
+       }
+       return false;
+}
+
 struct isis_spf_run {
        struct isis_area *area;
        int level;
@@ -160,12 +329,8 @@ static const char *vid2string(struct isis_vertex *vertex, char *buff, int size)
        return "UNKNOWN";
 }
 
-static struct isis_vertex *isis_vertex_new(void *id, enum vertextype vtype)
+static void isis_vertex_id_init(struct isis_vertex *vertex, void *id, enum vertextype vtype)
 {
-       struct isis_vertex *vertex;
-
-       vertex = XCALLOC(MTYPE_ISIS_VERTEX, sizeof(struct isis_vertex));
-
        vertex->type = vtype;
 
        if (VTYPE_IS(vtype) || VTYPE_ES(vtype)) {
@@ -176,6 +341,15 @@ static struct isis_vertex *isis_vertex_new(void *id, enum vertextype vtype)
        } else {
                zlog_err("WTF!");
        }
+}
+
+static struct isis_vertex *isis_vertex_new(void *id, enum vertextype vtype)
+{
+       struct isis_vertex *vertex;
+
+       vertex = XCALLOC(MTYPE_ISIS_VERTEX, sizeof(struct isis_vertex));
+
+       isis_vertex_id_init(vertex, id, vtype);
 
        vertex->Adj_N = list_new();
        vertex->parents = list_new();
@@ -223,8 +397,8 @@ struct isis_spftree *isis_spftree_new(struct isis_area *area)
                return NULL;
        }
 
-       tree->tents = list_new();
-       tree->paths = list_new();
+       isis_vertex_queue_init(&tree->tents, "IS-IS SPF tents");
+       isis_vertex_queue_init(&tree->paths, "IS-IS SPF paths");
        tree->area = area;
        tree->last_run_timestamp = 0;
        tree->last_run_duration = 0;
@@ -234,15 +408,8 @@ struct isis_spftree *isis_spftree_new(struct isis_area *area)
 
 void isis_spftree_del(struct isis_spftree *spftree)
 {
-
-       spftree->tents->del = (void (*)(void *))isis_vertex_del;
-       list_delete(spftree->tents);
-       spftree->tents = NULL;
-
-       spftree->paths->del = (void (*)(void *))isis_vertex_del;
-       list_delete(spftree->paths);
-       spftree->paths = NULL;
-
+       isis_vertex_queue_free(&spftree->tents);
+       isis_vertex_queue_free(&spftree->paths);
        XFREE(MTYPE_ISIS_SPFTREE, spftree);
 
        return;
@@ -252,12 +419,13 @@ static void isis_spftree_adj_del(struct isis_spftree *spftree,
                                 struct isis_adjacency *adj)
 {
        struct listnode *node;
+       struct isis_vertex *v;
        if (!adj)
                return;
-       for (node = listhead(spftree->tents); node; node = listnextnode(node))
-               isis_vertex_adj_del(listgetdata(node), adj);
-       for (node = listhead(spftree->paths); node; node = listnextnode(node))
-               isis_vertex_adj_del(listgetdata(node), adj);
+       for (ALL_QUEUE_ELEMENTS_RO(&spftree->tents, node, v))
+               isis_vertex_adj_del(v, adj);
+       for (ALL_QUEUE_ELEMENTS_RO(&spftree->paths, node, v))
+               isis_vertex_adj_del(v, adj);
        return;
 }
 
@@ -340,7 +508,7 @@ static struct isis_lsp *isis_root_system_lsp(struct isis_area *area, int level,
        LSP_PSEUDO_ID(lspid) = 0;
        LSP_FRAGMENT(lspid) = 0;
        lsp = lsp_search(lspid, area->lspdb[level - 1]);
-       if (lsp && lsp->lsp_header->rem_lifetime != 0)
+       if (lsp && lsp->hdr.rem_lifetime != 0)
                return lsp;
        return NULL;
 }
@@ -370,7 +538,7 @@ static struct isis_vertex *isis_spf_add_root(struct isis_spftree *spftree,
                                 spftree->area->oldmetric
                                         ? VTYPE_NONPSEUDO_IS
                                         : VTYPE_NONPSEUDO_TE_IS);
-       listnode_add(spftree->paths, vertex);
+       isis_vertex_queue_add(&spftree->paths, vertex);
 
 #ifdef EXTREME_DEBUG
        zlog_debug("ISIS-Spf: added this IS  %s %s depth %d dist %d to PATHS",
@@ -382,35 +550,13 @@ static struct isis_vertex *isis_spf_add_root(struct isis_spftree *spftree,
        return vertex;
 }
 
-static struct isis_vertex *isis_find_vertex(struct list *list, void *id,
+static struct isis_vertex *isis_find_vertex(struct isis_vertex_queue *queue, void *id,
                                            enum vertextype vtype)
 {
-       struct listnode *node;
-       struct isis_vertex *vertex;
-       struct prefix *p1, *p2;
+       struct isis_vertex querier;
 
-       for (ALL_LIST_ELEMENTS_RO(list, node, vertex)) {
-               if (vertex->type != vtype)
-                       continue;
-               if (VTYPE_IS(vertex->type) || VTYPE_ES(vertex->type)) {
-                       if (memcmp((u_char *)id, vertex->N.id,
-                                  ISIS_SYS_ID_LEN + 1)
-                           == 0)
-                               return vertex;
-               }
-               if (VTYPE_IP(vertex->type)) {
-                       p1 = (struct prefix *)id;
-                       p2 = (struct prefix *)&vertex->N.id;
-                       if (p1->family == p2->family
-                           && p1->prefixlen == p2->prefixlen
-                           && !memcmp(&p1->u.prefix, &p2->u.prefix,
-                                      PSIZE(p1->prefixlen))) {
-                               return vertex;
-                       }
-               }
-       }
-
-       return NULL;
+       isis_vertex_id_init(&querier, id, vtype);
+       return hash_lookup(queue->hash, &querier);
 }
 
 /*
@@ -428,6 +574,30 @@ static bool tent_cmp(struct isis_vertex *current, struct isis_vertex *candidate)
        return false;
 }
 
+static void isis_vertex_queue_insert(struct isis_vertex_queue *queue,
+                                    struct isis_vertex *vertex)
+{
+       struct listnode *node;
+       struct isis_vertex *v;
+
+       /* XXX: This cant use the standard ALL_LIST_ELEMENTS macro */
+       for (node = listhead(queue->list); node; node = listnextnode(node)) {
+               v = listgetdata(node);
+               if (tent_cmp(v, vertex)) {
+                       listnode_add_before(queue->list, node, vertex);
+                       break;
+               }
+       }
+
+       if (node == NULL)
+               listnode_add(queue->list, vertex);
+
+       struct isis_vertex *inserted;
+
+       inserted = hash_get(queue->hash, vertex, hash_alloc_intern);
+       assert(inserted == vertex);
+}
+
 /*
  * Add a vertex to TENT sorted by cost and by vertextype on tie break situation
  */
@@ -437,15 +607,15 @@ static struct isis_vertex *isis_spf_add2tent(struct isis_spftree *spftree,
                                             struct isis_adjacency *adj,
                                             struct isis_vertex *parent)
 {
-       struct isis_vertex *vertex, *v;
+       struct isis_vertex *vertex;
        struct listnode *node;
        struct isis_adjacency *parent_adj;
 #ifdef EXTREME_DEBUG
        char buff[PREFIX2STR_BUFFER];
 #endif
 
-       assert(isis_find_vertex(spftree->paths, id, vtype) == NULL);
-       assert(isis_find_vertex(spftree->tents, id, vtype) == NULL);
+       assert(isis_find_vertex(&spftree->paths, id, vtype) == NULL);
+       assert(isis_find_vertex(&spftree->tents, id, vtype) == NULL);
        vertex = isis_vertex_new(id, vtype);
        vertex->d_N = cost;
        vertex->depth = depth;
@@ -471,23 +641,7 @@ static struct isis_vertex *isis_spf_add2tent(struct isis_spftree *spftree,
                vertex->d_N, listcount(vertex->Adj_N));
 #endif /* EXTREME_DEBUG */
 
-       if (list_isempty(spftree->tents)) {
-               listnode_add(spftree->tents, vertex);
-               return vertex;
-       }
-
-       /* XXX: This cant use the standard ALL_LIST_ELEMENTS macro */
-       for (node = listhead(spftree->tents); node; node = listnextnode(node)) {
-               v = listgetdata(node);
-               if (tent_cmp(v, vertex)) {
-                       listnode_add_before(spftree->tents, node, vertex);
-                       break;
-               }
-       }
-
-       if (node == NULL)
-               listnode_add(spftree->tents, vertex);
-
+       isis_vertex_queue_insert(&spftree->tents, vertex);
        return vertex;
 }
 
@@ -498,7 +652,7 @@ static void isis_spf_add_local(struct isis_spftree *spftree,
 {
        struct isis_vertex *vertex;
 
-       vertex = isis_find_vertex(spftree->tents, id, vtype);
+       vertex = isis_find_vertex(&spftree->tents, id, vtype);
 
        if (vertex) {
                /* C.2.5   c) */
@@ -522,7 +676,7 @@ static void isis_spf_add_local(struct isis_spftree *spftree,
                        /*         f) */
                        struct listnode *pnode, *pnextnode;
                        struct isis_vertex *pvertex;
-                       listnode_delete(spftree->tents, vertex);
+                       isis_vertex_queue_delete(&spftree->tents, vertex);
                        assert(listcount(vertex->children) == 0);
                        for (ALL_LIST_ELEMENTS(vertex->parents, pnode,
                                               pnextnode, pvertex))
@@ -546,6 +700,13 @@ static void process_N(struct isis_spftree *spftree, enum vertextype vtype,
 
        assert(spftree && parent);
 
+       struct prefix p;
+       if (vtype >= VTYPE_IPREACH_INTERNAL) {
+               prefix_copy(&p, id);
+               apply_mask(&p);
+               id = &p;
+       }
+
        /* RFC3787 section 5.1 */
        if (spftree->area->newmetric == 1) {
                if (dist > MAX_WIDE_PATH_METRIC)
@@ -558,7 +719,7 @@ static void process_N(struct isis_spftree *spftree, enum vertextype vtype,
        }
 
        /*       c)    */
-       vertex = isis_find_vertex(spftree->paths, id, vtype);
+       vertex = isis_find_vertex(&spftree->paths, id, vtype);
        if (vertex) {
 #ifdef EXTREME_DEBUG
                zlog_debug(
@@ -570,7 +731,7 @@ static void process_N(struct isis_spftree *spftree, enum vertextype vtype,
                return;
        }
 
-       vertex = isis_find_vertex(spftree->tents, id, vtype);
+       vertex = isis_find_vertex(&spftree->tents, id, vtype);
        /*       d)    */
        if (vertex) {
 /*        1) */
@@ -605,7 +766,7 @@ static void process_N(struct isis_spftree *spftree, enum vertextype vtype,
                } else {
                        struct listnode *pnode, *pnextnode;
                        struct isis_vertex *pvertex;
-                       listnode_delete(spftree->tents, vertex);
+                       isis_vertex_queue_delete(&spftree->tents, vertex);
                        assert(listcount(vertex->children) == 0);
                        for (ALL_LIST_ELEMENTS(vertex->parents, pnode,
                                               pnextnode, pvertex))
@@ -632,30 +793,35 @@ static int isis_spf_process_lsp(struct isis_spftree *spftree,
                                uint16_t depth, u_char *root_sysid,
                                struct isis_vertex *parent)
 {
-       bool pseudo_lsp = LSP_PSEUDO_ID(lsp->lsp_header->lsp_id);
-       struct listnode *node, *fragnode = NULL;
+       bool pseudo_lsp = LSP_PSEUDO_ID(lsp->hdr.lsp_id);
+       struct listnode *fragnode = NULL;
        uint32_t dist;
-       struct is_neigh *is_neigh;
-       struct te_is_neigh *te_is_neigh;
-       struct ipv4_reachability *ipreach;
-       struct te_ipv4_reachability *te_ipv4_reach;
        enum vertextype vtype;
-       struct prefix prefix;
-       struct ipv6_reachability *ip6reach;
        static const u_char null_sysid[ISIS_SYS_ID_LEN];
-       struct mt_router_info *mt_router_info = NULL;
+       struct isis_mt_router_info *mt_router_info = NULL;
+
+       if (!lsp->tlvs)
+               return ISIS_OK;
 
        if (spftree->mtid != ISIS_MT_IPV4_UNICAST)
-               mt_router_info = tlvs_lookup_mt_router_info(&lsp->tlv_data,
-                                                           spftree->mtid);
+               mt_router_info = isis_tlvs_lookup_mt_router_info(lsp->tlvs,
+                                                                spftree->mtid);
 
        if (!pseudo_lsp && (spftree->mtid == ISIS_MT_IPV4_UNICAST
-                           && !speaks(lsp->tlv_data.nlpids, spftree->family))
+                           && !speaks(lsp->tlvs->protocols_supported.protocols,
+                                      lsp->tlvs->protocols_supported.count,
+                                      spftree->family))
            && !mt_router_info)
                return ISIS_OK;
 
+       /* RFC3787 section 4 SHOULD ignore overload bit in pseudo LSPs */
+       bool no_overload = (pseudo_lsp
+                           || (spftree->mtid == ISIS_MT_IPV4_UNICAST
+                               && !ISIS_MASK_LSP_OL_BIT(lsp->hdr.lsp_bits))
+                           || (mt_router_info && !mt_router_info->overload));
+
 lspfragloop:
-       if (lsp->lsp_header->seq_num == 0) {
+       if (lsp->hdr.seqno == 0) {
                zlog_warn(
                        "isis_spf_process_lsp(): lsp with 0 seq_num - ignore");
                return ISIS_WARNING;
@@ -663,142 +829,117 @@ lspfragloop:
 
 #ifdef EXTREME_DEBUG
        zlog_debug("ISIS-Spf: process_lsp %s",
-                  print_sys_hostname(lsp->lsp_header->lsp_id));
+                  print_sys_hostname(lsp->hdr.lsp_id));
 #endif /* EXTREME_DEBUG */
 
-       /* RFC3787 section 4 SHOULD ignore overload bit in pseudo LSPs */
-       if (pseudo_lsp || (spftree->mtid == ISIS_MT_IPV4_UNICAST
-                          && !ISIS_MASK_LSP_OL_BIT(lsp->lsp_header->lsp_bits))
-           || (mt_router_info && !mt_router_info->overload))
-
-       {
+       if (no_overload) {
                if (pseudo_lsp || spftree->mtid == ISIS_MT_IPV4_UNICAST) {
-                       for (ALL_LIST_ELEMENTS_RO(lsp->tlv_data.is_neighs, node,
-                                                 is_neigh)) {
+                       struct isis_oldstyle_reach *r;
+                       for (r = (struct isis_oldstyle_reach *)
+                                        lsp->tlvs->oldstyle_reach.head;
+                            r; r = r->next) {
                                /* C.2.6 a) */
                                /* Two way connectivity */
-                               if (!memcmp(is_neigh->neigh_id, root_sysid,
-                                           ISIS_SYS_ID_LEN))
+                               if (!memcmp(r->id, root_sysid, ISIS_SYS_ID_LEN))
                                        continue;
                                if (!pseudo_lsp
-                                   && !memcmp(is_neigh->neigh_id, null_sysid,
+                                   && !memcmp(r->id, null_sysid,
                                               ISIS_SYS_ID_LEN))
                                        continue;
-                               dist = cost + is_neigh->metrics.metric_default;
+                               dist = cost + r->metric;
                                process_N(spftree,
-                                         LSP_PSEUDO_ID(is_neigh->neigh_id)
+                                         LSP_PSEUDO_ID(r->id)
                                                  ? VTYPE_PSEUDO_IS
                                                  : VTYPE_NONPSEUDO_IS,
-                                         (void *)is_neigh->neigh_id, dist,
-                                         depth + 1, parent);
+                                         (void *)r->id, dist, depth + 1,
+                                         parent);
                        }
                }
 
-               struct list *te_is_neighs = NULL;
-               if (pseudo_lsp || spftree->mtid == ISIS_MT_IPV4_UNICAST) {
-                       te_is_neighs = lsp->tlv_data.te_is_neighs;
-               } else {
-                       struct tlv_mt_neighbors *mt_neighbors;
-                       mt_neighbors = tlvs_lookup_mt_neighbors(&lsp->tlv_data,
-                                                               spftree->mtid);
-                       if (mt_neighbors)
-                               te_is_neighs = mt_neighbors->list;
-               }
-               for (ALL_LIST_ELEMENTS_RO(te_is_neighs, node, te_is_neigh)) {
-                       if (!memcmp(te_is_neigh->neigh_id, root_sysid,
-                                   ISIS_SYS_ID_LEN))
+               struct isis_item_list *te_neighs = NULL;
+               if (pseudo_lsp || spftree->mtid == ISIS_MT_IPV4_UNICAST)
+                       te_neighs = &lsp->tlvs->extended_reach;
+               else
+                       te_neighs = isis_lookup_mt_items(&lsp->tlvs->mt_reach,
+                                                        spftree->mtid);
+
+               struct isis_extended_reach *er;
+               for (er = te_neighs
+                                 ? (struct isis_extended_reach *)
+                                           te_neighs->head
+                                 : NULL;
+                    er; er = er->next) {
+                       if (!memcmp(er->id, root_sysid, ISIS_SYS_ID_LEN))
                                continue;
                        if (!pseudo_lsp
-                           && !memcmp(te_is_neigh->neigh_id, null_sysid,
-                                      ISIS_SYS_ID_LEN))
+                           && !memcmp(er->id, null_sysid, ISIS_SYS_ID_LEN))
                                continue;
-                       dist = cost + GET_TE_METRIC(te_is_neigh);
+                       dist = cost + er->metric;
                        process_N(spftree,
-                                 LSP_PSEUDO_ID(te_is_neigh->neigh_id)
-                                         ? VTYPE_PSEUDO_TE_IS
-                                         : VTYPE_NONPSEUDO_TE_IS,
-                                 (void *)te_is_neigh->neigh_id, dist,
-                                 depth + 1, parent);
+                                 LSP_PSEUDO_ID(er->id) ? VTYPE_PSEUDO_TE_IS
+                                                       : VTYPE_NONPSEUDO_TE_IS,
+                                 (void *)er->id, dist, depth + 1, parent);
                }
        }
 
        if (!pseudo_lsp && spftree->family == AF_INET
            && spftree->mtid == ISIS_MT_IPV4_UNICAST) {
-               struct list *reachs[] = {lsp->tlv_data.ipv4_int_reachs,
-                                        lsp->tlv_data.ipv4_ext_reachs};
+               struct isis_item_list *reachs[] = {
+                       &lsp->tlvs->oldstyle_ip_reach,
+                       &lsp->tlvs->oldstyle_ip_reach_ext};
 
-               prefix.family = AF_INET;
                for (unsigned int i = 0; i < array_size(reachs); i++) {
-                       vtype = (reachs[i] == lsp->tlv_data.ipv4_int_reachs)
-                                       ? VTYPE_IPREACH_INTERNAL
-                                       : VTYPE_IPREACH_EXTERNAL;
-                       for (ALL_LIST_ELEMENTS_RO(reachs[i], node, ipreach)) {
-                               dist = cost + ipreach->metrics.metric_default;
-                               prefix.u.prefix4 = ipreach->prefix;
-                               prefix.prefixlen = ip_masklen(ipreach->mask);
-                               apply_mask(&prefix);
-                               process_N(spftree, vtype, (void *)&prefix, dist,
-                                         depth + 1, parent);
+                       vtype = i ? VTYPE_IPREACH_EXTERNAL
+                                 : VTYPE_IPREACH_INTERNAL;
+
+                       struct isis_oldstyle_ip_reach *r;
+                       for (r = (struct isis_oldstyle_ip_reach *)reachs[i]
+                                        ->head;
+                            r; r = r->next) {
+                               dist = cost + r->metric;
+                               process_N(spftree, vtype, (void *)&r->prefix,
+                                         dist, depth + 1, parent);
                        }
                }
        }
 
        if (!pseudo_lsp && spftree->family == AF_INET) {
-               struct list *ipv4reachs = NULL;
-
-               if (spftree->mtid == ISIS_MT_IPV4_UNICAST) {
-                       ipv4reachs = lsp->tlv_data.te_ipv4_reachs;
-               } else {
-                       struct tlv_mt_ipv4_reachs *mt_reachs;
-                       mt_reachs = tlvs_lookup_mt_ipv4_reachs(&lsp->tlv_data,
-                                                              spftree->mtid);
-                       if (mt_reachs)
-                               ipv4reachs = mt_reachs->list;
-               }
-
-               prefix.family = AF_INET;
-               for (ALL_LIST_ELEMENTS_RO(ipv4reachs, node, te_ipv4_reach)) {
-                       assert((te_ipv4_reach->control & 0x3F)
-                              <= IPV4_MAX_BITLEN);
-
-                       dist = cost + ntohl(te_ipv4_reach->te_metric);
-                       prefix.u.prefix4 =
-                               newprefix2inaddr(&te_ipv4_reach->prefix_start,
-                                                te_ipv4_reach->control);
-                       prefix.prefixlen = (te_ipv4_reach->control & 0x3F);
-                       apply_mask(&prefix);
-                       process_N(spftree, VTYPE_IPREACH_TE, (void *)&prefix,
+               struct isis_item_list *ipv4_reachs;
+               if (spftree->mtid == ISIS_MT_IPV4_UNICAST)
+                       ipv4_reachs = &lsp->tlvs->extended_ip_reach;
+               else
+                       ipv4_reachs = isis_lookup_mt_items(
+                               &lsp->tlvs->mt_ip_reach, spftree->mtid);
+
+               struct isis_extended_ip_reach *r;
+               for (r = ipv4_reachs
+                                ? (struct isis_extended_ip_reach *)
+                                          ipv4_reachs->head
+                                : NULL;
+                    r; r = r->next) {
+                       dist = cost + r->metric;
+                       process_N(spftree, VTYPE_IPREACH_TE, (void *)&r->prefix,
                                  dist, depth + 1, parent);
                }
        }
 
        if (!pseudo_lsp && spftree->family == AF_INET6) {
-               struct list *ipv6reachs = NULL;
-
-               if (spftree->mtid == ISIS_MT_IPV4_UNICAST) {
-                       ipv6reachs = lsp->tlv_data.ipv6_reachs;
-               } else {
-                       struct tlv_mt_ipv6_reachs *mt_reachs;
-                       mt_reachs = tlvs_lookup_mt_ipv6_reachs(&lsp->tlv_data,
-                                                              spftree->mtid);
-                       if (mt_reachs)
-                               ipv6reachs = mt_reachs->list;
-               }
-
-               prefix.family = AF_INET6;
-               for (ALL_LIST_ELEMENTS_RO(ipv6reachs, node, ip6reach)) {
-                       assert(ip6reach->prefix_len <= IPV6_MAX_BITLEN);
-
-                       dist = cost + ntohl(ip6reach->metric);
-                       vtype = (ip6reach->control_info
-                                & CTRL_INFO_DISTRIBUTION)
-                                       ? VTYPE_IP6REACH_EXTERNAL
-                                       : VTYPE_IP6REACH_INTERNAL;
-                       prefix.prefixlen = ip6reach->prefix_len;
-                       memcpy(&prefix.u.prefix6.s6_addr, ip6reach->prefix,
-                              PSIZE(ip6reach->prefix_len));
-                       apply_mask(&prefix);
-                       process_N(spftree, vtype, (void *)&prefix, dist,
+               struct isis_item_list *ipv6_reachs;
+               if (spftree->mtid == ISIS_MT_IPV4_UNICAST)
+                       ipv6_reachs = &lsp->tlvs->ipv6_reach;
+               else
+                       ipv6_reachs = isis_lookup_mt_items(
+                               &lsp->tlvs->mt_ipv6_reach, spftree->mtid);
+
+               struct isis_ipv6_reach *r;
+               for (r = ipv6_reachs
+                                ? (struct isis_ipv6_reach *)ipv6_reachs->head
+                                : NULL;
+                    r; r = r->next) {
+                       dist = cost + r->metric;
+                       vtype = r->external ? VTYPE_IP6REACH_EXTERNAL
+                                           : VTYPE_IP6REACH_INTERNAL;
+                       process_N(spftree, vtype, (void *)&r->prefix, dist,
                                  depth + 1, parent);
                }
        }
@@ -893,7 +1034,9 @@ static int isis_spf_preload_tent(struct isis_spftree *spftree,
                                if (!adj_has_mt(adj, spftree->mtid))
                                        continue;
                                if (spftree->mtid == ISIS_MT_IPV4_UNICAST
-                                   && !speaks(&adj->nlpids, spftree->family))
+                                   && !speaks(adj->nlpids.nlpids,
+                                              adj->nlpids.count,
+                                              spftree->family))
                                        continue;
                                switch (adj->sys_type) {
                                case ISIS_SYSTYPE_ES:
@@ -928,8 +1071,7 @@ static int isis_spf_preload_tent(struct isis_spftree *spftree,
                                                        ->lspdb[spftree->level
                                                                - 1]);
                                        if (lsp == NULL
-                                           || lsp->lsp_header->rem_lifetime
-                                                      == 0)
+                                           || lsp->hdr.rem_lifetime == 0)
                                                zlog_warn(
                                                        "ISIS-Spf: No LSP %s found for IS adjacency "
                                                        "L%d on %s (ID %u)",
@@ -979,7 +1121,7 @@ static int isis_spf_preload_tent(struct isis_spftree *spftree,
                        lsp = lsp_search(
                                lsp_id,
                                spftree->area->lspdb[spftree->level - 1]);
-                       if (lsp == NULL || lsp->lsp_header->rem_lifetime == 0) {
+                       if (lsp == NULL || lsp->hdr.rem_lifetime == 0) {
                                zlog_warn(
                                        "ISIS-Spf: No lsp (%p) found from root "
                                        "to L%d DR %s on %s (ID %d)",
@@ -1015,7 +1157,9 @@ static int isis_spf_preload_tent(struct isis_spftree *spftree,
                                LSP_PSEUDO_ID(lsp_id) = 0;
                                LSP_FRAGMENT(lsp_id) = 0;
                                if (spftree->mtid != ISIS_MT_IPV4_UNICAST
-                                   || speaks(&adj->nlpids, spftree->family))
+                                   || speaks(adj->nlpids.nlpids,
+                                             adj->nlpids.count,
+                                             spftree->family))
                                        isis_spf_add_local(
                                                spftree,
                                                spftree->area->oldmetric
@@ -1052,9 +1196,9 @@ static void add_to_paths(struct isis_spftree *spftree,
 {
        char buff[PREFIX2STR_BUFFER];
 
-       if (isis_find_vertex(spftree->paths, vertex->N.id, vertex->type))
+       if (isis_find_vertex(&spftree->paths, vertex->N.id, vertex->type))
                return;
-       listnode_add(spftree->paths, vertex);
+       isis_vertex_queue_add(&spftree->paths, vertex);
 
 #ifdef EXTREME_DEBUG
        zlog_debug("ISIS-Spf: added %s %s %s depth %d dist %d to PATHS",
@@ -1083,11 +1227,8 @@ static void add_to_paths(struct isis_spftree *spftree,
 static void init_spt(struct isis_spftree *spftree, int mtid, int level,
                     int family)
 {
-       spftree->tents->del = spftree->paths->del =
-               (void (*)(void *))isis_vertex_del;
-       list_delete_all_node(spftree->tents);
-       list_delete_all_node(spftree->paths);
-       spftree->tents->del = spftree->paths->del = NULL;
+       isis_vertex_queue_clear(&spftree->tents);
+       isis_vertex_queue_clear(&spftree->paths);
 
        spftree->mtid = mtid;
        spftree->level = level;
@@ -1099,7 +1240,6 @@ static int isis_run_spf(struct isis_area *area, int level, int family,
                        u_char *sysid)
 {
        int retval = ISIS_OK;
-       struct listnode *node;
        struct isis_vertex *vertex;
        struct isis_vertex *root_vertex;
        struct isis_spftree *spftree = NULL;
@@ -1154,15 +1294,14 @@ static int isis_run_spf(struct isis_area *area, int level, int family,
        /*
         * C.2.7 Step 2
         */
-       if (listcount(spftree->tents) == 0) {
+       if (isis_vertex_queue_count(&spftree->tents) == 0) {
                zlog_warn("ISIS-Spf: TENT is empty SPF-root:%s",
                          print_sys_hostname(sysid));
                goto out;
        }
 
-       while (listcount(spftree->tents) > 0) {
-               node = listhead(spftree->tents);
-               vertex = listgetdata(node);
+       while (isis_vertex_queue_count(&spftree->tents)) {
+               vertex = isis_vertex_queue_pop(&spftree->tents);
 
 #ifdef EXTREME_DEBUG
                zlog_debug(
@@ -1171,14 +1310,12 @@ static int isis_run_spf(struct isis_area *area, int level, int family,
                        vtype2string(vertex->type), vertex->depth, vertex->d_N);
 #endif /* EXTREME_DEBUG */
 
-               /* Remove from tent list and add to paths list */
-               list_delete_node(spftree->tents, node);
                add_to_paths(spftree, vertex);
                if (VTYPE_IS(vertex->type)) {
                        memcpy(lsp_id, vertex->N.id, ISIS_SYS_ID_LEN + 1);
                        LSP_FRAGMENT(lsp_id) = 0;
                        lsp = lsp_search(lsp_id, area->lspdb[level - 1]);
-                       if (lsp && lsp->lsp_header->rem_lifetime != 0) {
+                       if (lsp && lsp->hdr.rem_lifetime != 0) {
                                isis_spf_process_lsp(spftree, lsp, vertex->d_N,
                                                     vertex->depth, sysid,
                                                     vertex);
@@ -1299,7 +1436,7 @@ int isis_spf_schedule(struct isis_area *area, int level)
        return ISIS_OK;
 }
 
-static void isis_print_paths(struct vty *vty, struct list *paths,
+static void isis_print_paths(struct vty *vty, struct isis_vertex_queue *queue,
                             u_char *root_sysid)
 {
        struct listnode *node;
@@ -1311,7 +1448,7 @@ static void isis_print_paths(struct vty *vty, struct list *paths,
        vty_out(vty,
                "Vertex               Type         Metric Next-Hop             Interface Parent\n");
 
-       for (ALL_LIST_ELEMENTS_RO(paths, node, vertex)) {
+       for (ALL_QUEUE_ELEMENTS_RO(queue, node, vertex)) {
                if (memcmp(vertex->N.id, root_sysid, ISIS_SYS_ID_LEN) == 0) {
                        vty_out(vty, "%-20s %-12s %-6s",
                                print_sys_hostname(root_sysid), "", "");
@@ -1395,22 +1532,22 @@ DEFUN (show_isis_topology,
                                continue;
 
                        if (area->ip_circuits > 0 && area->spftree[level - 1]
-                           && area->spftree[level - 1]->paths->count > 0) {
+                           && isis_vertex_queue_count(&area->spftree[level - 1]->paths) > 0) {
                                vty_out(vty,
                                        "IS-IS paths to level-%d routers that speak IP\n",
                                        level);
                                isis_print_paths(
-                                       vty, area->spftree[level - 1]->paths,
+                                       vty, &area->spftree[level - 1]->paths,
                                        isis->sysid);
                                vty_out(vty, "\n");
                        }
                        if (area->ipv6_circuits > 0 && area->spftree6[level - 1]
-                           && area->spftree6[level - 1]->paths->count > 0) {
+                           && isis_vertex_queue_count(&area->spftree6[level - 1]->paths) > 0) {
                                vty_out(vty,
                                        "IS-IS paths to level-%d routers that speak IPv6\n",
                                        level);
                                isis_print_paths(
-                                       vty, area->spftree6[level - 1]->paths,
+                                       vty, &area->spftree6[level - 1]->paths,
                                        isis->sysid);
                                vty_out(vty, "\n");
                        }
@@ -1426,3 +1563,16 @@ void isis_spf_cmds_init()
 {
        install_element(VIEW_NODE, &show_isis_topology_cmd);
 }
+
+void isis_spf_print(struct isis_spftree *spftree, struct vty *vty)
+{
+       vty_out(vty, "      last run elapsed  : ");
+       vty_out_timestr(vty, spftree->last_run_timestamp);
+       vty_out(vty, "\n");
+
+       vty_out(vty, "      last run duration : %u usec\n",
+               (u_int32_t)spftree->last_run_duration);
+
+       vty_out(vty, "      run count         : %u\n",
+               spftree->runcount);
+}
index c7a505489f46596fd25a39d3675aa11e8e90d9e6..84e07861d2c351252316efde190b28982f5a1f61 100644 (file)
 #ifndef _ZEBRA_ISIS_SPF_H
 #define _ZEBRA_ISIS_SPF_H
 
-enum vertextype {
-       VTYPE_PSEUDO_IS = 1,
-       VTYPE_PSEUDO_TE_IS,
-       VTYPE_NONPSEUDO_IS,
-       VTYPE_NONPSEUDO_TE_IS,
-       VTYPE_ES,
-       VTYPE_IPREACH_INTERNAL,
-       VTYPE_IPREACH_EXTERNAL,
-       VTYPE_IPREACH_TE,
-       VTYPE_IP6REACH_INTERNAL,
-       VTYPE_IP6REACH_EXTERNAL
-};
-
-#define VTYPE_IS(t) ((t) >= VTYPE_PSEUDO_IS && (t) <= VTYPE_NONPSEUDO_TE_IS)
-#define VTYPE_ES(t) ((t) == VTYPE_ES)
-#define VTYPE_IP(t) ((t) >= VTYPE_IPREACH_INTERNAL && (t) <= VTYPE_IP6REACH_EXTERNAL)
-
-/*
- * Triple <N, d(N), {Adj(N)}>
- */
-struct isis_vertex {
-       enum vertextype type;
-
-       union {
-               u_char id[ISIS_SYS_ID_LEN + 1];
-               struct prefix prefix;
-       } N;
-
-       u_int32_t d_N;   /* d(N) Distance from this IS      */
-       u_int16_t depth;       /* The depth in the imaginary tree */
-       struct list *Adj_N;    /* {Adj(N)} next hop or neighbor list */
-       struct list *parents;  /* list of parents for ECMP */
-       struct list *children; /* list of children used for tree dump */
-};
-
-struct isis_spftree {
-       struct list *paths;     /* the SPT */
-       struct list *tents;     /* TENT */
-       struct isis_area *area;    /* back pointer to area */
-       unsigned int runcount;     /* number of runs since uptime */
-       time_t last_run_timestamp; /* last run timestamp for scheduling */
-       time_t last_run_duration;  /* last run duration in msec */
-
-       uint16_t mtid;
-       int family;
-       int level;
-};
+struct isis_spftree;
 
 struct isis_spftree *isis_spftree_new(struct isis_area *area);
 void isis_spftree_del(struct isis_spftree *spftree);
@@ -79,4 +33,5 @@ void spftree_area_del(struct isis_area *area);
 void spftree_area_adj_del(struct isis_area *area, struct isis_adjacency *adj);
 int isis_spf_schedule(struct isis_area *area, int level);
 void isis_spf_cmds_init(void);
+void isis_spf_print(struct isis_spftree *spftree, struct vty *vty);
 #endif /* _ZEBRA_ISIS_SPF_H */
index 5296d9948092427f0c9a93ffdc8cc9d9aead2399..70afef1a86ee4fe81a4b8ff14f82c4444fd48669 100644 (file)
@@ -41,6 +41,7 @@
 #include "md5.h"
 #include "sockunion.h"
 #include "network.h"
+#include "sbuf.h"
 
 #include "isisd/dict.h"
 #include "isisd/isis_constants.h"
@@ -48,7 +49,6 @@
 #include "isisd/isis_flags.h"
 #include "isisd/isis_circuit.h"
 #include "isisd/isisd.h"
-#include "isisd/isis_tlv.h"
 #include "isisd/isis_lsp.h"
 #include "isisd/isis_pdu.h"
 #include "isisd/isis_dynhn.h"
@@ -100,9 +100,9 @@ struct mpls_te_circuit *mpls_te_circuit_new()
 /* 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 */
-u_char add_te_subtlvs(u_char *buf, struct mpls_te_circuit *mtc)
+uint8_t add_te_subtlvs(uint8_t *buf, struct mpls_te_circuit *mtc)
 {
-       u_char size, *tlvs = buf;
+       uint8_t size, *tlvs = buf;
 
        zlog_debug("ISIS MPLS-TE: Add TE Sub TLVs to buffer");
 
@@ -232,7 +232,7 @@ u_char add_te_subtlvs(u_char *buf, struct mpls_te_circuit *mtc)
 }
 
 /* Compute total Sub-TLVs size */
-u_char subtlvs_len(struct mpls_te_circuit *mtc)
+uint8_t subtlvs_len(struct mpls_te_circuit *mtc)
 {
        int length = 0;
 
@@ -306,7 +306,7 @@ u_char subtlvs_len(struct mpls_te_circuit *mtc)
                return 0;
        }
 
-       mtc->length = (u_char)length;
+       mtc->length = (uint8_t)length;
 
        return mtc->length;
 }
@@ -546,13 +546,9 @@ void isis_link_params_update(struct isis_circuit *circuit,
                if ((SUBTLV_TYPE(mtc->rmt_ipaddr) == 0)
                    && (circuit->circ_type == CIRCUIT_T_P2P)) {
                        struct isis_adjacency *adj = circuit->u.p2p.neighbor;
-                       if (adj->ipv4_addrs != NULL
-                           && listcount(adj->ipv4_addrs) != 0) {
-                               struct in_addr *ip_addr;
-                               ip_addr = (struct in_addr *)listgetdata(
-                                       (struct listnode *)listhead(
-                                               adj->ipv4_addrs));
-                               set_circuitparams_rmt_ipaddr(mtc, *ip_addr);
+                       if (adj->ipv4_address_count) {
+                               set_circuitparams_rmt_ipaddr(
+                                       mtc, adj->ipv4_addresses[0]);
                        }
                }
 
@@ -670,163 +666,116 @@ void isis_mpls_te_update(struct interface *ifp)
  * Followings are vty session control functions.
  *------------------------------------------------------------------------*/
 
-static u_char show_vty_subtlv_admin_grp(struct vty *vty,
-                                       struct te_subtlv_admin_grp *tlv)
+static u_char print_subtlv_admin_grp(struct sbuf *buf, int indent,
+                                    struct te_subtlv_admin_grp *tlv)
 {
-
-       if (vty != NULL)
-               vty_out(vty, "    Administrative Group: 0x%x\n",
-                       (u_int32_t)ntohl(tlv->value));
-       else
-               zlog_debug("      Administrative Group: 0x%x",
-                          (u_int32_t)ntohl(tlv->value));
-
+       sbuf_push(buf, indent, "Administrative Group: 0x%" PRIx32 "\n",
+                 ntohl(tlv->value));
        return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE);
 }
 
-static u_char show_vty_subtlv_llri(struct vty *vty, struct te_subtlv_llri *tlv)
+static u_char print_subtlv_llri(struct sbuf *buf, int indent,
+                               struct te_subtlv_llri *tlv)
 {
-       if (vty != NULL) {
-               vty_out(vty, "    Link Local  ID: %d\n",
-                       (u_int32_t)ntohl(tlv->local));
-               vty_out(vty, "    Link Remote ID: %d\n",
-                       (u_int32_t)ntohl(tlv->remote));
-       } else {
-               zlog_debug("      Link Local  ID: %d",
-                          (u_int32_t)ntohl(tlv->local));
-               zlog_debug("      Link Remote ID: %d",
-                          (u_int32_t)ntohl(tlv->remote));
-       }
+       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 u_char show_vty_subtlv_local_ipaddr(struct vty *vty,
-                                          struct te_subtlv_local_ipaddr *tlv)
+static u_char print_subtlv_local_ipaddr(struct sbuf *buf, int indent,
+                                       struct te_subtlv_local_ipaddr *tlv)
 {
-       if (vty != NULL)
-               vty_out(vty, "    Local Interface IP Address(es): %s\n",
-                       inet_ntoa(tlv->value));
-       else
-               zlog_debug("      Local Interface IP Address(es): %s",
-                          inet_ntoa(tlv->value));
+       sbuf_push(buf, indent, "Local Interface IP Address(es): %s\n",
+                 inet_ntoa(tlv->value));
 
        return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE);
 }
 
-static u_char show_vty_subtlv_rmt_ipaddr(struct vty *vty,
-                                        struct te_subtlv_rmt_ipaddr *tlv)
+static u_char print_subtlv_rmt_ipaddr(struct sbuf *buf, int indent,
+                                     struct te_subtlv_rmt_ipaddr *tlv)
 {
-       if (vty != NULL)
-               vty_out(vty, "    Remote Interface IP Address(es): %s\n",
-                       inet_ntoa(tlv->value));
-       else
-               zlog_debug("      Remote Interface IP Address(es): %s",
-                          inet_ntoa(tlv->value));
+       sbuf_push(buf, indent, "Remote Interface IP Address(es): %s\n",
+                 inet_ntoa(tlv->value));
 
        return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE);
 }
 
-static u_char show_vty_subtlv_max_bw(struct vty *vty,
-                                    struct te_subtlv_max_bw *tlv)
+static u_char print_subtlv_max_bw(struct sbuf *buf, int indent,
+                                 struct te_subtlv_max_bw *tlv)
 {
        float fval;
 
        fval = ntohf(tlv->value);
 
-       if (vty != NULL)
-               vty_out(vty, "    Maximum Bandwidth: %g (Bytes/sec)\n", fval);
-       else
-               zlog_debug("      Maximum Bandwidth: %g (Bytes/sec)", fval);
+       sbuf_push(buf, indent, "Maximum Bandwidth: %g (Bytes/sec)\n", fval);
 
        return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE);
 }
 
-static u_char show_vty_subtlv_max_rsv_bw(struct vty *vty,
-                                        struct te_subtlv_max_rsv_bw *tlv)
+static u_char print_subtlv_max_rsv_bw(struct sbuf *buf, int indent,
+                                     struct te_subtlv_max_rsv_bw *tlv)
 {
        float fval;
 
        fval = ntohf(tlv->value);
 
-       if (vty != NULL)
-               vty_out(vty,
-                       "    Maximum Reservable Bandwidth: %g (Bytes/sec)\n",
-                       fval);
-       else
-               zlog_debug("      Maximum Reservable Bandwidth: %g (Bytes/sec)",
-                          fval);
+       sbuf_push(buf, indent, "Maximum Reservable Bandwidth: %g (Bytes/sec)\n", fval);
 
        return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE);
 }
 
-static u_char show_vty_subtlv_unrsv_bw(struct vty *vty,
-                                      struct te_subtlv_unrsv_bw *tlv)
+static u_char print_subtlv_unrsv_bw(struct sbuf *buf, int indent,
+                                   struct te_subtlv_unrsv_bw *tlv)
 {
        float fval1, fval2;
        int i;
 
-       if (vty != NULL)
-               vty_out(vty, "    Unreserved Bandwidth:\n");
-       else
-               zlog_debug("      Unreserved Bandwidth:");
+       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]);
-               if (vty != NULL)
-                       vty_out(vty,
-                               "      [%d]: %g (Bytes/sec),\t[%d]: %g (Bytes/sec)\n",
-                               i, fval1, i + 1, fval2);
-               else
-                       zlog_debug(
-                               "        [%d]: %g (Bytes/sec),\t[%d]: %g (Bytes/sec)",
-                               i, fval1, i + 1, fval2);
+               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 u_char show_vty_subtlv_te_metric(struct vty *vty,
-                                       struct te_subtlv_te_metric *tlv)
+static u_char print_subtlv_te_metric(struct sbuf *buf, int indent,
+                                    struct te_subtlv_te_metric *tlv)
 {
        u_int32_t te_metric;
 
        te_metric = tlv->value[2] | tlv->value[1] << 8 | tlv->value[0] << 16;
-       if (vty != NULL)
-               vty_out(vty, "    Traffic Engineering Metric: %u\n", te_metric);
-       else
-               zlog_debug("      Traffic Engineering Metric: %u", te_metric);
+       sbuf_push(buf, indent, "Traffic Engineering Metric: %u\n", te_metric);
 
        return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE);
 }
 
-static u_char show_vty_subtlv_ras(struct vty *vty, struct te_subtlv_ras *tlv)
+static u_char print_subtlv_ras(struct sbuf *buf, int indent,
+                              struct te_subtlv_ras *tlv)
 {
-       if (vty != NULL)
-               vty_out(vty, "    Inter-AS TE Remote AS number: %u\n",
-                       ntohl(tlv->value));
-       else
-               zlog_debug("      Inter-AS TE Remote AS number: %u",
-                          ntohl(tlv->value));
+       sbuf_push(buf, indent, "Inter-AS TE Remote AS number: %" PRIu32 "\n",
+                 ntohl(tlv->value));
 
        return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE);
 }
 
-static u_char show_vty_subtlv_rip(struct vty *vty, struct te_subtlv_rip *tlv)
+static u_char print_subtlv_rip(struct sbuf *buf, int indent,
+                              struct te_subtlv_rip *tlv)
 {
-       if (vty != NULL)
-               vty_out(vty, "    Inter-AS TE Remote ASBR IP address: %s\n",
-                       inet_ntoa(tlv->value));
-       else
-               zlog_debug("      Inter-AS TE Remote ASBR IP address: %s",
-                          inet_ntoa(tlv->value));
+       sbuf_push(buf, indent, "Inter-AS TE Remote ASBR IP address: %s\n",
+                 inet_ntoa(tlv->value));
 
        return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE);
 }
 
-static u_char show_vty_subtlv_av_delay(struct vty *vty,
-                                      struct te_subtlv_av_delay *tlv)
+static u_char print_subtlv_av_delay(struct sbuf *buf, int indent,
+                                   struct te_subtlv_av_delay *tlv)
 {
        u_int32_t delay;
        u_int32_t A;
@@ -834,18 +783,14 @@ static u_char show_vty_subtlv_av_delay(struct vty *vty,
        delay = (u_int32_t)ntohl(tlv->value) & TE_EXT_MASK;
        A = (u_int32_t)ntohl(tlv->value) & TE_EXT_ANORMAL;
 
-       if (vty != NULL)
-               vty_out(vty, "    %s Average Link Delay: %d (micro-sec)\n",
-                       A ? "Anomalous" : "Normal", delay);
-       else
-               zlog_debug("      %s Average Link Delay: %d (micro-sec)",
-                          A ? "Anomalous" : "Normal", delay);
+       sbuf_push(buf, indent, "%s Average Link Delay: %" PRIu32 " (micro-sec)\n",
+                 A ? "Anomalous" : "Normal", delay);
 
        return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE);
 }
 
-static u_char show_vty_subtlv_mm_delay(struct vty *vty,
-                                      struct te_subtlv_mm_delay *tlv)
+static u_char print_subtlv_mm_delay(struct sbuf *buf, int indent,
+                                   struct te_subtlv_mm_delay *tlv)
 {
        u_int32_t low, high;
        u_int32_t A;
@@ -854,33 +799,26 @@ static u_char show_vty_subtlv_mm_delay(struct vty *vty,
        A = (u_int32_t)ntohl(tlv->low) & TE_EXT_ANORMAL;
        high = (u_int32_t)ntohl(tlv->high) & TE_EXT_MASK;
 
-       if (vty != NULL)
-               vty_out(vty, "    %s Min/Max Link Delay: %d / %d (micro-sec)\n",
-                       A ? "Anomalous" : "Normal", low, high);
-       else
-               zlog_debug("      %s Min/Max Link Delay: %d / %d (micro-sec)",
-                          A ? "Anomalous" : "Normal", low, high);
+       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 u_char show_vty_subtlv_delay_var(struct vty *vty,
-                                       struct te_subtlv_delay_var *tlv)
+static u_char print_subtlv_delay_var(struct sbuf *buf, int indent,
+                                    struct te_subtlv_delay_var *tlv)
 {
        u_int32_t jitter;
 
        jitter = (u_int32_t)ntohl(tlv->value) & TE_EXT_MASK;
 
-       if (vty != NULL)
-               vty_out(vty, "    Delay Variation: %d (micro-sec)\n", jitter);
-       else
-               zlog_debug("      Delay Variation: %d (micro-sec)", jitter);
+       sbuf_push(buf, indent, "Delay Variation: %" PRIu32 " (micro-sec)\n", jitter);
 
        return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE);
 }
 
-static u_char show_vty_subtlv_pkt_loss(struct vty *vty,
-                                      struct te_subtlv_pkt_loss *tlv)
+static u_char print_subtlv_pkt_loss(struct sbuf *buf, int indent,
+                                   struct te_subtlv_pkt_loss *tlv)
 {
        u_int32_t loss;
        u_int32_t A;
@@ -890,189 +828,162 @@ static u_char show_vty_subtlv_pkt_loss(struct vty *vty,
        fval = (float)(loss * LOSS_PRECISION);
        A = (u_int32_t)ntohl(tlv->value) & TE_EXT_ANORMAL;
 
-       if (vty != NULL)
-               vty_out(vty, "    %s Link Packet Loss: %g (%%)\n",
-                       A ? "Anomalous" : "Normal", fval);
-       else
-               zlog_debug("      %s Link Packet Loss: %g (%%)",
-                          A ? "Anomalous" : "Normal", fval);
+       sbuf_push(buf, indent, "%s Link Packet Loss: %g (%%)\n",
+                 A ? "Anomalous" : "Normal", fval);
 
        return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE);
 }
 
-static u_char show_vty_subtlv_res_bw(struct vty *vty,
-                                    struct te_subtlv_res_bw *tlv)
+static u_char print_subtlv_res_bw(struct sbuf *buf, int indent,
+                                 struct te_subtlv_res_bw *tlv)
 {
        float fval;
 
        fval = ntohf(tlv->value);
 
-       if (vty != NULL)
-               vty_out(vty,
-                       "    Unidirectional Residual Bandwidth: %g (Bytes/sec)\n",
-                       fval);
-       else
-               zlog_debug(
-                       "      Unidirectional Residual Bandwidth: %g (Bytes/sec)",
-                       fval);
+       sbuf_push(buf, indent, "Unidirectional Residual Bandwidth: %g (Bytes/sec)\n",
+                 fval);
 
        return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE);
 }
 
-static u_char show_vty_subtlv_ava_bw(struct vty *vty,
-                                    struct te_subtlv_ava_bw *tlv)
+static u_char print_subtlv_ava_bw(struct sbuf *buf, int indent,
+                                 struct te_subtlv_ava_bw *tlv)
 {
        float fval;
 
        fval = ntohf(tlv->value);
 
-       if (vty != NULL)
-               vty_out(vty,
-                       "    Unidirectional Available Bandwidth: %g (Bytes/sec)\n",
-                       fval);
-       else
-               zlog_debug(
-                       "      Unidirectional Available Bandwidth: %g (Bytes/sec)",
-                       fval);
+       sbuf_push(buf, indent, "Unidirectional Available Bandwidth: %g (Bytes/sec)\n",
+                 fval);
 
        return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE);
 }
 
-static u_char show_vty_subtlv_use_bw(struct vty *vty,
-                                    struct te_subtlv_use_bw *tlv)
+static u_char print_subtlv_use_bw(struct sbuf *buf, int indent,
+                                 struct te_subtlv_use_bw *tlv)
 {
        float fval;
 
        fval = ntohf(tlv->value);
 
-       if (vty != NULL)
-               vty_out(vty,
-                       "    Unidirectional Utilized Bandwidth: %g (Bytes/sec)\n",
-                       fval);
-       else
-               zlog_debug(
-                       "      Unidirectional Utilized Bandwidth: %g (Bytes/sec)",
-                       fval);
+       sbuf_push(buf, indent, "Unidirectional Utilized Bandwidth: %g (Bytes/sec)\n",
+                 fval);
 
        return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE);
 }
 
-static u_char show_vty_unknown_tlv(struct vty *vty, struct subtlv_header *tlvh)
+static u_char print_unknown_tlv(struct sbuf *buf, int indent,
+                               struct subtlv_header *tlvh)
 {
        int i, rtn = 1;
        u_char *v = (u_char *)tlvh;
 
-       if (vty != NULL) {
-               if (tlvh->length != 0) {
-                       vty_out(vty,
-                               "    Unknown TLV: [type(%#.2x), length(%#.2x)]\n",
-                               tlvh->type, tlvh->length);
-                       vty_out(vty, "       Dump: [00]");
-                       rtn = 1; /* initialize end of line counter */
-                       for (i = 0; i < tlvh->length; i++) {
-                               vty_out(vty, " %#.2x", v[i]);
-                               if (rtn == 8) {
-                                       vty_out(vty, "\n             [%.2x]",
-                                               i + 1);
-                                       rtn = 1;
-                               } else
-                                       rtn++;
-                       }
-                       vty_out(vty, "\n");
-               } else
-                       vty_out(vty,
-                               "    Unknown TLV: [type(%#.2x), length(%#.2x)]\n",
-                               tlvh->type, tlvh->length);
+       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 {
-               zlog_debug("      Unknown TLV: [type(%#.2x), length(%#.2x)]",
-                          tlvh->type, tlvh->length);
+               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 vty *vty, struct te_is_neigh *te)
+void mpls_te_print_detail(struct sbuf *buf, int indent,
+                         uint8_t *subtlvs, uint8_t subtlv_len)
 {
-       struct subtlv_header *tlvh;
-       u_int16_t sum = 0;
-
-       zlog_debug("ISIS MPLS-TE: Show database TE detail");
+       struct subtlv_header *tlvh = (struct subtlv_header *)subtlvs;
+       uint16_t sum = 0;
 
-       tlvh = (struct subtlv_header *)te->sub_tlvs;
-
-       for (; sum < te->sub_tlvs_length; tlvh = SUBTLV_HDR_NEXT(tlvh)) {
+       for (; sum < subtlv_len; tlvh = SUBTLV_HDR_NEXT(tlvh)) {
                switch (tlvh->type) {
                case TE_SUBTLV_ADMIN_GRP:
-                       sum += show_vty_subtlv_admin_grp(
-                               vty, (struct te_subtlv_admin_grp *)tlvh);
+                       sum += print_subtlv_admin_grp(buf, indent,
+                               (struct te_subtlv_admin_grp *)tlvh);
                        break;
                case TE_SUBTLV_LLRI:
-                       sum += show_vty_subtlv_llri(
-                               vty, (struct te_subtlv_llri *)tlvh);
+                       sum += print_subtlv_llri(buf, indent,
+                               (struct te_subtlv_llri *)tlvh);
                        break;
                case TE_SUBTLV_LOCAL_IPADDR:
-                       sum += show_vty_subtlv_local_ipaddr(
-                               vty, (struct te_subtlv_local_ipaddr *)tlvh);
+                       sum += print_subtlv_local_ipaddr(buf, indent,
+                               (struct te_subtlv_local_ipaddr *)tlvh);
                        break;
                case TE_SUBTLV_RMT_IPADDR:
-                       sum += show_vty_subtlv_rmt_ipaddr(
-                               vty, (struct te_subtlv_rmt_ipaddr *)tlvh);
+                       sum += print_subtlv_rmt_ipaddr(buf, indent,
+                               (struct te_subtlv_rmt_ipaddr *)tlvh);
                        break;
                case TE_SUBTLV_MAX_BW:
-                       sum += show_vty_subtlv_max_bw(
-                               vty, (struct te_subtlv_max_bw *)tlvh);
+                       sum += print_subtlv_max_bw(buf, indent,
+                               (struct te_subtlv_max_bw *)tlvh);
                        break;
                case TE_SUBTLV_MAX_RSV_BW:
-                       sum += show_vty_subtlv_max_rsv_bw(
-                               vty, (struct te_subtlv_max_rsv_bw *)tlvh);
+                       sum += print_subtlv_max_rsv_bw(buf, indent,
+                               (struct te_subtlv_max_rsv_bw *)tlvh);
                        break;
                case TE_SUBTLV_UNRSV_BW:
-                       sum += show_vty_subtlv_unrsv_bw(
-                               vty, (struct te_subtlv_unrsv_bw *)tlvh);
+                       sum += print_subtlv_unrsv_bw(buf, indent,
+                               (struct te_subtlv_unrsv_bw *)tlvh);
                        break;
                case TE_SUBTLV_TE_METRIC:
-                       sum += show_vty_subtlv_te_metric(
-                               vty, (struct te_subtlv_te_metric *)tlvh);
+                       sum += print_subtlv_te_metric(buf, indent,
+                               (struct te_subtlv_te_metric *)tlvh);
                        break;
                case TE_SUBTLV_RAS:
-                       sum += show_vty_subtlv_ras(
-                               vty, (struct te_subtlv_ras *)tlvh);
+                       sum += print_subtlv_ras(buf, indent,
+                               (struct te_subtlv_ras *)tlvh);
                        break;
                case TE_SUBTLV_RIP:
-                       sum += show_vty_subtlv_rip(
-                               vty, (struct te_subtlv_rip *)tlvh);
+                       sum += print_subtlv_rip(buf, indent,
+                               (struct te_subtlv_rip *)tlvh);
                        break;
                case TE_SUBTLV_AV_DELAY:
-                       sum += show_vty_subtlv_av_delay(
-                               vty, (struct te_subtlv_av_delay *)tlvh);
+                       sum += print_subtlv_av_delay(buf, indent,
+                               (struct te_subtlv_av_delay *)tlvh);
                        break;
                case TE_SUBTLV_MM_DELAY:
-                       sum += show_vty_subtlv_mm_delay(
-                               vty, (struct te_subtlv_mm_delay *)tlvh);
+                       sum += print_subtlv_mm_delay(buf, indent,
+                               (struct te_subtlv_mm_delay *)tlvh);
                        break;
                case TE_SUBTLV_DELAY_VAR:
-                       sum += show_vty_subtlv_delay_var(
-                               vty, (struct te_subtlv_delay_var *)tlvh);
+                       sum += print_subtlv_delay_var(buf, indent,
+                               (struct te_subtlv_delay_var *)tlvh);
                        break;
                case TE_SUBTLV_PKT_LOSS:
-                       sum += show_vty_subtlv_pkt_loss(
-                               vty, (struct te_subtlv_pkt_loss *)tlvh);
+                       sum += print_subtlv_pkt_loss(buf, indent,
+                               (struct te_subtlv_pkt_loss *)tlvh);
                        break;
                case TE_SUBTLV_RES_BW:
-                       sum += show_vty_subtlv_res_bw(
-                               vty, (struct te_subtlv_res_bw *)tlvh);
+                       sum += print_subtlv_res_bw(buf, indent,
+                               (struct te_subtlv_res_bw *)tlvh);
                        break;
                case TE_SUBTLV_AVA_BW:
-                       sum += show_vty_subtlv_ava_bw(
-                               vty, (struct te_subtlv_ava_bw *)tlvh);
+                       sum += print_subtlv_ava_bw(buf, indent,
+                               (struct te_subtlv_ava_bw *)tlvh);
                        break;
                case TE_SUBTLV_USE_BW:
-                       sum += show_vty_subtlv_use_bw(
-                               vty, (struct te_subtlv_use_bw *)tlvh);
+                       sum += print_subtlv_use_bw(buf, indent,
+                               (struct te_subtlv_use_bw *)tlvh);
                        break;
                default:
-                       sum += show_vty_unknown_tlv(vty, tlvh);
+                       sum += print_unknown_tlv(buf, indent, tlvh);
                        break;
                }
        }
@@ -1256,6 +1167,9 @@ DEFUN (show_isis_mpls_te_router,
 static void show_mpls_te_sub(struct vty *vty, struct interface *ifp)
 {
        struct mpls_te_circuit *mtc;
+       struct sbuf buf;
+
+       sbuf_init(&buf, NULL, 0);
 
        if ((IS_MPLS_TE(isisMplsTE))
            && ((mtc = lookup_mpls_params_by_ifp(ifp)) != NULL)) {
@@ -1280,38 +1194,42 @@ static void show_mpls_te_sub(struct vty *vty, struct interface *ifp)
                                ifp->name);
                }
 
-               show_vty_subtlv_admin_grp(vty, &mtc->admin_grp);
+               sbuf_reset(&buf);
+               print_subtlv_admin_grp(&buf, 4, &mtc->admin_grp);
 
                if (SUBTLV_TYPE(mtc->local_ipaddr) != 0)
-                       show_vty_subtlv_local_ipaddr(vty, &mtc->local_ipaddr);
+                       print_subtlv_local_ipaddr(&buf, 4, &mtc->local_ipaddr);
                if (SUBTLV_TYPE(mtc->rmt_ipaddr) != 0)
-                       show_vty_subtlv_rmt_ipaddr(vty, &mtc->rmt_ipaddr);
+                       print_subtlv_rmt_ipaddr(&buf, 4, &mtc->rmt_ipaddr);
 
-               show_vty_subtlv_max_bw(vty, &mtc->max_bw);
-               show_vty_subtlv_max_rsv_bw(vty, &mtc->max_rsv_bw);
-               show_vty_subtlv_unrsv_bw(vty, &mtc->unrsv_bw);
-               show_vty_subtlv_te_metric(vty, &mtc->te_metric);
+               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)
-                               show_vty_subtlv_ras(vty, &mtc->ras);
+                               print_subtlv_ras(&buf, 4, &mtc->ras);
                        if (SUBTLV_TYPE(mtc->rip) != 0)
-                               show_vty_subtlv_rip(vty, &mtc->rip);
+                               print_subtlv_rip(&buf, 4, &mtc->rip);
                }
 
-               show_vty_subtlv_av_delay(vty, &mtc->av_delay);
-               show_vty_subtlv_mm_delay(vty, &mtc->mm_delay);
-               show_vty_subtlv_delay_var(vty, &mtc->delay_var);
-               show_vty_subtlv_pkt_loss(vty, &mtc->pkt_loss);
-               show_vty_subtlv_res_bw(vty, &mtc->res_bw);
-               show_vty_subtlv_ava_bw(vty, &mtc->ava_bw);
-               show_vty_subtlv_use_bw(vty, &mtc->use_bw);
+               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);
+
+               vty_multiline(vty, "", "%s", sbuf_buf(&buf));
                vty_out(vty, "---------------\n\n");
        } else {
                vty_out(vty, "  %s: MPLS-TE is disabled on this interface\n",
                        ifp->name);
        }
 
+       sbuf_free(&buf);
        return;
 }
 
index 0bd076af1926faa5acef9487204098886e1b838d..9b29792e2b29119a76d7ddaed2d1aaedefa81259 100644 (file)
@@ -81,6 +81,8 @@ struct subtlv_header {
        u_char 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)
@@ -306,12 +308,13 @@ struct mpls_te_circuit {
 /* Prototypes. */
 void isis_mpls_te_init(void);
 struct mpls_te_circuit *mpls_te_circuit_new(void);
-void mpls_te_print_detail(struct vty *, struct te_is_neigh *);
+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);
-u_char subtlvs_len(struct mpls_te_circuit *);
-u_char add_te_subtlvs(u_char *, struct mpls_te_circuit *);
-u_char build_te_subtlvs(u_char *, struct isis_circuit *);
+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 *);
 void isis_mpls_te_config_write_router(struct vty *);
diff --git a/isisd/isis_tlv.c b/isisd/isis_tlv.c
deleted file mode 100644 (file)
index a295f4d..0000000
+++ /dev/null
@@ -1,1453 +0,0 @@
-/*
- * IS-IS Rout(e)ing protocol - isis_tlv.c
- *                             IS-IS TLV related routines
- *
- * Copyright (C) 2001,2002   Sampo Saaristo
- *                           Tampere University of Technology
- *                           Institute of Communications Engineering
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public Licenseas published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; see the file COPYING; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include <zebra.h>
-
-#include "log.h"
-#include "linklist.h"
-#include "stream.h"
-#include "memory.h"
-#include "prefix.h"
-#include "vty.h"
-#include "if.h"
-
-#include "isisd/dict.h"
-#include "isisd/isis_constants.h"
-#include "isisd/isis_common.h"
-#include "isisd/isis_flags.h"
-#include "isisd/isis_circuit.h"
-#include "isisd/isis_tlv.h"
-#include "isisd/isisd.h"
-#include "isisd/isis_dynhn.h"
-#include "isisd/isis_misc.h"
-#include "isisd/isis_pdu.h"
-#include "isisd/isis_lsp.h"
-#include "isisd/isis_te.h"
-#include "isisd/isis_mt.h"
-
-void free_tlv(void *val)
-{
-       XFREE(MTYPE_ISIS_TLV, val);
-
-       return;
-}
-
-/*
- * Called after parsing of a PDU. There shouldn't be any tlv's left, so this
- * is only a caution to avoid memory leaks
- */
-void free_tlvs(struct tlvs *tlvs)
-{
-       if (tlvs->area_addrs)
-               list_delete(tlvs->area_addrs);
-       if (tlvs->mt_router_info)
-               list_delete(tlvs->mt_router_info);
-       if (tlvs->is_neighs)
-               list_delete(tlvs->is_neighs);
-       if (tlvs->te_is_neighs)
-               list_delete(tlvs->te_is_neighs);
-       if (tlvs->mt_is_neighs)
-               list_delete(tlvs->mt_is_neighs);
-       if (tlvs->es_neighs)
-               list_delete(tlvs->es_neighs);
-       if (tlvs->lsp_entries)
-               list_delete(tlvs->lsp_entries);
-       if (tlvs->prefix_neighs)
-               list_delete(tlvs->prefix_neighs);
-       if (tlvs->lan_neighs)
-               list_delete(tlvs->lan_neighs);
-       if (tlvs->ipv4_addrs)
-               list_delete(tlvs->ipv4_addrs);
-       if (tlvs->ipv4_int_reachs)
-               list_delete(tlvs->ipv4_int_reachs);
-       if (tlvs->ipv4_ext_reachs)
-               list_delete(tlvs->ipv4_ext_reachs);
-       if (tlvs->te_ipv4_reachs)
-               list_delete(tlvs->te_ipv4_reachs);
-       if (tlvs->mt_ipv4_reachs)
-               list_delete(tlvs->mt_ipv4_reachs);
-       if (tlvs->ipv6_addrs)
-               list_delete(tlvs->ipv6_addrs);
-       if (tlvs->ipv6_reachs)
-               list_delete(tlvs->ipv6_reachs);
-       if (tlvs->mt_ipv6_reachs)
-               list_delete(tlvs->mt_ipv6_reachs);
-
-       memset(tlvs, 0, sizeof(struct tlvs));
-
-       return;
-}
-
-static int parse_mtid(uint16_t *mtid, bool read_mtid, unsigned int *length,
-                     u_char **pnt)
-{
-       if (!read_mtid) {
-               *mtid = ISIS_MT_IPV4_UNICAST;
-               return ISIS_OK;
-       }
-
-       uint16_t mtid_buf;
-
-       if (*length < sizeof(mtid_buf)) {
-               zlog_warn("ISIS-TLV: mt tlv too short to contain MT id");
-               return ISIS_WARNING;
-       }
-
-       memcpy(&mtid_buf, *pnt, sizeof(mtid_buf));
-       *pnt += sizeof(mtid_buf);
-       *length -= sizeof(mtid_buf);
-
-       *mtid = ntohs(mtid_buf) & ISIS_MT_MASK;
-       return ISIS_OK;
-}
-
-static int parse_mt_is_neighs(struct tlvs *tlvs, bool read_mtid,
-                             unsigned int length, u_char *pnt)
-{
-       struct list *neigh_list;
-       uint16_t mtid;
-       int rv;
-
-       rv = parse_mtid(&mtid, read_mtid, &length, &pnt);
-       if (rv != ISIS_OK)
-               return rv;
-
-       if (mtid == ISIS_MT_IPV4_UNICAST) {
-               if (!tlvs->te_is_neighs) {
-                       tlvs->te_is_neighs = list_new();
-                       tlvs->te_is_neighs->del = free_tlv;
-               }
-               neigh_list = tlvs->te_is_neighs;
-       } else {
-               struct tlv_mt_neighbors *neighbors;
-
-               neighbors = tlvs_get_mt_neighbors(tlvs, mtid);
-               neighbors->list->del = free_tlv;
-               neigh_list = neighbors->list;
-       }
-
-       while (length >= IS_NEIGHBOURS_LEN) {
-               struct te_is_neigh *neigh =
-                       XCALLOC(MTYPE_ISIS_TLV, sizeof(*neigh));
-
-               memcpy(neigh, pnt, IS_NEIGHBOURS_LEN);
-               pnt += IS_NEIGHBOURS_LEN;
-               length -= IS_NEIGHBOURS_LEN;
-
-               if (neigh->sub_tlvs_length > length) {
-                       zlog_warn(
-                               "ISIS-TLV: neighbor subtlv length exceeds TLV size");
-                       XFREE(MTYPE_ISIS_TLV, neigh);
-                       return ISIS_WARNING;
-               }
-
-               memcpy(neigh->sub_tlvs, pnt, neigh->sub_tlvs_length);
-               pnt += neigh->sub_tlvs_length;
-               length -= neigh->sub_tlvs_length;
-
-               listnode_add(neigh_list, neigh);
-       }
-
-       if (length) {
-               zlog_warn("ISIS-TLV: TE/MT neighor TLV has trailing data");
-               return ISIS_WARNING;
-       }
-
-       return ISIS_OK;
-}
-
-static int parse_mt_ipv4_reachs(struct tlvs *tlvs, bool read_mtid,
-                               unsigned int length, u_char *pnt)
-{
-       struct list *reach_list;
-       uint16_t mtid;
-       int rv;
-
-       rv = parse_mtid(&mtid, read_mtid, &length, &pnt);
-       if (rv != ISIS_OK)
-               return rv;
-
-       if (mtid == ISIS_MT_IPV4_UNICAST) {
-               if (!tlvs->te_ipv4_reachs) {
-                       tlvs->te_ipv4_reachs = list_new();
-                       tlvs->te_ipv4_reachs->del = free_tlv;
-               }
-               reach_list = tlvs->te_ipv4_reachs;
-       } else {
-               struct tlv_mt_ipv4_reachs *reachs;
-
-               reachs = tlvs_get_mt_ipv4_reachs(tlvs, mtid);
-               reachs->list->del = free_tlv;
-               reach_list = reachs->list;
-       }
-
-       while (length >= 5) /* Metric + Control */
-       {
-               struct te_ipv4_reachability *reach =
-                       XCALLOC(MTYPE_ISIS_TLV, TE_IPV4_REACH_LEN);
-
-               memcpy(reach, pnt, 5); /* Metric + Control */
-               pnt += 5;
-               length -= 5;
-
-               unsigned char prefixlen = reach->control & 0x3F;
-
-               if (prefixlen > IPV4_MAX_BITLEN) {
-                       zlog_warn(
-                               "ISIS-TLV: invalid IPv4 extended reachability prefix length %d",
-                               prefixlen);
-                       XFREE(MTYPE_ISIS_TLV, reach);
-                       return ISIS_WARNING;
-               }
-
-               if (length < (unsigned int)PSIZE(prefixlen)) {
-                       zlog_warn(
-                               "ISIS-TLV: invalid IPv4 extended reachability prefix too long for tlv");
-                       XFREE(MTYPE_ISIS_TLV, reach);
-                       return ISIS_WARNING;
-               }
-
-               memcpy(&reach->prefix_start, pnt, PSIZE(prefixlen));
-               pnt += PSIZE(prefixlen);
-               length -= PSIZE(prefixlen);
-
-               if (reach->control & TE_IPV4_HAS_SUBTLV) {
-                       if (length < 1) {
-                               zlog_warn(
-                                       "ISIS-TLV: invalid IPv4 extended reachability SubTLV missing");
-                               XFREE(MTYPE_ISIS_TLV, reach);
-                               return ISIS_WARNING;
-                       }
-
-                       u_char subtlv_len = *pnt;
-                       pnt++;
-                       length--;
-
-                       if (length < subtlv_len) {
-                               zlog_warn(
-                                       "ISIS-TLV: invalid IPv4 extended reachability SubTLVs have oversize");
-                               XFREE(MTYPE_ISIS_TLV, reach);
-                               return ISIS_WARNING;
-                       }
-
-                       /* Skip Sub-TLVs for now */
-                       pnt += subtlv_len;
-                       length -= subtlv_len;
-               }
-               listnode_add(reach_list, reach);
-       }
-
-       if (length) {
-               zlog_warn(
-                       "ISIS-TLV: TE/MT ipv4 reachability TLV has trailing data");
-               return ISIS_WARNING;
-       }
-
-       return ISIS_OK;
-}
-
-static int parse_mt_ipv6_reachs(struct tlvs *tlvs, bool read_mtid,
-                               unsigned int length, u_char *pnt)
-{
-       struct list *reach_list;
-       uint16_t mtid;
-       int rv;
-
-       rv = parse_mtid(&mtid, read_mtid, &length, &pnt);
-       if (rv != ISIS_OK)
-               return rv;
-
-       if (mtid == ISIS_MT_IPV4_UNICAST) {
-               if (!tlvs->ipv6_reachs) {
-                       tlvs->ipv6_reachs = list_new();
-                       tlvs->ipv6_reachs->del = free_tlv;
-               }
-               reach_list = tlvs->ipv6_reachs;
-       } else {
-               struct tlv_mt_ipv6_reachs *reachs;
-
-               reachs = tlvs_get_mt_ipv6_reachs(tlvs, mtid);
-               reachs->list->del = free_tlv;
-               reach_list = reachs->list;
-       }
-
-       while (length >= 6) /* Metric + Control + Prefixlen */
-       {
-               struct ipv6_reachability *reach =
-                       XCALLOC(MTYPE_ISIS_TLV, sizeof(*reach));
-
-               memcpy(reach, pnt, 6); /* Metric + Control + Prefixlen */
-               pnt += 6;
-               length -= 6;
-
-               if (reach->prefix_len > IPV6_MAX_BITLEN) {
-                       zlog_warn(
-                               "ISIS-TLV: invalid IPv6 reachability prefix length %d",
-                               reach->prefix_len);
-                       XFREE(MTYPE_ISIS_TLV, reach);
-                       return ISIS_WARNING;
-               }
-
-               if (length < (unsigned int)PSIZE(reach->prefix_len)) {
-                       zlog_warn(
-                               "ISIS-TLV: invalid IPv6 reachability prefix too long for tlv");
-                       XFREE(MTYPE_ISIS_TLV, reach);
-                       return ISIS_WARNING;
-               }
-
-               memcpy(&reach->prefix, pnt, PSIZE(reach->prefix_len));
-               pnt += PSIZE(reach->prefix_len);
-               length -= PSIZE(reach->prefix_len);
-
-               if (reach->control_info & CTRL_INFO_SUBTLVS) {
-                       if (length < 1) {
-                               zlog_warn(
-                                       "ISIS-TLV: invalid IPv6 reachability SubTLV missing");
-                               XFREE(MTYPE_ISIS_TLV, reach);
-                               return ISIS_WARNING;
-                       }
-
-                       u_char subtlv_len = *pnt;
-                       pnt++;
-                       length--;
-
-                       if (length < subtlv_len) {
-                               zlog_warn(
-                                       "ISIS-TLV: invalid IPv6 reachability SubTLVs have oversize");
-                               XFREE(MTYPE_ISIS_TLV, reach);
-                               return ISIS_WARNING;
-                       }
-
-                       /* Skip Sub-TLVs for now */
-                       pnt += subtlv_len;
-                       length -= subtlv_len;
-               }
-               listnode_add(reach_list, reach);
-       }
-
-       if (length) {
-               zlog_warn(
-                       "ISIS-TLV: (MT) IPv6 reachability TLV has trailing data");
-               return ISIS_WARNING;
-       }
-
-       return ISIS_OK;
-}
-
-/*
- * Parses the tlvs found in the variant length part of the PDU.
- * Caller tells with flags in "expected" which TLV's it is interested in.
- */
-int parse_tlvs(char *areatag, u_char *stream, int size, u_int32_t *expected,
-              u_int32_t *found, struct tlvs *tlvs, u_int32_t *auth_tlv_offset)
-{
-       u_char type, length;
-       struct lan_neigh *lan_nei;
-       struct area_addr *area_addr;
-       struct is_neigh *is_nei;
-       struct es_neigh *es_nei;
-       struct lsp_entry *lsp_entry;
-       struct in_addr *ipv4_addr;
-       struct ipv4_reachability *ipv4_reach;
-       struct in6_addr *ipv6_addr;
-       int value_len, retval = ISIS_OK;
-       u_char *start = stream, *pnt = stream;
-
-       *found = 0;
-       memset(tlvs, 0, sizeof(struct tlvs));
-
-       while (pnt < stream + size - 2) {
-               type = *pnt;
-               length = *(pnt + 1);
-               pnt += 2;
-               value_len = 0;
-               if (pnt + length > stream + size) {
-                       zlog_warn(
-                               "ISIS-TLV (%s): TLV (type %d, length %d) exceeds packet "
-                               "boundaries",
-                               areatag, type, length);
-                       retval = ISIS_WARNING;
-                       break;
-               }
-               switch (type) {
-               case AREA_ADDRESSES:
-                       /* +-------+-------+-------+-------+-------+-------+-------+-------+
-                        * |                        Address Length |
-                        * +-------+-------+-------+-------+-------+-------+-------+-------+
-                        * |                         Area Address |
-                        * +-------+-------+-------+-------+-------+-------+-------+-------+
-                        * : :
-                        */
-                       *found |= TLVFLAG_AREA_ADDRS;
-#ifdef EXTREME_TLV_DEBUG
-                       zlog_debug("TLV Area Adresses len %d", length);
-#endif /* EXTREME_TLV_DEBUG */
-                       if (*expected & TLVFLAG_AREA_ADDRS) {
-                               while (length > value_len) {
-                                       area_addr = (struct area_addr *)pnt;
-                                       value_len += area_addr->addr_len + 1;
-                                       pnt += area_addr->addr_len + 1;
-                                       if (!tlvs->area_addrs)
-                                               tlvs->area_addrs = list_new();
-                                       listnode_add(tlvs->area_addrs,
-                                                    area_addr);
-                               }
-                       } else {
-                               pnt += length;
-                       }
-                       break;
-
-               case IS_NEIGHBOURS:
-                       *found |= TLVFLAG_IS_NEIGHS;
-#ifdef EXTREME_TLV_DEBUG
-                       zlog_debug("ISIS-TLV (%s): IS Neighbours length %d",
-                                  areatag, length);
-#endif /* EXTREME_TLV_DEBUG */
-                       if (TLVFLAG_IS_NEIGHS & *expected) {
-                               /* +-------+-------+-------+-------+-------+-------+-------+-------+
-                                * |                        Virtual Flag |
-                                * +-------+-------+-------+-------+-------+-------+-------+-------+
-                                */
-                               pnt++;
-                               value_len++;
-                               /* +-------+-------+-------+-------+-------+-------+-------+-------+
-                                * |   0   |  I/E  |               Default
-                                * Metric                  |
-                                * +-------+-------+-------+-------+-------+-------+-------+-------+
-                                * |   S   |  I/E  |               Delay Metric
-                                * |
-                                * +-------+-------+-------+-------+-------+-------+-------+-------+
-                                * |   S   |  I/E  |               Expense
-                                * Metric                  |
-                                * +-------+-------+-------+-------+-------+-------+-------+-------+
-                                * |   S   |  I/E  |               Error Metric
-                                * |
-                                * +-------+-------+-------+-------+-------+-------+-------+-------+
-                                * |                        Neighbour ID |
-                                * +---------------------------------------------------------------+
-                                * : :
-                                */
-                               while (length > value_len) {
-                                       is_nei = (struct is_neigh *)pnt;
-                                       value_len += 4 + ISIS_SYS_ID_LEN + 1;
-                                       pnt += 4 + ISIS_SYS_ID_LEN + 1;
-                                       if (!tlvs->is_neighs)
-                                               tlvs->is_neighs = list_new();
-                                       listnode_add(tlvs->is_neighs, is_nei);
-                               }
-                       } else {
-                               pnt += length;
-                       }
-                       break;
-
-               case TE_IS_NEIGHBOURS:
-                       *found |= TLVFLAG_TE_IS_NEIGHS;
-#ifdef EXTREME_TLV_DEBUG
-                       zlog_debug(
-                               "ISIS-TLV (%s): Extended IS Neighbours length %d",
-                               areatag, length);
-#endif /* EXTREME_TLV_DEBUG */
-                       if (TLVFLAG_TE_IS_NEIGHS & *expected)
-                               retval = parse_mt_is_neighs(tlvs, false, length,
-                                                           pnt);
-                       pnt += length;
-                       break;
-
-               case MT_IS_NEIGHBOURS:
-                       *found |= TLVFLAG_TE_IS_NEIGHS;
-#ifdef EXTREME_TLV_DEBUG
-                       zlog_debug("ISIS-TLV (%s): MT IS Neighbours length %d",
-                                  areatag, length);
-#endif
-                       if (TLVFLAG_TE_IS_NEIGHS & *expected)
-                               retval = parse_mt_is_neighs(tlvs, true, length,
-                                                           pnt);
-                       pnt += length;
-                       break;
-
-               case ES_NEIGHBOURS:
-/* +-------+-------+-------+-------+-------+-------+-------+-------+
- * |   0   |  I/E  |               Default Metric                  |
- * +-------+-------+-------+-------+-------+-------+-------+-------+
- * |   S   |  I/E  |               Delay Metric                    |
- * +-------+-------+-------+-------+-------+-------+-------+-------+
- * |   S   |  I/E  |               Expense Metric                  |
- * +-------+-------+-------+-------+-------+-------+-------+-------+
- * |   S   |  I/E  |               Error Metric                    |
- * +-------+-------+-------+-------+-------+-------+-------+-------+
- * |                        Neighbour ID                           |
- * +---------------------------------------------------------------+
- * |                        Neighbour ID                           |
- * +---------------------------------------------------------------+
- * :                                                               :
- */
-#ifdef EXTREME_TLV_DEBUG
-                       zlog_debug("ISIS-TLV (%s): ES Neighbours length %d",
-                                  areatag, length);
-#endif /* EXTREME_TLV_DEBUG */
-                       *found |= TLVFLAG_ES_NEIGHS;
-                       if (*expected & TLVFLAG_ES_NEIGHS) {
-                               es_nei = (struct es_neigh *)pnt;
-                               value_len += 4;
-                               pnt += 4;
-                               while (length > value_len) {
-                                       /* FIXME FIXME FIXME - add to the list
-                                        */
-                                       /*          sys_id->id = pnt; */
-                                       value_len += ISIS_SYS_ID_LEN;
-                                       pnt += ISIS_SYS_ID_LEN;
-                                       /*  if (!es_nei->neigh_ids)
-                                        * es_nei->neigh_ids = sysid; */
-                               }
-                               if (!tlvs->es_neighs)
-                                       tlvs->es_neighs = list_new();
-                               listnode_add(tlvs->es_neighs, es_nei);
-                       } else {
-                               pnt += length;
-                       }
-                       break;
-
-               case LAN_NEIGHBOURS:
-                       /* +-------+-------+-------+-------+-------+-------+-------+-------+
-                        * |                        LAN Address |
-                        * +-------+-------+-------+-------+-------+-------+-------+-------+
-                        * : :
-                        */
-                       *found |= TLVFLAG_LAN_NEIGHS;
-#ifdef EXTREME_TLV_DEBUG
-                       zlog_debug("ISIS-TLV (%s): LAN Neigbours length %d",
-                                  areatag, length);
-#endif /* EXTREME_TLV_DEBUG */
-                       if (TLVFLAG_LAN_NEIGHS & *expected) {
-                               while (length > value_len) {
-                                       lan_nei = (struct lan_neigh *)pnt;
-                                       if (!tlvs->lan_neighs)
-                                               tlvs->lan_neighs = list_new();
-                                       listnode_add(tlvs->lan_neighs, lan_nei);
-                                       value_len += ETH_ALEN;
-                                       pnt += ETH_ALEN;
-                               }
-                       } else {
-                               pnt += length;
-                       }
-                       break;
-
-               case PADDING:
-#ifdef EXTREME_TLV_DEBUG
-                       zlog_debug("TLV padding %d", length);
-#endif /* EXTREME_TLV_DEBUG */
-                       pnt += length;
-                       break;
-
-               case LSP_ENTRIES:
-/* +-------+-------+-------+-------+-------+-------+-------+-------+
- * |                     Remaining Lifetime                        | 2
- * +-------+-------+-------+-------+-------+-------+-------+-------+
- * |                         LSP ID                                | id+2
- * +-------+-------+-------+-------+-------+-------+-------+-------+
- * |                   LSP Sequence Number                         | 4
- * +-------+-------+-------+-------+-------+-------+-------+-------+
- * |                        Checksum                               | 2
- * +-------+-------+-------+-------+-------+-------+-------+-------+
- */
-#ifdef EXTREME_TLV_DEBUG
-                       zlog_debug("ISIS-TLV (%s): LSP Entries length %d",
-                                  areatag, length);
-#endif /* EXTREME_TLV_DEBUG */
-                       *found |= TLVFLAG_LSP_ENTRIES;
-                       if (TLVFLAG_LSP_ENTRIES & *expected) {
-                               while (length > value_len) {
-                                       lsp_entry = (struct lsp_entry *)pnt;
-                                       value_len += 10 + ISIS_SYS_ID_LEN;
-                                       pnt += 10 + ISIS_SYS_ID_LEN;
-                                       if (!tlvs->lsp_entries)
-                                               tlvs->lsp_entries = list_new();
-                                       listnode_add(tlvs->lsp_entries,
-                                                    lsp_entry);
-                               }
-                       } else {
-                               pnt += length;
-                       }
-                       break;
-
-               case CHECKSUM:
-                       /* +-------+-------+-------+-------+-------+-------+-------+-------+
-                        * |                   16 bit fletcher CHECKSUM |
-                        * +-------+-------+-------+-------+-------+-------+-------+-------+
-                        * : :
-                        */
-                       *found |= TLVFLAG_CHECKSUM;
-#ifdef EXTREME_TLV_DEBUG
-                       zlog_debug("ISIS-TLV (%s): Checksum length %d", areatag,
-                                  length);
-#endif /* EXTREME_TLV_DEBUG */
-                       if (*expected & TLVFLAG_CHECKSUM) {
-                               tlvs->checksum = (struct checksum *)pnt;
-                       }
-                       pnt += length;
-                       break;
-
-               case PROTOCOLS_SUPPORTED:
-                       /* +-------+-------+-------+-------+-------+-------+-------+-------+
-                        * |                       NLPID |
-                        * +-------+-------+-------+-------+-------+-------+-------+-------+
-                        * : :
-                        */
-                       *found |= TLVFLAG_NLPID;
-#ifdef EXTREME_TLV_DEBUG
-                       zlog_debug(
-                               "ISIS-TLV (%s): Protocols Supported length %d",
-                               areatag, length);
-#endif /* EXTREME_TLV_DEBUG */
-                       if (*expected & TLVFLAG_NLPID) {
-                               tlvs->nlpids = (struct nlpids *)(pnt - 1);
-                       }
-                       pnt += length;
-                       break;
-
-               case IPV4_ADDR:
-                       /* +-------+-------+-------+-------+-------+-------+-------+-------+
-                        * +                 IP version 4 address + 4
-                        * +-------+-------+-------+-------+-------+-------+-------+-------+
-                        * : :
-                        */
-                       *found |= TLVFLAG_IPV4_ADDR;
-#ifdef EXTREME_TLV_DEBUG
-                       zlog_debug("ISIS-TLV (%s): IPv4 Address length %d",
-                                  areatag, length);
-#endif /* EXTREME_TLV_DEBUG */
-                       if (*expected & TLVFLAG_IPV4_ADDR) {
-                               while (length > value_len) {
-                                       ipv4_addr = (struct in_addr *)pnt;
-#ifdef EXTREME_TLV_DEBUG
-                                       zlog_debug(
-                                               "ISIS-TLV (%s) : IP ADDR %s, pnt %p",
-                                               areatag, inet_ntoa(*ipv4_addr),
-                                               pnt);
-#endif /* EXTREME_TLV_DEBUG */
-                                       if (!tlvs->ipv4_addrs)
-                                               tlvs->ipv4_addrs = list_new();
-                                       listnode_add(tlvs->ipv4_addrs,
-                                                    ipv4_addr);
-                                       value_len += 4;
-                                       pnt += 4;
-                               }
-                       } else {
-                               pnt += length;
-                       }
-                       break;
-
-               case AUTH_INFO:
-                       *found |= TLVFLAG_AUTH_INFO;
-#ifdef EXTREME_TLV_DEBUG
-                       zlog_debug(
-                               "ISIS-TLV (%s): IS-IS Authentication Information",
-                               areatag);
-#endif
-                       if (*expected & TLVFLAG_AUTH_INFO) {
-                               tlvs->auth_info.type = *pnt;
-                               if (length == 0) {
-                                       zlog_warn(
-                                               "ISIS-TLV (%s): TLV (type %d, length %d) "
-                                               "incorrect.",
-                                               areatag, type, length);
-                                       return ISIS_WARNING;
-                               }
-                               --length;
-                               tlvs->auth_info.len = length;
-                               pnt++;
-                               memcpy(tlvs->auth_info.passwd, pnt, length);
-                               /* Return the authentication tlv pos for later
-                                * computation
-                                * of MD5 (RFC 5304, 2)
-                                */
-                               if (auth_tlv_offset)
-                                       *auth_tlv_offset += (pnt - start - 3);
-                               pnt += length;
-                       } else {
-                               pnt += length;
-                       }
-                       break;
-
-               case DYNAMIC_HOSTNAME:
-                       *found |= TLVFLAG_DYN_HOSTNAME;
-#ifdef EXTREME_TLV_DEBUG
-                       zlog_debug("ISIS-TLV (%s): Dynamic Hostname length %d",
-                                  areatag, length);
-#endif /* EXTREME_TLV_DEBUG */
-                       if (*expected & TLVFLAG_DYN_HOSTNAME) {
-                               /* the length is also included in the pointed
-                                * struct */
-                               tlvs->hostname = (struct hostname *)(pnt - 1);
-                       }
-                       pnt += length;
-                       break;
-
-               case TE_ROUTER_ID:
-                       /* +---------------------------------------------------------------+
-                        * +                         Router ID + 4
-                        * +---------------------------------------------------------------+
-                        */
-                       *found |= TLVFLAG_TE_ROUTER_ID;
-#ifdef EXTREME_TLV_DEBUG
-                       zlog_debug("ISIS-TLV (%s): TE Router ID %d", areatag,
-                                  length);
-#endif /* EXTREME_TLV_DEBUG */
-                       if (*expected & TLVFLAG_TE_ROUTER_ID)
-                               tlvs->router_id = (struct te_router_id *)(pnt);
-                       pnt += length;
-                       break;
-
-               case IPV4_INT_REACHABILITY:
-                       /* +-------+-------+-------+-------+-------+-------+-------+-------+
-                        * |   0   |  I/E  |               Default Metric | 1
-                        * +-------+-------+-------+-------+-------+-------+-------+-------+
-                        * |   S   |  I/E  |               Delay Metric | 1
-                        * +-------+-------+-------+-------+-------+-------+-------+-------+
-                        * |   S   |  I/E  |               Expense Metric | 1
-                        * +-------+-------+-------+-------+-------+-------+-------+-------+
-                        * |   S   |  I/E  |               Error Metric | 1
-                        * +-------+-------+-------+-------+-------+-------+-------+-------+
-                        * |                        ip address | 4
-                        * +---------------------------------------------------------------+
-                        * |                        address mask | 4
-                        * +---------------------------------------------------------------+
-                        * : :
-                        */
-                       *found |= TLVFLAG_IPV4_INT_REACHABILITY;
-#ifdef EXTREME_TLV_DEBUG
-                       zlog_debug(
-                               "ISIS-TLV (%s): IPv4 internal Reachability length %d",
-                               areatag, length);
-#endif /* EXTREME_TLV_DEBUG */
-                       if (*expected & TLVFLAG_IPV4_INT_REACHABILITY) {
-                               while (length > value_len) {
-                                       ipv4_reach =
-                                               (struct ipv4_reachability *)pnt;
-                                       if (!tlvs->ipv4_int_reachs)
-                                               tlvs->ipv4_int_reachs =
-                                                       list_new();
-                                       listnode_add(tlvs->ipv4_int_reachs,
-                                                    ipv4_reach);
-                                       value_len += 12;
-                                       pnt += 12;
-                               }
-                       } else {
-                               pnt += length;
-                       }
-                       break;
-
-               case IPV4_EXT_REACHABILITY:
-                       /* +-------+-------+-------+-------+-------+-------+-------+-------+
-                        * |   0   |  I/E  |               Default Metric | 1
-                        * +-------+-------+-------+-------+-------+-------+-------+-------+
-                        * |   S   |  I/E  |               Delay Metric | 1
-                        * +-------+-------+-------+-------+-------+-------+-------+-------+
-                        * |   S   |  I/E  |               Expense Metric | 1
-                        * +-------+-------+-------+-------+-------+-------+-------+-------+
-                        * |   S   |  I/E  |               Error Metric | 1
-                        * +-------+-------+-------+-------+-------+-------+-------+-------+
-                        * |                        ip address | 4
-                        * +---------------------------------------------------------------+
-                        * |                        address mask | 4
-                        * +---------------------------------------------------------------+
-                        * : :
-                        */
-                       *found |= TLVFLAG_IPV4_EXT_REACHABILITY;
-#ifdef EXTREME_TLV_DEBUG
-                       zlog_debug(
-                               "ISIS-TLV (%s): IPv4 external Reachability length %d",
-                               areatag, length);
-#endif /* EXTREME_TLV_DEBUG */
-                       if (*expected & TLVFLAG_IPV4_EXT_REACHABILITY) {
-                               while (length > value_len) {
-                                       ipv4_reach =
-                                               (struct ipv4_reachability *)pnt;
-                                       if (!tlvs->ipv4_ext_reachs)
-                                               tlvs->ipv4_ext_reachs =
-                                                       list_new();
-                                       listnode_add(tlvs->ipv4_ext_reachs,
-                                                    ipv4_reach);
-                                       value_len += 12;
-                                       pnt += 12;
-                               }
-                       } else {
-                               pnt += length;
-                       }
-                       break;
-
-               case TE_IPV4_REACHABILITY:
-                       *found |= TLVFLAG_TE_IPV4_REACHABILITY;
-#ifdef EXTREME_TLV_DEBUG
-                       zlog_debug(
-                               "ISIS-TLV (%s): IPv4 extended Reachability length %d",
-                               areatag, length);
-#endif /* EXTREME_TLV_DEBUG */
-                       if (*expected & TLVFLAG_TE_IPV4_REACHABILITY)
-                               retval = parse_mt_ipv4_reachs(tlvs, false,
-                                                             length, pnt);
-                       pnt += length;
-                       break;
-               case MT_IPV4_REACHABILITY:
-                       *found |= TLVFLAG_TE_IPV4_REACHABILITY;
-#ifdef EXTREME_TLV_DEBUG
-                       zlog_debug(
-                               "ISIS-TLV (%s): IPv4 MT Reachability length %d",
-                               areatag, length);
-#endif /* EXTREME_TLV_DEBUG */
-                       if (*expected & TLVFLAG_TE_IPV4_REACHABILITY)
-                               retval = parse_mt_ipv4_reachs(tlvs, true,
-                                                             length, pnt);
-                       pnt += length;
-                       break;
-               case IPV6_ADDR:
-                       /* +-------+-------+-------+-------+-------+-------+-------+-------+
-                        * +                 IP version 6 address + 16
-                        * +-------+-------+-------+-------+-------+-------+-------+-------+
-                        * : :
-                        */
-                       *found |= TLVFLAG_IPV6_ADDR;
-#ifdef EXTREME_TLV_DEBUG
-                       zlog_debug("ISIS-TLV (%s): IPv6 Address length %d",
-                                  areatag, length);
-#endif /* EXTREME_TLV_DEBUG */
-                       if (*expected & TLVFLAG_IPV6_ADDR) {
-                               while (length > value_len) {
-                                       ipv6_addr = (struct in6_addr *)pnt;
-                                       if (!tlvs->ipv6_addrs)
-                                               tlvs->ipv6_addrs = list_new();
-                                       listnode_add(tlvs->ipv6_addrs,
-                                                    ipv6_addr);
-                                       value_len += 16;
-                                       pnt += 16;
-                               }
-                       } else {
-                               pnt += length;
-                       }
-                       break;
-
-               case IPV6_REACHABILITY:
-                       *found |= TLVFLAG_IPV6_REACHABILITY;
-#ifdef EXTREME_TLV_DEBUG
-                       zlog_debug("ISIS-TLV (%s): IPv6 Reachability length %d",
-                                  areatag, length);
-#endif /* EXTREME_TLV_DEBUG */
-                       if (*expected & TLVFLAG_IPV6_REACHABILITY)
-                               retval = parse_mt_ipv6_reachs(tlvs, false,
-                                                             length, pnt);
-                       pnt += length;
-                       break;
-               case MT_IPV6_REACHABILITY:
-                       *found |= TLVFLAG_IPV6_REACHABILITY;
-#ifdef EXTREME_TLV_DEBUG
-                       zlog_debug("ISIS-TLV (%s): IPv6 Reachability length %d",
-                                  areatag, length);
-#endif /* EXTREME_TLV_DEBUG */
-                       if (*expected & TLVFLAG_IPV6_REACHABILITY)
-                               retval = parse_mt_ipv6_reachs(tlvs, true,
-                                                             length, pnt);
-                       pnt += length;
-                       break;
-               case WAY3_HELLO:
-                       /* +---------------------------------------------------------------+
-                        * |                  Adjacency state | 1
-                        * +---------------------------------------------------------------+
-                        * |                  Extended Local Circuit ID | 4
-                        * +---------------------------------------------------------------+
-                        * |                  Neighbor System ID (If known)
-                        * | 0-8
-                        *                                      (probably 6)
-                        * +---------------------------------------------------------------+
-                        * |                  Neighbor Local Circuit ID (If
-                        * known)         | 4
-                        * +---------------------------------------------------------------+
-                        */
-                       *found |= TLVFLAG_3WAY_HELLO;
-                       if (*expected & TLVFLAG_3WAY_HELLO) {
-                               while (length > value_len) {
-                                       /* FIXME: make this work */
-                                       /*           Adjacency State (one
-                                          octet):
-                                                     0 = Up
-                                                     1 = Initializing
-                                                     2 = Down
-                                                   Extended Local Circuit ID
-                                          (four octets)
-                                                   Neighbor System ID if known
-                                          (zero to eight octets)
-                                                   Neighbor Extended Local
-                                          Circuit ID (four octets, if Neighbor
-                                                     System ID is present) */
-                                       pnt += length;
-                                       value_len += length;
-                               }
-                       } else {
-                               pnt += length;
-                       }
-
-                       break;
-               case GRACEFUL_RESTART:
-                       /* +-------+-------+-------+-------+-------+-------+-------+-------+
-                        * |         Reserved                      |  SA   |  RA
-                        * |  RR   | 1
-                        * +-------+-------+-------+-------+-------+-------+-------+-------+
-                        * |                          Remaining Time | 2
-                        * +---------------------------------------------------------------+
-                        * |                Restarting Neighbor ID (If known)
-                        * | 0-8
-                        * +---------------------------------------------------------------+
-                        */
-                       *found |= TLVFLAG_GRACEFUL_RESTART;
-                       if (*expected & TLVFLAG_GRACEFUL_RESTART) {
-                               /* FIXME: make this work */
-                       }
-                       pnt += length;
-                       break;
-
-               case MT_ROUTER_INFORMATION:
-                       *found |= TLVFLAG_MT_ROUTER_INFORMATION;
-                       if (*expected & TLVFLAG_MT_ROUTER_INFORMATION) {
-                               if (!tlvs->mt_router_info) {
-                                       tlvs->mt_router_info = list_new();
-                                       tlvs->mt_router_info->del = free_tlv;
-                               }
-                               while (length > value_len) {
-                                       uint16_t mt_info;
-                                       struct mt_router_info *info;
-
-                                       if (value_len + sizeof(mt_info)
-                                           > length) {
-                                               zlog_warn(
-                                                       "ISIS-TLV (%s): TLV 229 is truncated.",
-                                                       areatag);
-                                               pnt += length - value_len;
-                                               break;
-                                       }
-
-                                       memcpy(&mt_info, pnt, sizeof(mt_info));
-                                       pnt += sizeof(mt_info);
-                                       value_len += sizeof(mt_info);
-
-                                       mt_info = ntohs(mt_info);
-                                       info = XCALLOC(MTYPE_ISIS_TLV,
-                                                      sizeof(*info));
-                                       info->mtid = mt_info & ISIS_MT_MASK;
-                                       info->overload =
-                                               mt_info & ISIS_MT_OL_MASK;
-                                       listnode_add(tlvs->mt_router_info,
-                                                    info);
-                               }
-                       } else {
-                               pnt += length;
-                       }
-                       break;
-               default:
-                       zlog_warn(
-                               "ISIS-TLV (%s): unsupported TLV type %d, length %d",
-                               areatag, type, length);
-
-                       pnt += length;
-                       break;
-               }
-               /* Abort Parsing if error occured */
-               if (retval != ISIS_OK)
-                       return retval;
-       }
-
-       return retval;
-}
-
-int add_tlv(u_char tag, u_char len, u_char *value, struct stream *stream)
-{
-       if ((stream_get_size(stream) - stream_get_endp(stream))
-           < (((unsigned)len) + 2)) {
-               zlog_warn(
-                       "No room for TLV of type %d "
-                       "(total size %d available %d required %d)",
-                       tag, (int)stream_get_size(stream),
-                       (int)(stream_get_size(stream)
-                             - stream_get_endp(stream)),
-                       len + 2);
-               return ISIS_WARNING;
-       }
-
-       stream_putc(stream, tag);           /* TAG */
-       stream_putc(stream, len);           /* LENGTH */
-       stream_put(stream, value, (int)len); /* VALUE */
-
-#ifdef EXTREME_DEBUG
-       zlog_debug("Added TLV %d len %d", tag, len);
-#endif /* EXTREME DEBUG */
-       return ISIS_OK;
-}
-
-int tlv_add_mt_router_info(struct list *mt_router_info, struct stream *stream)
-{
-       struct listnode *node;
-       struct mt_router_info *info;
-
-       uint16_t value[127];
-       uint16_t *pos = value;
-
-       for (ALL_LIST_ELEMENTS_RO(mt_router_info, node, info)) {
-               uint16_t mt_info;
-
-               mt_info = info->mtid;
-               if (info->overload)
-                       mt_info |= ISIS_MT_OL_MASK;
-
-               *pos = htons(mt_info);
-               pos++;
-       }
-
-       return add_tlv(MT_ROUTER_INFORMATION, (pos - value) * sizeof(*pos),
-                      (u_char *)value, stream);
-}
-
-int tlv_add_area_addrs(struct list *area_addrs, struct stream *stream)
-{
-       struct listnode *node;
-       struct area_addr *area_addr;
-
-       u_char value[255];
-       u_char *pos = value;
-
-       for (ALL_LIST_ELEMENTS_RO(area_addrs, node, area_addr)) {
-               if (pos - value + area_addr->addr_len > 255)
-                       goto err;
-               *pos = area_addr->addr_len;
-               pos++;
-               memcpy(pos, area_addr->area_addr, (int)area_addr->addr_len);
-               pos += area_addr->addr_len;
-       }
-
-       return add_tlv(AREA_ADDRESSES, pos - value, value, stream);
-
-err:
-       zlog_warn("tlv_add_area_addrs(): TLV longer than 255");
-       return ISIS_WARNING;
-}
-
-int tlv_add_is_neighs(struct list *is_neighs, struct stream *stream)
-{
-       struct listnode *node;
-       struct is_neigh *is_neigh;
-       u_char value[255];
-       u_char *pos = value;
-       int retval;
-
-       *pos = 0; /*is_neigh->virtual; */
-       pos++;
-
-       for (ALL_LIST_ELEMENTS_RO(is_neighs, node, is_neigh)) {
-               if (pos - value + IS_NEIGHBOURS_LEN > 255) {
-                       retval = add_tlv(IS_NEIGHBOURS, pos - value, value,
-                                        stream);
-                       if (retval != ISIS_OK)
-                               return retval;
-                       pos = value;
-               }
-               *pos = is_neigh->metrics.metric_default;
-               pos++;
-               *pos = is_neigh->metrics.metric_delay;
-               pos++;
-               *pos = is_neigh->metrics.metric_expense;
-               pos++;
-               *pos = is_neigh->metrics.metric_error;
-               pos++;
-               memcpy(pos, is_neigh->neigh_id, ISIS_SYS_ID_LEN + 1);
-               pos += ISIS_SYS_ID_LEN + 1;
-       }
-
-       return add_tlv(IS_NEIGHBOURS, pos - value, value, stream);
-}
-
-static size_t max_tlv_size(struct stream *stream)
-{
-       size_t avail = stream_get_size(stream) - stream_get_endp(stream);
-
-       if (avail < 2)
-               return 0;
-
-       if (avail < 257)
-               return avail - 2;
-
-       return 255;
-}
-
-unsigned int tlv_add_te_is_neighs(struct list *te_is_neighs,
-                                 struct stream *stream, void *arg)
-{
-       struct listnode *node;
-       struct te_is_neigh *te_is_neigh;
-       u_char value[255];
-       u_char *pos = value;
-       uint16_t mtid = arg ? *(uint16_t *)arg : ISIS_MT_IPV4_UNICAST;
-       unsigned int consumed = 0;
-       size_t max_size = max_tlv_size(stream);
-
-       if (mtid != ISIS_MT_IPV4_UNICAST) {
-               uint16_t mtid_conversion = ntohs(mtid);
-               memcpy(pos, &mtid_conversion, sizeof(mtid_conversion));
-               pos += sizeof(mtid_conversion);
-       }
-
-       for (ALL_LIST_ELEMENTS_RO(te_is_neighs, node, te_is_neigh)) {
-               /* FIXME: Check if Total SubTLVs size doesn't exceed 255 */
-               if ((size_t)(pos - value) + IS_NEIGHBOURS_LEN
-                           + te_is_neigh->sub_tlvs_length
-                   > max_size)
-                       break;
-
-               memcpy(pos, te_is_neigh->neigh_id, ISIS_SYS_ID_LEN + 1);
-               pos += ISIS_SYS_ID_LEN + 1;
-               memcpy(pos, te_is_neigh->te_metric, 3);
-               pos += 3;
-               /* Set the total size of Sub TLVs */
-               *pos = te_is_neigh->sub_tlvs_length;
-               pos++;
-               /* Copy Sub TLVs if any */
-               if (te_is_neigh->sub_tlvs_length > 0) {
-                       memcpy(pos, te_is_neigh->sub_tlvs,
-                              te_is_neigh->sub_tlvs_length);
-                       pos += te_is_neigh->sub_tlvs_length;
-               }
-               consumed++;
-       }
-
-       if (consumed) {
-               int rv = add_tlv((mtid != ISIS_MT_IPV4_UNICAST)
-                                        ? MT_IS_NEIGHBOURS
-                                        : TE_IS_NEIGHBOURS,
-                                pos - value, value, stream);
-               assert(rv == ISIS_OK);
-       }
-       return consumed;
-}
-
-int tlv_add_lan_neighs(struct list *lan_neighs, struct stream *stream)
-{
-       struct listnode *node;
-       u_char *snpa;
-       u_char value[255];
-       u_char *pos = value;
-       int retval;
-
-       for (ALL_LIST_ELEMENTS_RO(lan_neighs, node, snpa)) {
-               if (pos - value + ETH_ALEN > 255) {
-                       retval = add_tlv(LAN_NEIGHBOURS, pos - value, value,
-                                        stream);
-                       if (retval != ISIS_OK)
-                               return retval;
-                       pos = value;
-               }
-               memcpy(pos, snpa, ETH_ALEN);
-               pos += ETH_ALEN;
-       }
-
-       return add_tlv(LAN_NEIGHBOURS, pos - value, value, stream);
-}
-
-int tlv_add_nlpid(struct nlpids *nlpids, struct stream *stream)
-{
-       return add_tlv(PROTOCOLS_SUPPORTED, nlpids->count, nlpids->nlpids,
-                      stream);
-}
-
-int tlv_add_authinfo(u_char auth_type, u_char auth_len, u_char *auth_value,
-                    struct stream *stream)
-{
-       u_char value[255];
-       u_char *pos = value;
-       *pos++ = auth_type;
-       memcpy(pos, auth_value, auth_len);
-
-       return add_tlv(AUTH_INFO, auth_len + 1, value, stream);
-}
-
-int tlv_add_checksum(struct checksum *checksum, struct stream *stream)
-{
-       u_char value[255];
-       u_char *pos = value;
-       return add_tlv(CHECKSUM, pos - value, value, stream);
-}
-
-int tlv_add_ip_addrs(struct list *ip_addrs, struct stream *stream)
-{
-       struct listnode *node;
-       struct prefix_ipv4 *ipv4;
-       u_char value[255];
-       u_char *pos = value;
-
-       for (ALL_LIST_ELEMENTS_RO(ip_addrs, node, ipv4)) {
-               if (pos - value + IPV4_MAX_BYTELEN > 255) {
-                       /* RFC 1195 s4.2: only one tuple of 63 allowed. */
-                       zlog_warn(
-                               "tlv_add_ip_addrs(): cutting off at 63 IP addresses");
-                       break;
-               }
-               *(u_int32_t *)pos = ipv4->prefix.s_addr;
-               pos += IPV4_MAX_BYTELEN;
-       }
-
-       return add_tlv(IPV4_ADDR, pos - value, value, stream);
-}
-
-/* Used to add TLV containing just one IPv4 address - either IPv4 address TLV
- * (in case of LSP) or TE router ID TLV. */
-int tlv_add_in_addr(struct in_addr *addr, struct stream *stream, u_char tag)
-{
-       u_char value[255];
-       u_char *pos = value;
-
-       memcpy(pos, addr, IPV4_MAX_BYTELEN);
-       pos += IPV4_MAX_BYTELEN;
-
-       return add_tlv(tag, pos - value, value, stream);
-}
-
-int tlv_add_dynamic_hostname(struct hostname *hostname, struct stream *stream)
-{
-       return add_tlv(DYNAMIC_HOSTNAME, hostname->namelen, hostname->name,
-                      stream);
-}
-
-int tlv_add_lsp_entries(struct list *lsps, struct stream *stream)
-{
-       struct listnode *node;
-       struct isis_lsp *lsp;
-       u_char value[255];
-       u_char *pos = value;
-       int retval;
-
-       for (ALL_LIST_ELEMENTS_RO(lsps, node, lsp)) {
-               if (pos - value + LSP_ENTRIES_LEN > 255) {
-                       retval = add_tlv(LSP_ENTRIES, pos - value, value,
-                                        stream);
-                       if (retval != ISIS_OK)
-                               return retval;
-                       pos = value;
-               }
-               *((u_int16_t *)pos) = lsp->lsp_header->rem_lifetime;
-               pos += 2;
-               memcpy(pos, lsp->lsp_header->lsp_id, ISIS_SYS_ID_LEN + 2);
-               pos += ISIS_SYS_ID_LEN + 2;
-               *((u_int32_t *)pos) = lsp->lsp_header->seq_num;
-               pos += 4;
-               *((u_int16_t *)pos) = lsp->lsp_header->checksum;
-               pos += 2;
-       }
-
-       return add_tlv(LSP_ENTRIES, pos - value, value, stream);
-}
-
-static int tlv_add_ipv4_reachs(u_char tag, struct list *ipv4_reachs,
-                              struct stream *stream)
-{
-       struct listnode *node;
-       struct ipv4_reachability *reach;
-       u_char value[255];
-       u_char *pos = value;
-       int retval;
-
-       for (ALL_LIST_ELEMENTS_RO(ipv4_reachs, node, reach)) {
-               if (pos - value + IPV4_REACH_LEN > 255) {
-                       retval = add_tlv(tag, pos - value, value, stream);
-                       if (retval != ISIS_OK)
-                               return retval;
-                       pos = value;
-               }
-               *pos = reach->metrics.metric_default;
-               pos++;
-               *pos = reach->metrics.metric_delay;
-               pos++;
-               *pos = reach->metrics.metric_expense;
-               pos++;
-               *pos = reach->metrics.metric_error;
-               pos++;
-               *(u_int32_t *)pos = reach->prefix.s_addr;
-               pos += IPV4_MAX_BYTELEN;
-               *(u_int32_t *)pos = reach->mask.s_addr;
-               pos += IPV4_MAX_BYTELEN;
-       }
-
-       return add_tlv(tag, pos - value, value, stream);
-}
-
-int tlv_add_ipv4_int_reachs(struct list *ipv4_reachs, struct stream *stream)
-{
-       return tlv_add_ipv4_reachs(IPV4_INT_REACHABILITY, ipv4_reachs, stream);
-}
-
-int tlv_add_ipv4_ext_reachs(struct list *ipv4_reachs, struct stream *stream)
-{
-       return tlv_add_ipv4_reachs(IPV4_EXT_REACHABILITY, ipv4_reachs, stream);
-}
-
-
-unsigned int tlv_add_te_ipv4_reachs(struct list *te_ipv4_reachs,
-                                   struct stream *stream, void *arg)
-{
-       struct listnode *node;
-       struct te_ipv4_reachability *te_reach;
-       u_char value[255];
-       u_char *pos = value;
-       uint16_t mtid = arg ? *(uint16_t *)arg : ISIS_MT_IPV4_UNICAST;
-       unsigned int consumed = 0;
-       size_t max_size = max_tlv_size(stream);
-
-       if (mtid != ISIS_MT_IPV4_UNICAST) {
-               uint16_t mtid_conversion = ntohs(mtid);
-               memcpy(pos, &mtid_conversion, sizeof(mtid_conversion));
-               pos += sizeof(mtid_conversion);
-       }
-
-       for (ALL_LIST_ELEMENTS_RO(te_ipv4_reachs, node, te_reach)) {
-               unsigned char prefixlen = te_reach->control & 0x3F;
-
-               if ((size_t)(pos - value) + 5 + PSIZE(prefixlen) > max_size)
-                       break;
-
-               *(u_int32_t *)pos = te_reach->te_metric;
-               pos += 4;
-               *pos = te_reach->control;
-               pos++;
-               memcpy(pos, &te_reach->prefix_start, PSIZE(prefixlen));
-               pos += PSIZE(prefixlen);
-               consumed++;
-       }
-
-       if (consumed) {
-               int rv = add_tlv((mtid != ISIS_MT_IPV4_UNICAST)
-                                        ? MT_IPV4_REACHABILITY
-                                        : TE_IPV4_REACHABILITY,
-                                pos - value, value, stream);
-               assert(rv == ISIS_OK);
-       }
-
-       return consumed;
-}
-
-int tlv_add_ipv6_addrs(struct list *ipv6_addrs, struct stream *stream)
-{
-       struct listnode *node;
-       struct prefix_ipv6 *ipv6;
-       u_char value[255];
-       u_char *pos = value;
-       int retval;
-
-       for (ALL_LIST_ELEMENTS_RO(ipv6_addrs, node, ipv6)) {
-               if (pos - value + IPV6_MAX_BYTELEN > 255) {
-                       retval = add_tlv(IPV6_ADDR, pos - value, value, stream);
-                       if (retval != ISIS_OK)
-                               return retval;
-                       pos = value;
-               }
-               memcpy(pos, ipv6->prefix.s6_addr, IPV6_MAX_BYTELEN);
-               pos += IPV6_MAX_BYTELEN;
-       }
-
-       return add_tlv(IPV6_ADDR, pos - value, value, stream);
-}
-
-unsigned int tlv_add_ipv6_reachs(struct list *ipv6_reachs,
-                                struct stream *stream, void *arg)
-{
-       struct listnode *node;
-       struct ipv6_reachability *ip6reach;
-       u_char value[255];
-       u_char *pos = value;
-       uint16_t mtid = arg ? *(uint16_t *)arg : ISIS_MT_IPV4_UNICAST;
-       unsigned int consumed = 0;
-       size_t max_size = max_tlv_size(stream);
-
-       if (mtid != ISIS_MT_IPV4_UNICAST) {
-               uint16_t mtid_conversion = ntohs(mtid);
-               memcpy(pos, &mtid_conversion, sizeof(mtid_conversion));
-               pos += sizeof(mtid_conversion);
-       }
-
-       for (ALL_LIST_ELEMENTS_RO(ipv6_reachs, node, ip6reach)) {
-               if ((size_t)(pos - value) + 6 + PSIZE(ip6reach->prefix_len)
-                   > max_size)
-                       break;
-
-               *(uint32_t *)pos = ip6reach->metric;
-               pos += 4;
-               *pos = ip6reach->control_info;
-               pos++;
-               *pos = ip6reach->prefix_len;
-               pos++;
-               memcpy(pos, ip6reach->prefix, PSIZE(ip6reach->prefix_len));
-               pos += PSIZE(ip6reach->prefix_len);
-               consumed++;
-       }
-
-       if (consumed) {
-               int rv = add_tlv((mtid != ISIS_MT_IPV4_UNICAST)
-                                        ? MT_IPV6_REACHABILITY
-                                        : IPV6_REACHABILITY,
-                                pos - value, value, stream);
-               assert(rv == ISIS_OK);
-       }
-
-       return consumed;
-}
-
-int tlv_add_padding(struct stream *stream)
-{
-       int fullpads, i, left;
-
-       /*
-        * How many times can we add full padding ?
-        */
-       fullpads = (stream_get_size(stream) - stream_get_endp(stream)) / 257;
-       for (i = 0; i < fullpads; i++) {
-               if (!stream_putc(stream, (u_char)PADDING)) /* TAG */
-                       goto err;
-               if (!stream_putc(stream, (u_char)255)) /* LENGHT */
-                       goto err;
-               stream_put(stream, NULL, 255); /* zero padding */
-       }
-
-       left = stream_get_size(stream) - stream_get_endp(stream);
-
-       if (left < 2)
-               return ISIS_OK;
-
-       if (left == 2) {
-               stream_putc(stream, PADDING);
-               stream_putc(stream, 0);
-               return ISIS_OK;
-       }
-
-       stream_putc(stream, PADDING);
-       stream_putc(stream, left - 2);
-       stream_put(stream, NULL, left - 2);
-
-       return ISIS_OK;
-
-err:
-       zlog_warn("tlv_add_padding(): no room for tlv");
-       return ISIS_WARNING;
-}
diff --git a/isisd/isis_tlv.h b/isisd/isis_tlv.h
deleted file mode 100644 (file)
index d065485..0000000
+++ /dev/null
@@ -1,340 +0,0 @@
-/*
- * IS-IS Rout(e)ing protocol - isis_tlv.h
- *                             IS-IS TLV related routines
- *
- * Copyright (C) 2001,2002   Sampo Saaristo
- *                           Tampere University of Technology
- *                           Institute of Communications Engineering
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public Licenseas published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; see the file COPYING; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#ifndef _ZEBRA_ISIS_TLV_H
-#define _ZEBRA_ISIS_TLV_H
-
-#include "isisd/isis_mt.h"
-
-/*
- * The list of TLVs we (should) support.
- * ____________________________________________________________________________
- * Name                   Value  IIH LSP SNP Status
- *                               LAN
- * ____________________________________________________________________________
- *
- * Area Addresses             1   y   y   n  ISO10589
- * IIS Neighbors              2   n   y   n  ISO10589
- * ES Neighbors               3   n   y   n  ISO10589
- * IIS Neighbors              6   y   n   n  ISO10589
- * Padding                    8   y   n   n  ISO10589
- * LSP Entries                9   n   n   y  ISO10589
- * Authentication            10   y   y   y  ISO10589, RFC3567
- * Checksum                  12   y   n   y  RFC3358
- * Extended IS Reachability  22   n   y   n  RFC5305
- * IS Alias                  24   n   y   n  RFC3786
- * IP Int. Reachability     128   n   y   n  RFC1195
- * Protocols Supported      129   y   y   n  RFC1195
- * IP Ext. Reachability     130   n   y   n  RFC1195
- * IDRPI                    131   n   y   y  RFC1195
- * IP Interface Address     132   y   y   n  RFC1195
- * TE Router ID             134   n   y   n  RFC5305
- * Extended IP Reachability 135   n   y   n  RFC5305
- * Dynamic Hostname         137   n   y   n  RFC2763
- * Shared Risk Link Group   138   n   y   y  RFC5307
- * Inter-AS Reachability    141   n   y   n  RFC5316
- * Restart TLV              211   y   n   n  RFC3847
- * MT IS Reachability       222   n   y   n  RFC5120
- * MT Supported             229   y   y   n  RFC5120
- * IPv6 Interface Address   232   y   y   n  RFC5308
- * MT IP Reachability       235   n   y   n  RFC5120
- * IPv6 IP Reachability     236   n   y   n  RFC5308
- * MT IPv6 IP Reachability  237   n   y   n  RFC5120
- * P2P Adjacency State      240   y   n   n  RFC3373
- * IIH Sequence Number      241   y   n   n  draft-shen-isis-iih-sequence
- * Router Capability        242   n   y   n  RFC4971
- *
- *
- * IS Reachability sub-TLVs we support (See isis_te.[c,h])
- * ____________________________________________________________________________
- * Name                           Value   Status
- * ____________________________________________________________________________
- * Administartive group (color)       3   RFC5305
- * Link Local/Remote Identifiers      4   RFC5307
- * IPv4 interface address             6   RFC5305
- * IPv4 neighbor address              8   RFC5305
- * Maximum link bandwidth             9   RFC5305
- * Reservable link bandwidth         10   RFC5305
- * Unreserved bandwidth              11   RFC5305
- * TE Default metric                 18   RFC5305
- * Link Protection Type              20   RFC5307
- * Interface Switching Capability    21   RFC5307
- * Remote AS number                  24   RFC5316
- * IPv4 Remote ASBR identifier       25   RFC5316
- *
- *
- * IP Reachability sub-TLVs we (should) support.
- * ____________________________________________________________________________
- * Name                           Value   Status
- * ____________________________________________________________________________
- * 32bit administrative tag           1   RFC5130
- * 64bit administrative tag           2   RFC5130
- * Management prefix color          117   RFC5120
- */
-
-#define AREA_ADDRESSES            1
-#define IS_NEIGHBOURS             2
-#define ES_NEIGHBOURS             3
-#define LAN_NEIGHBOURS            6
-#define PADDING                   8
-#define LSP_ENTRIES               9
-#define AUTH_INFO                 10
-#define CHECKSUM                  12
-#define TE_IS_NEIGHBOURS          22
-#define IS_ALIAS                  24
-#define IPV4_INT_REACHABILITY     128
-#define PROTOCOLS_SUPPORTED       129
-#define IPV4_EXT_REACHABILITY     130
-#define IDRP_INFO                 131
-#define IPV4_ADDR                 132
-#define TE_ROUTER_ID              134
-#define TE_IPV4_REACHABILITY      135
-#define DYNAMIC_HOSTNAME          137
-#define GRACEFUL_RESTART          211
-#define MT_IS_NEIGHBOURS          222
-#define MT_ROUTER_INFORMATION     229
-#define IPV6_ADDR                 232
-#define MT_IPV4_REACHABILITY      235
-#define IPV6_REACHABILITY         236
-#define MT_IPV6_REACHABILITY      237
-#define WAY3_HELLO                240
-#define ROUTER_INFORMATION        242
-
-#define AUTH_INFO_HDRLEN          3
-
-#define MAX_TLV_LEN 255
-
-#define IS_NEIGHBOURS_LEN (ISIS_SYS_ID_LEN + 5)
-#define LAN_NEIGHBOURS_LEN 6
-#define LSP_ENTRIES_LEN (10 + ISIS_SYS_ID_LEN) /* FIXME: should be entry */
-#define IPV4_REACH_LEN 12
-#define IPV6_REACH_LEN 22
-#define TE_IPV4_REACH_LEN 9
-
-#define MAX_SUBTLV_SIZE         256
-
-/* struct for neighbor */
-struct is_neigh {
-       struct metric metrics;
-       u_char neigh_id[ISIS_SYS_ID_LEN + 1];
-};
-
-/* struct for te metric */
-struct te_is_neigh {
-       u_char neigh_id[ISIS_SYS_ID_LEN + 1];
-       u_char te_metric[3];
-       u_char sub_tlvs_length;
-       /* Theorical Maximum SubTLVs is 256 because the sub_tlvs_length is 8
-        * bits */
-       /* Practically, 118 bytes are necessary to store all supported TE
-        * parameters */
-       /* FIXME: A pointer will use less memory, but need to be free */
-       /* which is hard to fix, especially within free_tlvs() function */
-       /* and malloc() / free() as a CPU cost compared to the memory usage */
-       u_char sub_tlvs[MAX_SUBTLV_SIZE]; /* SUB TLVs storage */
-};
-
-/* Decode and encode three-octet metric into host byte order integer */
-#define GET_TE_METRIC(t)                                                       \
-       (((unsigned)(t)->te_metric[0] << 16) | ((t)->te_metric[1] << 8)        \
-        | (t)->te_metric[2])
-#define SET_TE_METRIC(t, m)                                                    \
-       (((t)->te_metric[0] = (m) >> 16), ((t)->te_metric[1] = (m) >> 8),      \
-        ((t)->te_metric[2] = (m)))
-
-/* struct for es neighbors */
-struct es_neigh {
-       struct metric metrics;
-       /* approximate position of first, we use the
-        * length ((uchar*)metric-1) to know all     */
-       u_char first_es_neigh[ISIS_SYS_ID_LEN];
-};
-
-struct partition_desig_level2_is {
-       struct list *isis_system_ids;
-};
-
-/* struct for lan neighbors */
-struct lan_neigh {
-       u_char LAN_addr[6];
-};
-
-#ifdef __SUNPRO_C
-#pragma pack(1)
-#endif
-
-/* struct for LSP entry */
-struct lsp_entry {
-       u_int16_t rem_lifetime;
-       u_char lsp_id[ISIS_SYS_ID_LEN + 2];
-       u_int32_t seq_num;
-       u_int16_t checksum;
-} __attribute__((packed));
-
-#ifdef __SUNPRO_C
-#pragma pack()
-#endif
-
-/* struct for checksum */
-struct checksum {
-       u_int16_t checksum;
-};
-
-/* ipv4 reachability */
-struct ipv4_reachability {
-       struct metric metrics;
-       struct in_addr prefix;
-       struct in_addr mask;
-};
-
-/* te router id */
-struct te_router_id {
-       struct in_addr id;
-};
-
-/* te ipv4 reachability */
-struct te_ipv4_reachability {
-       u_int32_t te_metric;
-       u_char control;
-       u_char prefix_start; /* since this is variable length by nature it only
-                               */
-};                          /* points to an approximate location */
-
-#define TE_IPV4_HAS_SUBTLV (0x40)
-
-struct idrp_info {
-       u_char len;
-       u_char *value;
-};
-
-struct ipv6_reachability {
-       u_int32_t metric;
-       u_char control_info;
-       u_char prefix_len;
-       u_char prefix[16];
-};
-
-/* bits in control_info */
-#define CTRL_INFO_DIRECTION    0x80
-#define DIRECTION_UP           0x00
-#define DIRECTION_DOWN         0x80
-
-#define CTRL_INFO_DISTRIBUTION 0x40
-#define DISTRIBUTION_INTERNAL  0x00
-#define DISTRIBUTION_EXTERNAL  0x40
-
-#define CTRL_INFO_SUBTLVS      0x20
-
-struct mt_router_info {
-       ISIS_MT_INFO_FIELDS
-       bool overload;
-};
-
-/*
- * Pointer to each tlv type, filled by parse_tlvs()
- */
-struct tlvs {
-       struct checksum *checksum;
-       struct hostname *hostname;
-       struct nlpids *nlpids;
-       struct te_router_id *router_id;
-       struct list *area_addrs;
-       struct list *mt_router_info;
-       struct list *is_neighs;
-       struct list *te_is_neighs;
-       struct list *mt_is_neighs;
-       struct list *es_neighs;
-       struct list *lsp_entries;
-       struct list *prefix_neighs;
-       struct list *lan_neighs;
-       struct list *ipv4_addrs;
-       struct list *ipv4_int_reachs;
-       struct list *ipv4_ext_reachs;
-       struct list *te_ipv4_reachs;
-       struct list *mt_ipv4_reachs;
-       struct list *ipv6_addrs;
-       struct list *ipv6_reachs;
-       struct list *mt_ipv6_reachs;
-       struct isis_passwd auth_info;
-};
-
-/*
- * Own definitions - used to bitmask found and expected
- */
-
-#define TLVFLAG_AREA_ADDRS                (1<<0)
-#define TLVFLAG_IS_NEIGHS                 (1<<1)
-#define TLVFLAG_ES_NEIGHS                 (1<<2)
-#define TLVFLAG_PARTITION_DESIG_LEVEL2_IS (1<<3)
-#define TLVFLAG_PREFIX_NEIGHS             (1<<4)
-#define TLVFLAG_LAN_NEIGHS                (1<<5)
-#define TLVFLAG_LSP_ENTRIES               (1<<6)
-#define TLVFLAG_PADDING                   (1<<7)
-#define TLVFLAG_AUTH_INFO                 (1<<8)
-#define TLVFLAG_IPV4_INT_REACHABILITY     (1<<9)
-#define TLVFLAG_NLPID                     (1<<10)
-#define TLVFLAG_IPV4_EXT_REACHABILITY     (1<<11)
-#define TLVFLAG_IPV4_ADDR                 (1<<12)
-#define TLVFLAG_DYN_HOSTNAME              (1<<13)
-#define TLVFLAG_IPV6_ADDR                 (1<<14)
-#define TLVFLAG_IPV6_REACHABILITY         (1<<15)
-#define TLVFLAG_TE_IS_NEIGHS              (1<<16)
-#define TLVFLAG_TE_IPV4_REACHABILITY      (1<<17)
-#define TLVFLAG_3WAY_HELLO                (1<<18)
-#define TLVFLAG_TE_ROUTER_ID              (1<<19)
-#define TLVFLAG_CHECKSUM                  (1<<20)
-#define TLVFLAG_GRACEFUL_RESTART          (1<<21)
-#define TLVFLAG_MT_ROUTER_INFORMATION     (1<<22)
-
-void init_tlvs(struct tlvs *tlvs, uint32_t expected);
-void free_tlvs(struct tlvs *tlvs);
-int parse_tlvs(char *areatag, u_char *stream, int size, u_int32_t *expected,
-              u_int32_t *found, struct tlvs *tlvs, u_int32_t *auth_tlv_offset);
-int add_tlv(u_char, u_char, u_char *, struct stream *);
-void free_tlv(void *val);
-
-int tlv_add_mt_router_info(struct list *mt_router_info, struct stream *stream);
-int tlv_add_area_addrs(struct list *area_addrs, struct stream *stream);
-int tlv_add_is_neighs(struct list *is_neighs, struct stream *stream);
-unsigned int tlv_add_te_is_neighs(struct list *te_is_neighs,
-                                 struct stream *stream, void *arg);
-int tlv_add_lan_neighs(struct list *lan_neighs, struct stream *stream);
-int tlv_add_nlpid(struct nlpids *nlpids, struct stream *stream);
-int tlv_add_checksum(struct checksum *checksum, struct stream *stream);
-int tlv_add_authinfo(u_char auth_type, u_char authlen, u_char *auth_value,
-                    struct stream *stream);
-int tlv_add_ip_addrs(struct list *ip_addrs, struct stream *stream);
-int tlv_add_in_addr(struct in_addr *, struct stream *stream, u_char tag);
-int tlv_add_dynamic_hostname(struct hostname *hostname, struct stream *stream);
-int tlv_add_lsp_entries(struct list *lsps, struct stream *stream);
-int tlv_add_ipv4_int_reachs(struct list *ipv4_reachs, struct stream *stream);
-int tlv_add_ipv4_ext_reachs(struct list *ipv4_reachs, struct stream *stream);
-unsigned int tlv_add_te_ipv4_reachs(struct list *te_ipv4_reachs,
-                                   struct stream *stream, void *arg);
-int tlv_add_ipv6_addrs(struct list *ipv6_addrs, struct stream *stream);
-unsigned int tlv_add_ipv6_reachs(struct list *ipv6_reachs,
-                                struct stream *stream, void *arg);
-
-int tlv_add_padding(struct stream *stream);
-
-#endif /* _ZEBRA_ISIS_TLV_H */
diff --git a/isisd/isis_tlvs.c b/isisd/isis_tlvs.c
new file mode 100644 (file)
index 0000000..8efbcd2
--- /dev/null
@@ -0,0 +1,3090 @@
+/*
+ * IS-IS TLV Serializer/Deserializer
+ *
+ * Copyright (C) 2015,2017 Christian Franke
+ *
+ * This file is part of FRR.
+ *
+ * FRR is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * FRR is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with FRR; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+#include <zebra.h>
+
+#include "md5.h"
+#include "memory.h"
+#include "stream.h"
+#include "sbuf.h"
+
+#include "isisd/isisd.h"
+#include "isisd/isis_memory.h"
+#include "isisd/isis_tlvs.h"
+#include "isisd/isis_common.h"
+#include "isisd/isis_mt.h"
+#include "isisd/isis_misc.h"
+#include "isisd/isis_adjacency.h"
+#include "isisd/isis_circuit.h"
+#include "isisd/isis_pdu.h"
+#include "isisd/isis_lsp.h"
+#include "isisd/isis_te.h"
+
+DEFINE_MTYPE_STATIC(ISISD, ISIS_TLV, "ISIS TLVs")
+DEFINE_MTYPE_STATIC(ISISD, ISIS_SUBTLV, "ISIS Sub-TLVs")
+DEFINE_MTYPE_STATIC(ISISD, ISIS_MT_ITEM_LIST, "ISIS MT Item Lists")
+
+typedef int (*unpack_tlv_func)(enum isis_tlv_context context, uint8_t tlv_type,
+                              uint8_t tlv_len, struct stream *s,
+                              struct sbuf *log, void *dest, int indent);
+typedef int (*pack_item_func)(struct isis_item *item, struct stream *s);
+typedef void (*free_item_func)(struct isis_item *i);
+typedef int (*unpack_item_func)(uint16_t mtid, uint8_t len, struct stream *s,
+                               struct sbuf *log, void *dest, int indent);
+typedef void (*format_item_func)(uint16_t mtid, struct isis_item *i,
+                                struct sbuf *buf, int indent);
+typedef struct isis_item *(*copy_item_func)(struct isis_item *i);
+
+struct tlv_ops {
+       const char *name;
+       unpack_tlv_func unpack;
+
+       pack_item_func pack_item;
+       free_item_func free_item;
+       unpack_item_func unpack_item;
+       format_item_func format_item;
+       copy_item_func copy_item;
+};
+
+enum how_to_pack {
+       ISIS_ITEMS,
+       ISIS_MT_ITEMS,
+};
+
+struct pack_order_entry {
+       enum isis_tlv_context context;
+       enum isis_tlv_type type;
+       enum how_to_pack how_to_pack;
+       size_t what_to_pack;
+};
+#define PACK_ENTRY(t, h, w)                                                    \
+       {                                                                      \
+               .context = ISIS_CONTEXT_LSP, .type = ISIS_TLV_##t,             \
+               .how_to_pack = (h),                                            \
+               .what_to_pack = offsetof(struct isis_tlvs, w),                 \
+       }
+
+static struct pack_order_entry pack_order[] = {
+       PACK_ENTRY(OLDSTYLE_REACH, ISIS_ITEMS, oldstyle_reach),
+       PACK_ENTRY(LAN_NEIGHBORS, ISIS_ITEMS, lan_neighbor),
+       PACK_ENTRY(LSP_ENTRY, ISIS_ITEMS, lsp_entries),
+       PACK_ENTRY(EXTENDED_REACH, ISIS_ITEMS, extended_reach),
+       PACK_ENTRY(MT_REACH, ISIS_MT_ITEMS, mt_reach),
+       PACK_ENTRY(OLDSTYLE_IP_REACH, ISIS_ITEMS, oldstyle_ip_reach),
+       PACK_ENTRY(OLDSTYLE_IP_REACH_EXT, ISIS_ITEMS, oldstyle_ip_reach_ext),
+       PACK_ENTRY(IPV4_ADDRESS, ISIS_ITEMS, ipv4_address),
+       PACK_ENTRY(IPV6_ADDRESS, ISIS_ITEMS, ipv6_address),
+       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)};
+
+/* This is a forward definition. The table is actually initialized
+ * in at the bottom. */
+static const struct tlv_ops *tlv_table[ISIS_CONTEXT_MAX][ISIS_TLV_MAX];
+
+/* End of _ops forward definition. */
+
+/* Prototypes */
+static void append_item(struct isis_item_list *dest, struct isis_item *item);
+
+/* Functions for Sub-TVL ??? IPv6 Source Prefix */
+
+static struct prefix_ipv6 *copy_subtlv_ipv6_source_prefix(struct prefix_ipv6 *p)
+{
+       if (!p)
+               return NULL;
+
+       struct prefix_ipv6 *rv = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(*rv));
+       rv->family = p->family;
+       rv->prefixlen = p->prefixlen;
+       memcpy(&rv->prefix, &p->prefix, sizeof(rv->prefix));
+       return rv;
+}
+
+static void format_subtlv_ipv6_source_prefix(struct prefix_ipv6 *p,
+                                            struct sbuf *buf, int indent)
+{
+       if (!p)
+               return;
+
+       char prefixbuf[PREFIX2STR_BUFFER];
+       sbuf_push(buf, indent, "IPv6 Source Prefix: %s\n",
+                 prefix2str(p, prefixbuf, sizeof(prefixbuf)));
+}
+
+static int pack_subtlv_ipv6_source_prefix(struct prefix_ipv6 *p,
+                                         struct stream *s)
+{
+       if (!p)
+               return 0;
+
+       if (STREAM_WRITEABLE(s) < 3 + (unsigned)PSIZE(p->prefixlen))
+               return 1;
+
+       stream_putc(s, ISIS_SUBTLV_IPV6_SOURCE_PREFIX);
+       stream_putc(s, 1 + PSIZE(p->prefixlen));
+       stream_putc(s, p->prefixlen);
+       stream_put(s, &p->prefix, PSIZE(p->prefixlen));
+       return 0;
+}
+
+static int unpack_subtlv_ipv6_source_prefix(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_subtlvs *subtlvs = dest;
+       struct prefix_ipv6 p = {
+               .family = AF_INET6,
+       };
+
+       sbuf_push(log, indent, "Unpacking IPv6 Source Prefix Sub-TLV...\n");
+
+       if (tlv_len < 1) {
+               sbuf_push(log, indent,
+                         "Not enough data left. (expected 1 or more bytes, got %" PRIu8 ")\n",
+                         tlv_len);
+               return 1;
+       }
+
+       p.prefixlen = stream_getc(s);
+       if (p.prefixlen > 128) {
+               sbuf_push(log, indent, "Prefixlen %u is inplausible for IPv6\n",
+                         p.prefixlen);
+               return 1;
+       }
+
+       if (tlv_len != 1 + PSIZE(p.prefixlen)) {
+               sbuf_push(
+                       log, indent,
+                       "TLV size differs from expected size for the prefixlen. "
+                       "(expected %u but got %" PRIu8 ")\n",
+                       1 + PSIZE(p.prefixlen), tlv_len);
+               return 1;
+       }
+
+       stream_get(&p.prefix, s, PSIZE(p.prefixlen));
+
+       if (subtlvs->source_prefix) {
+               sbuf_push(
+                       log, indent,
+                       "WARNING: source prefix Sub-TLV present multiple times.\n");
+               /* Ignore all but first occurrence of the source prefix Sub-TLV
+                */
+               return 0;
+       }
+
+       subtlvs->source_prefix = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(p));
+       memcpy(subtlvs->source_prefix, &p, sizeof(p));
+       return 0;
+}
+
+/* Functions related to subtlvs */
+
+static struct isis_subtlvs *isis_alloc_subtlvs(void)
+{
+       struct isis_subtlvs *result;
+
+       result = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(*result));
+
+       return result;
+}
+
+static struct isis_subtlvs *copy_subtlvs(struct isis_subtlvs *subtlvs)
+{
+       if (!subtlvs)
+               return NULL;
+
+       struct isis_subtlvs *rv = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(*rv));
+
+       rv->source_prefix =
+               copy_subtlv_ipv6_source_prefix(subtlvs->source_prefix);
+       return rv;
+}
+
+static void format_subtlvs(struct isis_subtlvs *subtlvs, struct sbuf *buf,
+                          int indent)
+{
+       format_subtlv_ipv6_source_prefix(subtlvs->source_prefix, buf, indent);
+}
+
+static void isis_free_subtlvs(struct isis_subtlvs *subtlvs)
+{
+       if (!subtlvs)
+               return;
+
+       XFREE(MTYPE_ISIS_SUBTLV, subtlvs->source_prefix);
+
+       XFREE(MTYPE_ISIS_SUBTLV, subtlvs);
+}
+
+static int pack_subtlvs(struct isis_subtlvs *subtlvs, struct stream *s)
+{
+       int rv;
+       size_t subtlv_len_pos = stream_get_endp(s);
+
+       if (STREAM_WRITEABLE(s) < 1)
+               return 1;
+
+       stream_putc(s, 0); /* Put 0 as subtlvs length, filled in later */
+
+       rv = pack_subtlv_ipv6_source_prefix(subtlvs->source_prefix, s);
+       if (rv)
+               return rv;
+
+       size_t subtlv_len = stream_get_endp(s) - subtlv_len_pos - 1;
+       if (subtlv_len > 255)
+               return 1;
+
+       stream_putc_at(s, subtlv_len_pos, subtlv_len);
+       return 0;
+}
+
+static int unpack_tlvs(enum isis_tlv_context context, size_t avail_len,
+                      struct stream *stream, struct sbuf *log, void *dest,
+                      int indent);
+
+/* Functions related to TLVs 1 Area Addresses */
+
+static struct isis_item *copy_item_area_address(struct isis_item *i)
+{
+       struct isis_area_address *addr = (struct isis_area_address *)i;
+       struct isis_area_address *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
+
+       rv->len = addr->len;
+       memcpy(rv->addr, addr->addr, addr->len);
+       return (struct isis_item *)rv;
+}
+
+static void format_item_area_address(uint16_t mtid, struct isis_item *i,
+                                    struct sbuf *buf, int indent)
+{
+       struct isis_area_address *addr = (struct isis_area_address *)i;
+
+       sbuf_push(buf, indent, "Area Address: %s\n",
+                 isonet_print(addr->addr, addr->len));
+}
+
+static void free_item_area_address(struct isis_item *i)
+{
+       XFREE(MTYPE_ISIS_TLV, i);
+}
+
+static int pack_item_area_address(struct isis_item *i, struct stream *s)
+{
+       struct isis_area_address *addr = (struct isis_area_address *)i;
+
+       if (STREAM_WRITEABLE(s) < (unsigned)1 + addr->len)
+               return 1;
+       stream_putc(s, addr->len);
+       stream_put(s, addr->addr, addr->len);
+       return 0;
+}
+
+static int unpack_item_area_address(uint16_t mtid, uint8_t len,
+                                   struct stream *s, struct sbuf *log,
+                                   void *dest, int indent)
+{
+       struct isis_tlvs *tlvs = dest;
+       struct isis_area_address *rv = NULL;
+
+       sbuf_push(log, indent, "Unpack area address...\n");
+       if (len < 1) {
+               sbuf_push(
+                       log, indent,
+                       "Not enough data left. (Expected 1 byte of address length, got %" PRIu8
+                       ")\n",
+                       len);
+               goto out;
+       }
+
+       rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
+       rv->len = stream_getc(s);
+
+       if (len < 1 + rv->len) {
+               sbuf_push(log, indent, "Not enough data left. (Expected %" PRIu8
+                                      " bytes of address, got %" PRIu8 ")\n",
+                         rv->len, len - 1);
+               goto out;
+       }
+
+       if (rv->len < 1 || rv->len > 20) {
+               sbuf_push(log, indent,
+                         "Implausible area address length %" PRIu8 "\n",
+                         rv->len);
+               goto out;
+       }
+
+       stream_get(rv->addr, s, rv->len);
+
+       format_item_area_address(ISIS_MT_IPV4_UNICAST, (struct isis_item *)rv,
+                                log, indent + 2);
+       append_item(&tlvs->area_addresses, (struct isis_item *)rv);
+       return 0;
+out:
+       XFREE(MTYPE_ISIS_TLV, rv);
+       return 1;
+}
+
+/* Functions related to TLV 2 (Old-Style) IS Reach */
+static struct isis_item *copy_item_oldstyle_reach(struct isis_item *i)
+{
+       struct isis_oldstyle_reach *r = (struct isis_oldstyle_reach *)i;
+       struct isis_oldstyle_reach *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
+
+       memcpy(rv->id, r->id, 7);
+       rv->metric = r->metric;
+       return (struct isis_item *)rv;
+}
+
+static void format_item_oldstyle_reach(uint16_t mtid, struct isis_item *i,
+                                      struct sbuf *buf, int indent)
+{
+       struct isis_oldstyle_reach *r = (struct isis_oldstyle_reach *)i;
+
+       sbuf_push(buf, indent, "IS Reachability: %s (Metric: %" PRIu8 ")\n",
+                 isis_format_id(r->id, 7), r->metric);
+}
+
+static void free_item_oldstyle_reach(struct isis_item *i)
+{
+       XFREE(MTYPE_ISIS_TLV, i);
+}
+
+static int pack_item_oldstyle_reach(struct isis_item *i, struct stream *s)
+{
+       struct isis_oldstyle_reach *r = (struct isis_oldstyle_reach *)i;
+
+       if (STREAM_WRITEABLE(s) < 11)
+               return 1;
+
+       stream_putc(s, r->metric);
+       stream_putc(s, 0x80); /* delay metric - unsupported */
+       stream_putc(s, 0x80); /* expense metric - unsupported */
+       stream_putc(s, 0x80); /* error metric - unsupported */
+       stream_put(s, r->id, 7);
+
+       return 0;
+}
+
+static int unpack_item_oldstyle_reach(uint16_t mtid, uint8_t len,
+                                     struct stream *s, struct sbuf *log,
+                                     void *dest, int indent)
+{
+       struct isis_tlvs *tlvs = dest;
+
+       sbuf_push(log, indent, "Unpack oldstyle reach...\n");
+       if (len < 11) {
+               sbuf_push(
+                       log, indent,
+                       "Not enough data left.(Expected 11 bytes of reach information, got %" PRIu8
+                       ")\n",
+                       len);
+               return 1;
+       }
+
+       struct isis_oldstyle_reach *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
+       rv->metric = stream_getc(s);
+       if ((rv->metric & 0x3f) != rv->metric) {
+               sbuf_push(log, indent, "Metric has unplausible format\n");
+               rv->metric &= 0x3f;
+       }
+       stream_forward_getp(s, 3); /* Skip other metrics */
+       stream_get(rv->id, s, 7);
+
+       format_item_oldstyle_reach(mtid, (struct isis_item *)rv, log,
+                                  indent + 2);
+       append_item(&tlvs->oldstyle_reach, (struct isis_item *)rv);
+       return 0;
+}
+
+/* Functions related to TLV 6 LAN Neighbors */
+static struct isis_item *copy_item_lan_neighbor(struct isis_item *i)
+{
+       struct isis_lan_neighbor *n = (struct isis_lan_neighbor *)i;
+       struct isis_lan_neighbor *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
+
+       memcpy(rv->mac, n->mac, 6);
+       return (struct isis_item *)rv;
+}
+
+static void format_item_lan_neighbor(uint16_t mtid, struct isis_item *i,
+                                    struct sbuf *buf, int indent)
+{
+       struct isis_lan_neighbor *n = (struct isis_lan_neighbor *)i;
+
+       sbuf_push(buf, indent, "LAN Neighbor: %s\n", isis_format_id(n->mac, 6));
+}
+
+static void free_item_lan_neighbor(struct isis_item *i)
+{
+       XFREE(MTYPE_ISIS_TLV, i);
+}
+
+static int pack_item_lan_neighbor(struct isis_item *i, struct stream *s)
+{
+       struct isis_lan_neighbor *n = (struct isis_lan_neighbor *)i;
+
+       if (STREAM_WRITEABLE(s) < 6)
+               return 1;
+
+       stream_put(s, n->mac, 6);
+
+       return 0;
+}
+
+static int unpack_item_lan_neighbor(uint16_t mtid, uint8_t len,
+                                   struct stream *s, struct sbuf *log,
+                                   void *dest, int indent)
+{
+       struct isis_tlvs *tlvs = dest;
+
+       sbuf_push(log, indent, "Unpack LAN neighbor...\n");
+       if (len < 6) {
+               sbuf_push(
+                       log, indent,
+                       "Not enough data left.(Expected 6 bytes of mac, got %" PRIu8
+                       ")\n",
+                       len);
+               return 1;
+       }
+
+       struct isis_lan_neighbor *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
+       stream_get(rv->mac, s, 6);
+
+       format_item_lan_neighbor(mtid, (struct isis_item *)rv, log, indent + 2);
+       append_item(&tlvs->lan_neighbor, (struct isis_item *)rv);
+       return 0;
+}
+
+/* Functions related to TLV 9 LSP Entry */
+static struct isis_item *copy_item_lsp_entry(struct isis_item *i)
+{
+       struct isis_lsp_entry *e = (struct isis_lsp_entry *)i;
+       struct isis_lsp_entry *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
+
+       rv->rem_lifetime = e->rem_lifetime;
+       memcpy(rv->id, e->id, sizeof(rv->id));
+       rv->seqno = e->seqno;
+       rv->checksum = e->checksum;
+
+       return (struct isis_item *)rv;
+}
+
+static void format_item_lsp_entry(uint16_t mtid, struct isis_item *i,
+                                 struct sbuf *buf, int indent)
+{
+       struct isis_lsp_entry *e = (struct isis_lsp_entry *)i;
+
+       sbuf_push(buf, indent, "LSP Entry: %s, seq 0x%08" PRIx32
+                 ", cksum 0x%04" PRIx16 ", lifetime %" PRIu16 "s\n",
+                 isis_format_id(e->id, 8), e->seqno, e->checksum,
+                 e->rem_lifetime);
+}
+
+static void free_item_lsp_entry(struct isis_item *i)
+{
+       XFREE(MTYPE_ISIS_TLV, i);
+}
+
+static int pack_item_lsp_entry(struct isis_item *i, struct stream *s)
+{
+       struct isis_lsp_entry *e = (struct isis_lsp_entry *)i;
+
+       if (STREAM_WRITEABLE(s) < 16)
+               return 1;
+
+       stream_putw(s, e->rem_lifetime);
+       stream_put(s, e->id, 8);
+       stream_putl(s, e->seqno);
+       stream_putw(s, e->checksum);
+
+       return 0;
+}
+
+static int unpack_item_lsp_entry(uint16_t mtid, uint8_t len, struct stream *s,
+                                struct sbuf *log, void *dest, int indent)
+{
+       struct isis_tlvs *tlvs = dest;
+
+       sbuf_push(log, indent, "Unpack LSP entry...\n");
+       if (len < 16) {
+               sbuf_push(
+                       log, indent,
+                       "Not enough data left. (Expected 16 bytes of LSP info, got %" PRIu8,
+                       len);
+               return 1;
+       }
+
+       struct isis_lsp_entry *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
+       rv->rem_lifetime = stream_getw(s);
+       stream_get(rv->id, s, 8);
+       rv->seqno = stream_getl(s);
+       rv->checksum = stream_getw(s);
+
+       format_item_lsp_entry(mtid, (struct isis_item *)rv, log, indent + 2);
+       append_item(&tlvs->lsp_entries, (struct isis_item *)rv);
+       return 0;
+}
+
+/* Functions related to TLVs 22/222 Extended Reach/MT Reach */
+
+static struct isis_item *copy_item_extended_reach(struct isis_item *i)
+{
+       struct isis_extended_reach *r = (struct isis_extended_reach *)i;
+       struct isis_extended_reach *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
+
+       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;
+       }
+
+       return (struct isis_item *)rv;
+}
+
+static void format_item_extended_reach(uint16_t mtid, struct isis_item *i,
+                                      struct sbuf *buf, int indent)
+{
+       struct isis_extended_reach *r = (struct isis_extended_reach *)i;
+
+       sbuf_push(buf, indent, "%s Reachability: %s (Metric: %u)",
+                 (mtid == ISIS_MT_IPV4_UNICAST) ? "Extended" : "MT",
+                 isis_format_id(r->id, 7), r->metric);
+       if (mtid != ISIS_MT_IPV4_UNICAST)
+               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);
+}
+
+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);
+       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;
+
+       if (STREAM_WRITEABLE(s) < 11 + (unsigned)r->subtlv_len)
+               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);
+       return 0;
+}
+
+static int unpack_item_extended_reach(uint16_t mtid, uint8_t len,
+                                     struct stream *s, struct sbuf *log,
+                                     void *dest, int indent)
+{
+       struct isis_tlvs *tlvs = dest;
+       struct isis_extended_reach *rv = NULL;
+       uint8_t subtlv_len;
+       struct isis_item_list *items;
+
+       if (mtid == ISIS_MT_IPV4_UNICAST) {
+               items = &tlvs->extended_reach;
+       } else {
+               items = isis_get_mt_items(&tlvs->mt_reach, mtid);
+       }
+
+       sbuf_push(log, indent, "Unpacking %s reachability...\n",
+                 (mtid == ISIS_MT_IPV4_UNICAST) ? "extended" : "mt");
+
+       if (len < 11) {
+               sbuf_push(log, indent,
+                         "Not enough data left. (expected 11 or more bytes, got %"
+                         PRIu8 ")\n",
+                         len);
+               goto out;
+       }
+
+       rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
+       stream_get(rv->id, s, 7);
+       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
+                         ", there are only %" PRIu8 " bytes left.\n",
+                         subtlv_len, len - 11);
+               goto out;
+       }
+
+       sbuf_push(log, indent, "Storing %" PRIu8 " bytes of subtlvs\n",
+                 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)) {
+                       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;
+       }
+
+       append_item(items, (struct isis_item *)rv);
+       return 0;
+out:
+       if (rv)
+               free_item_extended_reach((struct isis_item *)rv);
+
+       return 1;
+}
+
+/* Functions related to TLV 128 (Old-Style) IP Reach */
+static struct isis_item *copy_item_oldstyle_ip_reach(struct isis_item *i)
+{
+       struct isis_oldstyle_ip_reach *r = (struct isis_oldstyle_ip_reach *)i;
+       struct isis_oldstyle_ip_reach *rv =
+               XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
+
+       rv->metric = r->metric;
+       rv->prefix = r->prefix;
+       return (struct isis_item *)rv;
+}
+
+static void format_item_oldstyle_ip_reach(uint16_t mtid, struct isis_item *i,
+                                         struct sbuf *buf, int indent)
+{
+       struct isis_oldstyle_ip_reach *r = (struct isis_oldstyle_ip_reach *)i;
+       char prefixbuf[PREFIX2STR_BUFFER];
+
+       sbuf_push(buf, indent, "IP Reachability: %s (Metric: %" PRIu8 ")\n",
+                 prefix2str(&r->prefix, prefixbuf, sizeof(prefixbuf)), r->metric);
+}
+
+static void free_item_oldstyle_ip_reach(struct isis_item *i)
+{
+       XFREE(MTYPE_ISIS_TLV, i);
+}
+
+static int pack_item_oldstyle_ip_reach(struct isis_item *i, struct stream *s)
+{
+       struct isis_oldstyle_ip_reach *r = (struct isis_oldstyle_ip_reach *)i;
+
+       if (STREAM_WRITEABLE(s) < 12)
+               return 1;
+
+       stream_putc(s, r->metric);
+       stream_putc(s, 0x80); /* delay metric - unsupported */
+       stream_putc(s, 0x80); /* expense metric - unsupported */
+       stream_putc(s, 0x80); /* error metric - unsupported */
+       stream_put(s, &r->prefix.prefix, 4);
+
+       struct in_addr mask;
+       masklen2ip(r->prefix.prefixlen, &mask);
+       stream_put(s, &mask, sizeof(mask));
+
+       return 0;
+}
+
+static int unpack_item_oldstyle_ip_reach(uint16_t mtid, uint8_t len,
+                                        struct stream *s, struct sbuf *log,
+                                        void *dest, int indent)
+{
+       sbuf_push(log, indent, "Unpack oldstyle ip reach...\n");
+       if (len < 12) {
+               sbuf_push(
+                       log, indent,
+                       "Not enough data left.(Expected 12 bytes of reach information, got %" PRIu8
+                       ")\n",
+                       len);
+               return 1;
+       }
+
+       struct isis_oldstyle_ip_reach *rv =
+               XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
+       rv->metric = stream_getc(s);
+       if ((rv->metric & 0x7f) != rv->metric) {
+               sbuf_push(log, indent, "Metric has unplausible format\n");
+               rv->metric &= 0x7f;
+       }
+       stream_forward_getp(s, 3); /* Skip other metrics */
+       rv->prefix.family = AF_INET;
+       stream_get(&rv->prefix.prefix, s, 4);
+
+       struct in_addr mask;
+       stream_get(&mask, s, 4);
+       rv->prefix.prefixlen = ip_masklen(mask);
+
+       format_item_oldstyle_ip_reach(mtid, (struct isis_item *)rv, log,
+                                     indent + 2);
+       append_item(dest, (struct isis_item *)rv);
+       return 0;
+}
+
+
+/* Functions related to TLV 129 protocols supported */
+
+static void copy_tlv_protocols_supported(struct isis_protocols_supported *src,
+                                        struct isis_protocols_supported *dest)
+{
+       if (!src->protocols || !src->count)
+               return;
+       dest->count = src->count;
+       dest->protocols = XCALLOC(MTYPE_ISIS_TLV, src->count);
+       memcpy(dest->protocols, src->protocols, src->count);
+}
+
+static void format_tlv_protocols_supported(struct isis_protocols_supported *p,
+                                          struct sbuf *buf, int indent)
+{
+       if (!p || !p->count || !p->protocols)
+               return;
+
+       sbuf_push(buf, indent, "Protocols Supported: ");
+       for (uint8_t i = 0; i < p->count; i++) {
+               sbuf_push(buf, 0, "%s%s", nlpid2str(p->protocols[i]),
+                         (i + 1 < p->count) ? ", " : "");
+       }
+       sbuf_push(buf, 0, "\n");
+}
+
+static void free_tlv_protocols_supported(struct isis_protocols_supported *p)
+{
+       XFREE(MTYPE_ISIS_TLV, p->protocols);
+}
+
+static int pack_tlv_protocols_supported(struct isis_protocols_supported *p,
+                                       struct stream *s)
+{
+       if (!p || !p->count || !p->protocols)
+               return 0;
+
+       if (STREAM_WRITEABLE(s) < (unsigned)(p->count + 2))
+               return 1;
+
+       stream_putc(s, ISIS_TLV_PROTOCOLS_SUPPORTED);
+       stream_putc(s, p->count);
+       stream_put(s, p->protocols, p->count);
+       return 0;
+}
+
+static int unpack_tlv_protocols_supported(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;
+
+       sbuf_push(log, indent, "Unpacking Protocols Supported TLV...\n");
+       if (!tlv_len) {
+               sbuf_push(log, indent, "WARNING: No protocols included\n");
+               return 0;
+       }
+       if (tlvs->protocols_supported.protocols) {
+               sbuf_push(
+                       log, indent,
+                       "WARNING: protocols supported TLV present multiple times.\n");
+               stream_forward_getp(s, tlv_len);
+               return 0;
+       }
+
+       tlvs->protocols_supported.count = tlv_len;
+       tlvs->protocols_supported.protocols = XCALLOC(MTYPE_ISIS_TLV, tlv_len);
+       stream_get(tlvs->protocols_supported.protocols, s, tlv_len);
+
+       format_tlv_protocols_supported(&tlvs->protocols_supported, log,
+                                      indent + 2);
+       return 0;
+}
+
+/* Functions related to TLV 132 IPv4 Interface addresses */
+static struct isis_item *copy_item_ipv4_address(struct isis_item *i)
+{
+       struct isis_ipv4_address *a = (struct isis_ipv4_address *)i;
+       struct isis_ipv4_address *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
+
+       rv->addr = a->addr;
+       return (struct isis_item *)rv;
+}
+
+static void format_item_ipv4_address(uint16_t mtid, struct isis_item *i,
+                                    struct sbuf *buf, int indent)
+{
+       struct isis_ipv4_address *a = (struct isis_ipv4_address *)i;
+       char addrbuf[INET_ADDRSTRLEN];
+
+       inet_ntop(AF_INET, &a->addr, addrbuf, sizeof(addrbuf));
+       sbuf_push(buf, indent, "IPv4 Interface Address: %s\n", addrbuf);
+}
+
+static void free_item_ipv4_address(struct isis_item *i)
+{
+       XFREE(MTYPE_ISIS_TLV, i);
+}
+
+static int pack_item_ipv4_address(struct isis_item *i, struct stream *s)
+{
+       struct isis_ipv4_address *a = (struct isis_ipv4_address *)i;
+
+       if (STREAM_WRITEABLE(s) < 4)
+               return 1;
+
+       stream_put(s, &a->addr, 4);
+
+       return 0;
+}
+
+static int unpack_item_ipv4_address(uint16_t mtid, uint8_t len,
+                                   struct stream *s, struct sbuf *log,
+                                   void *dest, int indent)
+{
+       struct isis_tlvs *tlvs = dest;
+
+       sbuf_push(log, indent, "Unpack IPv4 Interface address...\n");
+       if (len < 4) {
+               sbuf_push(
+                       log, indent,
+                       "Not enough data left.(Expected 4 bytes of IPv4 address, got %" PRIu8
+                       ")\n",
+                       len);
+               return 1;
+       }
+
+       struct isis_ipv4_address *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
+       stream_get(&rv->addr, s, 4);
+
+       format_item_ipv4_address(mtid, (struct isis_item *)rv, log, indent + 2);
+       append_item(&tlvs->ipv4_address, (struct isis_item *)rv);
+       return 0;
+}
+
+
+/* Functions related to TLV 232 IPv6 Interface addresses */
+static struct isis_item *copy_item_ipv6_address(struct isis_item *i)
+{
+       struct isis_ipv6_address *a = (struct isis_ipv6_address *)i;
+       struct isis_ipv6_address *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
+
+       rv->addr = a->addr;
+       return (struct isis_item *)rv;
+}
+
+static void format_item_ipv6_address(uint16_t mtid, struct isis_item *i,
+                                    struct sbuf *buf, int indent)
+{
+       struct isis_ipv6_address *a = (struct isis_ipv6_address *)i;
+       char addrbuf[INET6_ADDRSTRLEN];
+
+       inet_ntop(AF_INET6, &a->addr, addrbuf, sizeof(addrbuf));
+       sbuf_push(buf, indent, "IPv6 Interface Address: %s\n", addrbuf);
+}
+
+static void free_item_ipv6_address(struct isis_item *i)
+{
+       XFREE(MTYPE_ISIS_TLV, i);
+}
+
+static int pack_item_ipv6_address(struct isis_item *i, struct stream *s)
+{
+       struct isis_ipv6_address *a = (struct isis_ipv6_address *)i;
+
+       if (STREAM_WRITEABLE(s) < 16)
+               return 1;
+
+       stream_put(s, &a->addr, 16);
+
+       return 0;
+}
+
+static int unpack_item_ipv6_address(uint16_t mtid, uint8_t len,
+                                   struct stream *s, struct sbuf *log,
+                                   void *dest, int indent)
+{
+       struct isis_tlvs *tlvs = dest;
+
+       sbuf_push(log, indent, "Unpack IPv6 Interface address...\n");
+       if (len < 16) {
+               sbuf_push(
+                       log, indent,
+                       "Not enough data left.(Expected 16 bytes of IPv6 address, got %" PRIu8
+                       ")\n",
+                       len);
+               return 1;
+       }
+
+       struct isis_ipv6_address *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
+       stream_get(&rv->addr, s, 16);
+
+       format_item_ipv6_address(mtid, (struct isis_item *)rv, log, indent + 2);
+       append_item(&tlvs->ipv6_address, (struct isis_item *)rv);
+       return 0;
+}
+
+
+/* Functions related to TLV 229 MT Router information */
+static struct isis_item *copy_item_mt_router_info(struct isis_item *i)
+{
+       struct isis_mt_router_info *info = (struct isis_mt_router_info *)i;
+       struct isis_mt_router_info *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
+
+       rv->overload = info->overload;
+       rv->attached = info->attached;
+       rv->mtid = info->mtid;
+       return (struct isis_item *)rv;
+}
+
+static void format_item_mt_router_info(uint16_t mtid, struct isis_item *i,
+                                      struct sbuf *buf, int indent)
+{
+       struct isis_mt_router_info *info = (struct isis_mt_router_info *)i;
+
+       sbuf_push(buf, indent, "MT Router Info: %s%s%s\n",
+                 isis_mtid2str(info->mtid),
+                 info->overload ? " Overload" : "",
+                 info->attached ? " Attached" : "");
+}
+
+static void free_item_mt_router_info(struct isis_item *i)
+{
+       XFREE(MTYPE_ISIS_TLV, i);
+}
+
+static int pack_item_mt_router_info(struct isis_item *i, struct stream *s)
+{
+       struct isis_mt_router_info *info = (struct isis_mt_router_info *)i;
+
+       if (STREAM_WRITEABLE(s) < 2)
+               return 1;
+
+       uint16_t entry = info->mtid;
+
+       if (info->overload)
+               entry |= ISIS_MT_OL_MASK;
+       if (info->attached)
+               entry |= ISIS_MT_AT_MASK;
+
+       stream_putw(s, entry);
+
+       return 0;
+}
+
+static int unpack_item_mt_router_info(uint16_t mtid, uint8_t len,
+                                     struct stream *s, struct sbuf *log,
+                                     void *dest, int indent)
+{
+       struct isis_tlvs *tlvs = dest;
+
+       sbuf_push(log, indent, "Unpack MT Router info...\n");
+       if (len < 2) {
+               sbuf_push(
+                       log, indent,
+                       "Not enough data left.(Expected 2 bytes of MT info, got %" PRIu8
+                       ")\n",
+                       len);
+               return 1;
+       }
+
+       struct isis_mt_router_info *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
+
+       uint16_t entry = stream_getw(s);
+       rv->overload = entry & ISIS_MT_OL_MASK;
+       rv->attached = entry & ISIS_MT_AT_MASK;
+       rv->mtid = entry & ISIS_MT_MASK;
+
+       format_item_mt_router_info(mtid, (struct isis_item *)rv, log,
+                                  indent + 2);
+       append_item(&tlvs->mt_router_info, (struct isis_item *)rv);
+       return 0;
+}
+
+/* Functions related to TLV 134 TE Router ID */
+
+static struct in_addr *copy_tlv_te_router_id(const struct in_addr *id)
+{
+       if (!id)
+               return NULL;
+
+       struct in_addr *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
+       memcpy(rv, id, sizeof(*rv));
+       return rv;
+}
+
+static void format_tlv_te_router_id(const struct in_addr *id, struct sbuf *buf,
+                                   int indent)
+{
+       if (!id)
+               return;
+
+       char addrbuf[INET_ADDRSTRLEN];
+       inet_ntop(AF_INET, id, addrbuf, sizeof(addrbuf));
+       sbuf_push(buf, indent, "TE Router ID: %s\n", addrbuf);
+}
+
+static void free_tlv_te_router_id(struct in_addr *id)
+{
+       XFREE(MTYPE_ISIS_TLV, id);
+}
+
+static int pack_tlv_te_router_id(const struct in_addr *id, struct stream *s)
+{
+       if (!id)
+               return 0;
+
+       if (STREAM_WRITEABLE(s) < (unsigned)(2 + sizeof(*id)))
+               return 1;
+
+       stream_putc(s, ISIS_TLV_TE_ROUTER_ID);
+       stream_putc(s, 4);
+       stream_put(s, id, 4);
+       return 0;
+}
+
+static int unpack_tlv_te_router_id(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;
+
+       sbuf_push(log, indent, "Unpacking TE Router ID TLV...\n");
+       if (tlv_len != 4) {
+               sbuf_push(log, indent, "WARNING: Length invalid\n");
+               return 1;
+       }
+
+       if (tlvs->te_router_id) {
+               sbuf_push(log, indent,
+                         "WARNING: TE Router ID present multiple times.\n");
+               stream_forward_getp(s, tlv_len);
+               return 0;
+       }
+
+       tlvs->te_router_id = XCALLOC(MTYPE_ISIS_TLV, 4);
+       stream_get(tlvs->te_router_id, s, 4);
+       format_tlv_te_router_id(tlvs->te_router_id, log, indent + 2);
+       return 0;
+}
+
+
+/* Functions related to TLVs 135/235 extended IP reach/MT IP Reach */
+
+static struct isis_item *copy_item_extended_ip_reach(struct isis_item *i)
+{
+       struct isis_extended_ip_reach *r = (struct isis_extended_ip_reach *)i;
+       struct isis_extended_ip_reach *rv =
+               XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
+
+       rv->metric = r->metric;
+       rv->down = r->down;
+       rv->prefix = r->prefix;
+
+       return (struct isis_item *)rv;
+}
+
+static void format_item_extended_ip_reach(uint16_t mtid, struct isis_item *i,
+                                         struct sbuf *buf, int indent)
+{
+       struct isis_extended_ip_reach *r = (struct isis_extended_ip_reach *)i;
+       char prefixbuf[PREFIX2STR_BUFFER];
+
+       sbuf_push(buf, indent, "%s IP Reachability: %s (Metric: %u)%s",
+                 (mtid == ISIS_MT_IPV4_UNICAST) ? "Extended" : "MT",
+                 prefix2str(&r->prefix, prefixbuf, sizeof(prefixbuf)), r->metric,
+                 r->down ? " Down" : "");
+       if (mtid != ISIS_MT_IPV4_UNICAST)
+               sbuf_push(buf, 0, " %s", isis_mtid2str(mtid));
+       sbuf_push(buf, 0, "\n");
+}
+
+static void free_item_extended_ip_reach(struct isis_item *i)
+{
+       struct isis_extended_ip_reach *item =
+               (struct isis_extended_ip_reach *)i;
+       XFREE(MTYPE_ISIS_TLV, item);
+}
+
+static int pack_item_extended_ip_reach(struct isis_item *i, struct stream *s)
+{
+       struct isis_extended_ip_reach *r = (struct isis_extended_ip_reach *)i;
+       uint8_t control;
+
+       if (STREAM_WRITEABLE(s) < 5)
+               return 1;
+       stream_putl(s, r->metric);
+
+       control = r->down ? ISIS_EXTENDED_IP_REACH_DOWN : 0;
+       control |= r->prefix.prefixlen;
+       stream_putc(s, control);
+
+       if (STREAM_WRITEABLE(s) < (unsigned)PSIZE(r->prefix.prefixlen))
+               return 1;
+       stream_put(s, &r->prefix.prefix.s_addr, PSIZE(r->prefix.prefixlen));
+       return 0;
+}
+
+static int unpack_item_extended_ip_reach(uint16_t mtid, uint8_t len,
+                                        struct stream *s, struct sbuf *log,
+                                        void *dest, int indent)
+{
+       struct isis_tlvs *tlvs = dest;
+       struct isis_extended_ip_reach *rv = NULL;
+       size_t consume;
+       uint8_t control, subtlv_len;
+       struct isis_item_list *items;
+
+       if (mtid == ISIS_MT_IPV4_UNICAST) {
+               items = &tlvs->extended_ip_reach;
+       } else {
+               items = isis_get_mt_items(&tlvs->mt_ip_reach, mtid);
+       }
+
+       sbuf_push(log, indent, "Unpacking %s IPv4 reachability...\n",
+                 (mtid == ISIS_MT_IPV4_UNICAST) ? "extended" : "mt");
+
+       consume = 5;
+       if (len < consume) {
+               sbuf_push(log, indent,
+                         "Not enough data left. (expected 5 or more bytes, got %" PRIu8 ")\n",
+                         len);
+               goto out;
+       }
+
+       rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
+
+       rv->metric = stream_getl(s);
+       control = stream_getc(s);
+       rv->down = (control & ISIS_EXTENDED_IP_REACH_DOWN);
+       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",
+                         rv->prefix.prefixlen);
+               goto out;
+       }
+
+       consume += PSIZE(rv->prefix.prefixlen);
+       if (len < consume) {
+               sbuf_push(log, indent,
+                         "Expected %u bytes of prefix, but only %u bytes available.\n",
+                         PSIZE(rv->prefix.prefixlen), len - 5);
+               goto out;
+       }
+       stream_get(&rv->prefix.prefix.s_addr, s, PSIZE(rv->prefix.prefixlen));
+       in_addr_t orig_prefix = rv->prefix.prefix.s_addr;
+       apply_mask_ipv4(&rv->prefix);
+       if (orig_prefix != rv->prefix.prefix.s_addr)
+               sbuf_push(log, indent + 2,
+                         "WARNING: Prefix had hostbits set.\n");
+       format_item_extended_ip_reach(mtid, (struct isis_item *)rv, log,
+                                     indent + 2);
+
+       if (control & ISIS_EXTENDED_IP_REACH_SUBTLV) {
+               consume += 1;
+               if (len < consume) {
+                       sbuf_push(log, indent,
+                                 "Expected 1 byte of subtlv len, but no more data present.\n");
+                       goto out;
+               }
+               subtlv_len = stream_getc(s);
+
+               if (!subtlv_len) {
+                       sbuf_push(log, indent + 2,
+                                 "  WARNING: subtlv bit is set, but there are no subtlvs.\n");
+               }
+               consume += subtlv_len;
+               if (len < consume) {
+                       sbuf_push(log, indent,
+                                 "Expected %" PRIu8
+                                 " bytes of subtlvs, but only %u bytes available.\n",
+                                 subtlv_len,
+                                 len - 6 - PSIZE(rv->prefix.prefixlen));
+                       goto out;
+               }
+               sbuf_push(log, indent, "Skipping %" PRIu8 " bytes of subvls",
+                         subtlv_len);
+               stream_forward_getp(s, subtlv_len);
+       }
+
+       append_item(items, (struct isis_item *)rv);
+       return 0;
+out:
+       if (rv)
+               free_item_extended_ip_reach((struct isis_item *)rv);
+       return 1;
+}
+
+/* Functions related to TLV 137 Dynamic Hostname */
+
+static char *copy_tlv_dynamic_hostname(const char *hostname)
+{
+       if (!hostname)
+               return NULL;
+
+       return XSTRDUP(MTYPE_ISIS_TLV, hostname);
+}
+
+static void format_tlv_dynamic_hostname(const char *hostname, struct sbuf *buf,
+                                       int indent)
+{
+       if (!hostname)
+               return;
+
+       sbuf_push(buf, indent, "Hostname: %s\n", hostname);
+}
+
+static void free_tlv_dynamic_hostname(char *hostname)
+{
+       XFREE(MTYPE_ISIS_TLV, hostname);
+}
+
+static int pack_tlv_dynamic_hostname(const char *hostname, struct stream *s)
+{
+       if (!hostname)
+               return 0;
+
+       uint8_t name_len = strlen(hostname);
+
+       if (STREAM_WRITEABLE(s) < (unsigned)(2 + name_len))
+               return 1;
+
+       stream_putc(s, ISIS_TLV_DYNAMIC_HOSTNAME);
+       stream_putc(s, name_len);
+       stream_put(s, hostname, name_len);
+       return 0;
+}
+
+static int unpack_tlv_dynamic_hostname(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;
+
+       sbuf_push(log, indent, "Unpacking Dynamic Hostname TLV...\n");
+       if (!tlv_len) {
+               sbuf_push(log, indent, "WARNING: No hostname included\n");
+               return 0;
+       }
+
+       if (tlvs->hostname) {
+               sbuf_push(log, indent,
+                         "WARNING: Hostname present multiple times.\n");
+               stream_forward_getp(s, tlv_len);
+               return 0;
+       }
+
+       tlvs->hostname = XCALLOC(MTYPE_ISIS_TLV, tlv_len + 1);
+       stream_get(tlvs->hostname, s, tlv_len);
+       tlvs->hostname[tlv_len] = '\0';
+
+       bool sane = true;
+       for (uint8_t i = 0; i < tlv_len; i++) {
+               if ((unsigned char)tlvs->hostname[i] > 127
+                   || !isprint(tlvs->hostname[i])) {
+                       sane = false;
+                       tlvs->hostname[i] = '?';
+               }
+       }
+       if (!sane) {
+               sbuf_push(
+                       log, indent,
+                       "WARNING: Hostname contained non-printable/non-ascii characters.\n");
+       }
+
+       return 0;
+}
+
+/* Functions related to TLVs 236/237 IPv6/MT-IPv6 reach */
+
+static struct isis_item *copy_item_ipv6_reach(struct isis_item *i)
+{
+       struct isis_ipv6_reach *r = (struct isis_ipv6_reach *)i;
+       struct isis_ipv6_reach *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
+       rv->metric = r->metric;
+       rv->down = r->down;
+       rv->external = r->external;
+       rv->prefix = r->prefix;
+       rv->subtlvs = copy_subtlvs(r->subtlvs);
+
+       return (struct isis_item *)rv;
+}
+
+static void format_item_ipv6_reach(uint16_t mtid, struct isis_item *i,
+                                  struct sbuf *buf, int indent)
+{
+       struct isis_ipv6_reach *r = (struct isis_ipv6_reach *)i;
+       char prefixbuf[PREFIX2STR_BUFFER];
+
+       sbuf_push(buf, indent, "%sIPv6 Reachability: %s (Metric: %u)%s%s",
+                 (mtid == ISIS_MT_IPV4_UNICAST) ? "" : "MT ",
+                 prefix2str(&r->prefix, prefixbuf, sizeof(prefixbuf)),
+                 r->metric,
+                 r->down ? " Down" : "",
+                 r->external ? " External" : "");
+       if (mtid != ISIS_MT_IPV4_UNICAST)
+               sbuf_push(buf, 0, " %s", isis_mtid2str(mtid));
+       sbuf_push(buf, 0, "\n");
+
+       if (r->subtlvs) {
+               sbuf_push(buf, indent, "  Subtlvs:\n");
+               format_subtlvs(r->subtlvs, buf, indent + 4);
+       }
+}
+
+static void free_item_ipv6_reach(struct isis_item *i)
+{
+       struct isis_ipv6_reach *item = (struct isis_ipv6_reach *)i;
+
+       isis_free_subtlvs(item->subtlvs);
+       XFREE(MTYPE_ISIS_TLV, item);
+}
+
+static int pack_item_ipv6_reach(struct isis_item *i, struct stream *s)
+{
+       struct isis_ipv6_reach *r = (struct isis_ipv6_reach *)i;
+       uint8_t control;
+
+       if (STREAM_WRITEABLE(s) < 6)
+               return 1;
+       stream_putl(s, r->metric);
+
+       control = r->down ? ISIS_IPV6_REACH_DOWN : 0;
+       control |= r->external ? ISIS_IPV6_REACH_EXTERNAL : 0;
+       control |= r->subtlvs ? ISIS_IPV6_REACH_SUBTLV : 0;
+
+       stream_putc(s, control);
+       stream_putc(s, r->prefix.prefixlen);
+
+       if (STREAM_WRITEABLE(s) < (unsigned)PSIZE(r->prefix.prefixlen))
+               return 1;
+       stream_put(s, &r->prefix.prefix.s6_addr, PSIZE(r->prefix.prefixlen));
+
+       if (r->subtlvs)
+               return pack_subtlvs(r->subtlvs, s);
+
+       return 0;
+}
+
+static int unpack_item_ipv6_reach(uint16_t mtid, uint8_t len, struct stream *s,
+                                 struct sbuf *log, void *dest, int indent)
+{
+       struct isis_tlvs *tlvs = dest;
+       struct isis_ipv6_reach *rv = NULL;
+       size_t consume;
+       uint8_t control, subtlv_len;
+       struct isis_item_list *items;
+
+       if (mtid == ISIS_MT_IPV4_UNICAST) {
+               items = &tlvs->ipv6_reach;
+       } else {
+               items = isis_get_mt_items(&tlvs->mt_ipv6_reach, mtid);
+       }
+
+       sbuf_push(log, indent, "Unpacking %sIPv6 reachability...\n",
+                 (mtid == ISIS_MT_IPV4_UNICAST) ? "" : "mt ");
+       consume = 6;
+       if (len < consume) {
+               sbuf_push(log, indent,
+                         "Not enough data left. (expected 6 or more bytes, got %"
+                         PRIu8 ")\n",
+                         len);
+               goto out;
+       }
+
+       rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
+
+       rv->metric = stream_getl(s);
+       control = stream_getc(s);
+       rv->down = (control & ISIS_IPV6_REACH_DOWN);
+       rv->external = (control & ISIS_IPV6_REACH_EXTERNAL);
+
+       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",
+                         rv->prefix.prefixlen);
+               goto out;
+       }
+
+       consume += PSIZE(rv->prefix.prefixlen);
+       if (len < consume) {
+               sbuf_push(log, indent,
+                         "Expected %u bytes of prefix, but only %u bytes available.\n",
+                         PSIZE(rv->prefix.prefixlen), len - 6);
+               goto out;
+       }
+       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,
+                         "WARNING: Prefix had hostbits set.\n");
+       format_item_ipv6_reach(mtid, (struct isis_item *)rv, log, indent + 2);
+
+       if (control & ISIS_IPV6_REACH_SUBTLV) {
+               consume += 1;
+               if (len < consume) {
+                       sbuf_push(log, indent,
+                                 "Expected 1 byte of subtlv len, but no more data persent.\n");
+                       goto out;
+               }
+               subtlv_len = stream_getc(s);
+
+               if (!subtlv_len) {
+                       sbuf_push(log, indent + 2,
+                                 "  WARNING: subtlv bit set, but there are no subtlvs.\n");
+               }
+               consume += subtlv_len;
+               if (len < consume) {
+                       sbuf_push(log, indent,
+                                 "Expected %" PRIu8
+                                 " bytes of subtlvs, but only %u bytes available.\n",
+                                 subtlv_len,
+                                 len - 6 - PSIZE(rv->prefix.prefixlen));
+                       goto out;
+               }
+
+               rv->subtlvs = isis_alloc_subtlvs();
+               if (unpack_tlvs(ISIS_CONTEXT_SUBTLV_IPV6_REACH, subtlv_len, s,
+                               log, rv->subtlvs, indent + 4)) {
+                       goto out;
+               }
+       }
+
+       append_item(items, (struct isis_item *)rv);
+       return 0;
+out:
+       if (rv)
+               free_item_ipv6_reach((struct isis_item *)rv);
+       return 1;
+}
+
+/* Functions related to TLV 10 Authentication */
+static struct isis_item *copy_item_auth(struct isis_item *i)
+{
+       struct isis_auth *auth = (struct isis_auth *)i;
+       struct isis_auth *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
+
+       rv->type = auth->type;
+       rv->length = auth->length;
+       memcpy(rv->value, auth->value, sizeof(rv->value));
+       return (struct isis_item *)rv;
+}
+
+static void format_item_auth(uint16_t mtid, struct isis_item *i,
+                            struct sbuf *buf, int indent)
+{
+       struct isis_auth *auth = (struct isis_auth *)i;
+       char obuf[768];
+
+       sbuf_push(buf, indent, "Authentication:\n");
+       switch (auth->type) {
+       case ISIS_PASSWD_TYPE_CLEARTXT:
+               zlog_sanitize(obuf, sizeof(obuf), auth->value, auth->length);
+               sbuf_push(buf, indent, "  Password: %s\n", obuf);
+               break;
+       case ISIS_PASSWD_TYPE_HMAC_MD5:
+               for (unsigned int i = 0; i < 16; i++) {
+                       snprintf(obuf + 2 * i, sizeof(obuf) - 2 * i,
+                                "%02" PRIx8, auth->value[i]);
+               }
+               sbuf_push(buf, indent, "  HMAC-MD5: %s\n", obuf);
+               break;
+       default:
+               sbuf_push(buf, indent, "  Unknown (%" PRIu8 ")\n", auth->type);
+               break;
+       };
+}
+
+static void free_item_auth(struct isis_item *i)
+{
+       XFREE(MTYPE_ISIS_TLV, i);
+}
+
+static int pack_item_auth(struct isis_item *i, struct stream *s)
+{
+       struct isis_auth *auth = (struct isis_auth *)i;
+
+       if (STREAM_WRITEABLE(s) < 1)
+               return 1;
+       stream_putc(s, auth->type);
+
+       switch (auth->type) {
+       case ISIS_PASSWD_TYPE_CLEARTXT:
+               if (STREAM_WRITEABLE(s) < auth->length)
+                       return 1;
+               stream_put(s, auth->passwd, auth->length);
+               break;
+       case ISIS_PASSWD_TYPE_HMAC_MD5:
+               if (STREAM_WRITEABLE(s) < 16)
+                       return 1;
+               auth->offset = stream_get_endp(s);
+               stream_put(s, NULL, 16);
+               break;
+       default:
+               return 1;
+       }
+
+       return 0;
+}
+
+static int unpack_item_auth(uint16_t mtid, uint8_t len, struct stream *s,
+                           struct sbuf *log, void *dest, int indent)
+{
+       struct isis_tlvs *tlvs = dest;
+
+       sbuf_push(log, indent, "Unpack Auth TLV...\n");
+       if (len < 1) {
+               sbuf_push(
+                       log, indent,
+                       "Not enough data left.(Expected 1 bytes of auth type, got %" PRIu8
+                       ")\n",
+                       len);
+               return 1;
+       }
+
+       struct isis_auth *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
+
+       rv->type = stream_getc(s);
+       rv->length = len - 1;
+
+       if (rv->type == ISIS_PASSWD_TYPE_HMAC_MD5 && rv->length != 16) {
+               sbuf_push(
+                       log, indent,
+                       "Unexpected auth length for HMAC-MD5 (expected 16, got %" PRIu8
+                       ")\n",
+                       rv->length);
+               XFREE(MTYPE_ISIS_TLV, rv);
+               return 1;
+       }
+
+       rv->offset = stream_get_getp(s);
+       stream_get(rv->value, s, rv->length);
+       format_item_auth(mtid, (struct isis_item *)rv, log, indent + 2);
+       append_item(&tlvs->isis_auth, (struct isis_item *)rv);
+       return 0;
+}
+
+/* Functions relating to item TLVs */
+
+static void init_item_list(struct isis_item_list *items)
+{
+       items->head = NULL;
+       items->tail = &items->head;
+       items->count = 0;
+}
+
+static struct isis_item *copy_item(enum isis_tlv_context context,
+                                  enum isis_tlv_type type,
+                                  struct isis_item *item)
+{
+       const struct tlv_ops *ops = tlv_table[context][type];
+
+       if (ops && ops->copy_item)
+               return ops->copy_item(item);
+
+       assert(!"Unknown item tlv type!");
+       return NULL;
+}
+
+static void copy_items(enum isis_tlv_context context, enum isis_tlv_type type,
+                      struct isis_item_list *src, struct isis_item_list *dest)
+{
+       struct isis_item *item;
+
+       init_item_list(dest);
+
+       for (item = src->head; item; item = item->next) {
+               append_item(dest, copy_item(context, type, item));
+       }
+}
+
+static void format_item(uint16_t mtid, enum isis_tlv_context context,
+                       enum isis_tlv_type type, struct isis_item *i,
+                       struct sbuf *buf, int indent)
+{
+       const struct tlv_ops *ops = tlv_table[context][type];
+
+       if (ops && ops->format_item) {
+               ops->format_item(mtid, i, buf, indent);
+               return;
+       }
+
+       assert(!"Unknown item tlv type!");
+}
+
+static void format_items_(uint16_t mtid, enum isis_tlv_context context,
+                         enum isis_tlv_type type, struct isis_item_list *items,
+                         struct sbuf *buf, int indent)
+{
+       struct isis_item *i;
+
+       for (i = items->head; i; i = i->next)
+               format_item(mtid, context, type, i, buf, indent);
+}
+#define format_items(...) format_items_(ISIS_MT_IPV4_UNICAST, __VA_ARGS__)
+
+static void free_item(enum isis_tlv_context tlv_context,
+                     enum isis_tlv_type tlv_type, struct isis_item *item)
+{
+       const struct tlv_ops *ops = tlv_table[tlv_context][tlv_type];
+
+       if (ops && ops->free_item) {
+               ops->free_item(item);
+               return;
+       }
+
+       assert(!"Unknown item tlv type!");
+}
+
+static void free_items(enum isis_tlv_context context, enum isis_tlv_type type,
+                      struct isis_item_list *items)
+{
+       struct isis_item *item, *next_item;
+
+       for (item = items->head; item; item = next_item) {
+               next_item = item->next;
+               free_item(context, type, item);
+       }
+}
+
+static int pack_item(enum isis_tlv_context context, enum isis_tlv_type type,
+                    struct isis_item *i, struct stream *s,
+                    struct isis_tlvs **fragment_tlvs,
+                    struct pack_order_entry *pe, uint16_t mtid)
+{
+       const struct tlv_ops *ops = tlv_table[context][type];
+
+       if (ops && ops->pack_item) {
+               return ops->pack_item(i, s);
+       }
+
+       assert(!"Unknown item tlv type!");
+       return 1;
+}
+
+static void add_item_to_fragment(struct isis_item *i, struct pack_order_entry *pe,
+                                struct isis_tlvs *fragment_tlvs, uint16_t mtid)
+{
+       struct isis_item_list *l;
+
+       if (pe->how_to_pack == ISIS_ITEMS) {
+               l = (struct isis_item_list *)(((char *)fragment_tlvs) + pe->what_to_pack);
+       } else {
+               struct isis_mt_item_list *m;
+               m = (struct isis_mt_item_list *)(((char *)fragment_tlvs) + pe->what_to_pack);
+               l = isis_get_mt_items(m, mtid);
+       }
+
+       append_item(l, copy_item(pe->context, pe->type, i));
+}
+
+static int pack_items_(uint16_t mtid, enum isis_tlv_context context,
+                      enum isis_tlv_type type, struct isis_item_list *items,
+                      struct stream *s, struct isis_tlvs **fragment_tlvs,
+                      struct pack_order_entry *pe,
+                      struct isis_tlvs *(*new_fragment)(struct list *l),
+                      struct list *new_fragment_arg)
+{
+       size_t len_pos, last_len, len;
+       struct isis_item *item = NULL;
+       int rv;
+
+       if (!items->head)
+               return 0;
+
+top:
+       if (STREAM_WRITEABLE(s) < 2)
+               goto too_long;
+
+       stream_putc(s, type);
+       len_pos = stream_get_endp(s);
+       stream_putc(s, 0); /* Put 0 as length for now */
+
+       if (context == ISIS_CONTEXT_LSP && IS_COMPAT_MT_TLV(type)
+           && mtid != ISIS_MT_IPV4_UNICAST) {
+               if (STREAM_WRITEABLE(s) < 2)
+                       goto too_long;
+               stream_putw(s, mtid);
+       }
+
+       if (context == ISIS_CONTEXT_LSP && type == ISIS_TLV_OLDSTYLE_REACH) {
+               if (STREAM_WRITEABLE(s) < 1)
+                       goto too_long;
+               stream_putc(s, 0); /* Virtual flag is set to 0 */
+       }
+
+       last_len = len = 0;
+       for (item = item ? item : items->head; item; item = item->next) {
+               rv = pack_item(context, type, item, s, fragment_tlvs, pe, mtid);
+               if (rv)
+                       goto too_long;
+
+               len = stream_get_endp(s) - len_pos - 1;
+
+               /* Multiple auths don't go into one TLV, so always break */
+               if (context == ISIS_CONTEXT_LSP && type == ISIS_TLV_AUTH) {
+                       item = item->next;
+                       break;
+               }
+
+               if (len > 255) {
+                       if (!last_len) /* strange, not a single item fit */
+                               return 1;
+                       /* drop last tlv, otherwise, its too long */
+                       stream_set_endp(s, len_pos + 1 + last_len);
+                       len = last_len;
+                       break;
+               }
+
+               if (fragment_tlvs)
+                       add_item_to_fragment(item, pe, *fragment_tlvs, mtid);
+
+               last_len = len;
+       }
+
+       stream_putc_at(s, len_pos, len);
+       if (item)
+               goto top;
+
+       return 0;
+too_long:
+       if (!fragment_tlvs)
+               return 1;
+       stream_reset(s);
+       *fragment_tlvs = new_fragment(new_fragment_arg);
+       goto top;
+}
+#define pack_items(...) pack_items_(ISIS_MT_IPV4_UNICAST, __VA_ARGS__)
+
+static void append_item(struct isis_item_list *dest, struct isis_item *item)
+{
+       *dest->tail = item;
+       dest->tail = &(*dest->tail)->next;
+       dest->count++;
+}
+
+static int unpack_item(uint16_t mtid, enum isis_tlv_context context,
+                      uint8_t tlv_type, uint8_t len, struct stream *s,
+                      struct sbuf *log, void *dest, int indent)
+{
+       const struct tlv_ops *ops = tlv_table[context][tlv_type];
+
+       if (ops && ops->unpack_item)
+               return ops->unpack_item(mtid, len, s, log, dest, indent);
+
+       assert(!"Unknown item tlv type!");
+       sbuf_push(log, indent, "Unknown item tlv type!\n");
+       return 1;
+}
+
+static int unpack_tlv_with_items(enum isis_tlv_context context,
+                                uint8_t tlv_type, uint8_t tlv_len,
+                                struct stream *s, struct sbuf *log, void *dest,
+                                int indent)
+{
+       size_t tlv_start;
+       size_t tlv_pos;
+       int rv;
+       uint16_t mtid;
+
+       tlv_start = stream_get_getp(s);
+       tlv_pos = 0;
+
+       if (context == ISIS_CONTEXT_LSP && IS_COMPAT_MT_TLV(tlv_type)) {
+               if (tlv_len < 2) {
+                       sbuf_push(log, indent,
+                                 "TLV is too short to contain MTID\n");
+                       return 1;
+               }
+               mtid = stream_getw(s) & ISIS_MT_MASK;
+               tlv_pos += 2;
+               sbuf_push(log, indent, "Unpacking as MT %s item TLV...\n",
+                         isis_mtid2str(mtid));
+       } else {
+               sbuf_push(log, indent, "Unpacking as item TLV...\n");
+               mtid = ISIS_MT_IPV4_UNICAST;
+       }
+
+       if (context == ISIS_CONTEXT_LSP
+           && tlv_type == ISIS_TLV_OLDSTYLE_REACH) {
+               if (tlv_len - tlv_pos < 1) {
+                       sbuf_push(log, indent,
+                                 "TLV is too short for old style reach\n");
+                       return 1;
+               }
+               stream_forward_getp(s, 1);
+               tlv_pos += 1;
+       }
+
+       if (context == ISIS_CONTEXT_LSP
+           && tlv_type == ISIS_TLV_OLDSTYLE_IP_REACH) {
+               struct isis_tlvs *tlvs = dest;
+               dest = &tlvs->oldstyle_ip_reach;
+       } else if (context == ISIS_CONTEXT_LSP
+                  && tlv_type == ISIS_TLV_OLDSTYLE_IP_REACH_EXT) {
+               struct isis_tlvs *tlvs = dest;
+               dest = &tlvs->oldstyle_ip_reach_ext;
+       }
+
+       if (context == ISIS_CONTEXT_LSP
+           && tlv_type == ISIS_TLV_MT_ROUTER_INFO) {
+               struct isis_tlvs *tlvs = dest;
+               tlvs->mt_router_info_empty = (tlv_pos >= (size_t)tlv_len);
+       }
+
+       while (tlv_pos < (size_t)tlv_len) {
+               rv = unpack_item(mtid, context, tlv_type, tlv_len - tlv_pos, s,
+                                log, dest, indent + 2);
+               if (rv)
+                       return rv;
+
+               tlv_pos = stream_get_getp(s) - tlv_start;
+       }
+
+       return 0;
+}
+
+/* Functions to manipulate mt_item_lists */
+
+static int isis_mt_item_list_cmp(const struct isis_item_list *a,
+                                const struct isis_item_list *b)
+{
+       if (a->mtid < b->mtid)
+               return -1;
+       if (a->mtid > b->mtid)
+               return 1;
+       return 0;
+}
+
+RB_PROTOTYPE(isis_mt_item_list, isis_item_list, mt_tree, isis_mt_item_list_cmp);
+RB_GENERATE(isis_mt_item_list, isis_item_list, mt_tree, isis_mt_item_list_cmp);
+
+struct isis_item_list *isis_get_mt_items(struct isis_mt_item_list *m,
+                                        uint16_t mtid)
+{
+       struct isis_item_list *rv;
+
+       rv = isis_lookup_mt_items(m, mtid);
+       if (!rv) {
+               rv = XCALLOC(MTYPE_ISIS_MT_ITEM_LIST, sizeof(*rv));
+               init_item_list(rv);
+               rv->mtid = mtid;
+               RB_INSERT(isis_mt_item_list, m, rv);
+       }
+
+       return rv;
+}
+
+struct isis_item_list *isis_lookup_mt_items(struct isis_mt_item_list *m,
+                                           uint16_t mtid)
+{
+       struct isis_item_list key = {.mtid = mtid};
+
+       return RB_FIND(isis_mt_item_list, m, &key);
+}
+
+static void free_mt_items(enum isis_tlv_context context,
+                         enum isis_tlv_type type, struct isis_mt_item_list *m)
+{
+       struct isis_item_list *n, *nnext;
+
+       RB_FOREACH_SAFE(n, isis_mt_item_list, m, nnext)
+       {
+               free_items(context, type, n);
+               RB_REMOVE(isis_mt_item_list, m, n);
+               XFREE(MTYPE_ISIS_MT_ITEM_LIST, n);
+       }
+}
+
+static void format_mt_items(enum isis_tlv_context context,
+                           enum isis_tlv_type type,
+                           struct isis_mt_item_list *m, struct sbuf *buf,
+                           int indent)
+{
+       struct isis_item_list *n;
+
+       RB_FOREACH(n, isis_mt_item_list, m)
+       {
+               format_items_(n->mtid, context, type, n, buf, indent);
+       }
+}
+
+static int pack_mt_items(enum isis_tlv_context context, enum isis_tlv_type type,
+                        struct isis_mt_item_list *m, struct stream *s,
+                        struct isis_tlvs **fragment_tlvs,
+                        struct pack_order_entry *pe,
+                        struct isis_tlvs *(*new_fragment)(struct list *l),
+                        struct list *new_fragment_arg)
+{
+       struct isis_item_list *n;
+
+       RB_FOREACH(n, isis_mt_item_list, m)
+       {
+               int rv;
+
+               rv = pack_items_(n->mtid, context, type, n, s, fragment_tlvs,
+                                pe, new_fragment, new_fragment_arg);
+               if (rv)
+                       return rv;
+       }
+
+       return 0;
+}
+
+static void copy_mt_items(enum isis_tlv_context context,
+                         enum isis_tlv_type type,
+                         struct isis_mt_item_list *src,
+                         struct isis_mt_item_list *dest)
+{
+       struct isis_item_list *n;
+
+       RB_INIT(isis_mt_item_list, dest);
+
+       RB_FOREACH(n, isis_mt_item_list, src)
+       {
+               copy_items(context, type, n, isis_get_mt_items(dest, n->mtid));
+       }
+}
+
+/* Functions related to tlvs in general */
+
+struct isis_tlvs *isis_alloc_tlvs(void)
+{
+       struct isis_tlvs *result;
+
+       result = XCALLOC(MTYPE_ISIS_TLV, sizeof(*result));
+
+       init_item_list(&result->isis_auth);
+       init_item_list(&result->area_addresses);
+       init_item_list(&result->mt_router_info);
+       init_item_list(&result->oldstyle_reach);
+       init_item_list(&result->lan_neighbor);
+       init_item_list(&result->lsp_entries);
+       init_item_list(&result->extended_reach);
+       RB_INIT(isis_mt_item_list, &result->mt_reach);
+       init_item_list(&result->oldstyle_ip_reach);
+       init_item_list(&result->oldstyle_ip_reach_ext);
+       init_item_list(&result->ipv4_address);
+       init_item_list(&result->ipv6_address);
+       init_item_list(&result->extended_ip_reach);
+       RB_INIT(isis_mt_item_list, &result->mt_ip_reach);
+       init_item_list(&result->ipv6_reach);
+       RB_INIT(isis_mt_item_list, &result->mt_ipv6_reach);
+
+       return result;
+}
+
+struct isis_tlvs *isis_copy_tlvs(struct isis_tlvs *tlvs)
+{
+       struct isis_tlvs *rv = XCALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
+
+       copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_AUTH, &tlvs->isis_auth,
+                  &rv->isis_auth);
+
+       copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_AREA_ADDRESSES,
+                  &tlvs->area_addresses, &rv->area_addresses);
+
+       copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_ROUTER_INFO,
+                  &tlvs->mt_router_info, &rv->mt_router_info);
+
+       tlvs->mt_router_info_empty = rv->mt_router_info_empty;
+
+       copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_OLDSTYLE_REACH,
+                  &tlvs->oldstyle_reach, &rv->oldstyle_reach);
+
+       copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_LAN_NEIGHBORS,
+                  &tlvs->lan_neighbor, &rv->lan_neighbor);
+
+       copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_LSP_ENTRY, &tlvs->lsp_entries,
+                  &rv->lsp_entries);
+
+       copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_EXTENDED_REACH,
+                  &tlvs->extended_reach, &rv->extended_reach);
+
+       copy_mt_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_REACH, &tlvs->mt_reach,
+                     &rv->mt_reach);
+
+       copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_OLDSTYLE_IP_REACH,
+                  &tlvs->oldstyle_ip_reach, &rv->oldstyle_ip_reach);
+
+       copy_tlv_protocols_supported(&tlvs->protocols_supported,
+                                    &rv->protocols_supported);
+
+       copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_OLDSTYLE_IP_REACH_EXT,
+                  &tlvs->oldstyle_ip_reach_ext, &rv->oldstyle_ip_reach_ext);
+
+       copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_IPV4_ADDRESS, &tlvs->ipv4_address,
+                  &rv->ipv4_address);
+
+       copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_IPV6_ADDRESS, &tlvs->ipv6_address,
+                  &rv->ipv6_address);
+
+       rv->te_router_id = copy_tlv_te_router_id(tlvs->te_router_id);
+
+       copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_EXTENDED_IP_REACH,
+                  &tlvs->extended_ip_reach, &rv->extended_ip_reach);
+
+       copy_mt_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_IP_REACH,
+                     &tlvs->mt_ip_reach, &rv->mt_ip_reach);
+
+       rv->hostname = copy_tlv_dynamic_hostname(tlvs->hostname);
+
+       copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_IPV6_REACH, &tlvs->ipv6_reach,
+                  &rv->ipv6_reach);
+
+       copy_mt_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_IPV6_REACH,
+                     &tlvs->mt_ipv6_reach, &rv->mt_ipv6_reach);
+
+       return rv;
+}
+
+static void format_tlvs(struct isis_tlvs *tlvs, struct sbuf *buf, int indent)
+{
+       format_tlv_protocols_supported(&tlvs->protocols_supported, buf, indent);
+
+       format_items(ISIS_CONTEXT_LSP, ISIS_TLV_AUTH, &tlvs->isis_auth, buf,
+                    indent);
+
+       format_items(ISIS_CONTEXT_LSP, ISIS_TLV_AREA_ADDRESSES,
+                    &tlvs->area_addresses, buf, indent);
+
+       if (tlvs->mt_router_info_empty) {
+               sbuf_push(buf, indent, "MT Router Info: None\n");
+       } else {
+               format_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_ROUTER_INFO,
+                            &tlvs->mt_router_info, buf, indent);
+       }
+
+       format_items(ISIS_CONTEXT_LSP, ISIS_TLV_OLDSTYLE_REACH,
+                    &tlvs->oldstyle_reach, buf, indent);
+
+       format_items(ISIS_CONTEXT_LSP, ISIS_TLV_LAN_NEIGHBORS,
+                    &tlvs->lan_neighbor, buf, indent);
+
+       format_items(ISIS_CONTEXT_LSP, ISIS_TLV_LSP_ENTRY, &tlvs->lsp_entries,
+                    buf, indent);
+
+       format_tlv_dynamic_hostname(tlvs->hostname, buf, indent);
+       format_tlv_te_router_id(tlvs->te_router_id, buf, indent);
+
+       format_items(ISIS_CONTEXT_LSP, ISIS_TLV_EXTENDED_REACH,
+                    &tlvs->extended_reach, buf, indent);
+
+       format_mt_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_REACH, &tlvs->mt_reach,
+                       buf, indent);
+
+       format_items(ISIS_CONTEXT_LSP, ISIS_TLV_OLDSTYLE_IP_REACH,
+                    &tlvs->oldstyle_ip_reach, buf, indent);
+
+       format_items(ISIS_CONTEXT_LSP, ISIS_TLV_OLDSTYLE_IP_REACH_EXT,
+                    &tlvs->oldstyle_ip_reach_ext, buf, indent);
+
+       format_items(ISIS_CONTEXT_LSP, ISIS_TLV_IPV4_ADDRESS,
+                    &tlvs->ipv4_address, buf, indent);
+
+       format_items(ISIS_CONTEXT_LSP, ISIS_TLV_IPV6_ADDRESS,
+                    &tlvs->ipv6_address, buf, indent);
+
+       format_items(ISIS_CONTEXT_LSP, ISIS_TLV_EXTENDED_IP_REACH,
+                    &tlvs->extended_ip_reach, buf, indent);
+
+       format_mt_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_IP_REACH,
+                       &tlvs->mt_ip_reach, buf, indent);
+
+       format_items(ISIS_CONTEXT_LSP, ISIS_TLV_IPV6_REACH, &tlvs->ipv6_reach,
+                    buf, indent);
+
+       format_mt_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_IPV6_REACH,
+                       &tlvs->mt_ipv6_reach, buf, indent);
+}
+
+const char *isis_format_tlvs(struct isis_tlvs *tlvs)
+{
+       static struct sbuf buf;
+
+       if (!sbuf_buf(&buf))
+               sbuf_init(&buf, NULL, 0);
+
+       sbuf_reset(&buf);
+       format_tlvs(tlvs, &buf, 0);
+       return sbuf_buf(&buf);
+}
+
+void isis_free_tlvs(struct isis_tlvs *tlvs)
+{
+       if (!tlvs)
+               return;
+
+       free_items(ISIS_CONTEXT_LSP, ISIS_TLV_AUTH, &tlvs->isis_auth);
+       free_items(ISIS_CONTEXT_LSP, ISIS_TLV_AREA_ADDRESSES,
+                  &tlvs->area_addresses);
+       free_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_ROUTER_INFO,
+                  &tlvs->mt_router_info);
+       free_items(ISIS_CONTEXT_LSP, ISIS_TLV_OLDSTYLE_REACH,
+                  &tlvs->oldstyle_reach);
+       free_items(ISIS_CONTEXT_LSP, ISIS_TLV_LAN_NEIGHBORS,
+                  &tlvs->lan_neighbor);
+       free_items(ISIS_CONTEXT_LSP, ISIS_TLV_LSP_ENTRY, &tlvs->lsp_entries);
+       free_items(ISIS_CONTEXT_LSP, ISIS_TLV_EXTENDED_REACH,
+                  &tlvs->extended_reach);
+       free_mt_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_REACH, &tlvs->mt_reach);
+       free_items(ISIS_CONTEXT_LSP, ISIS_TLV_OLDSTYLE_IP_REACH,
+                  &tlvs->oldstyle_ip_reach);
+       free_tlv_protocols_supported(&tlvs->protocols_supported);
+       free_items(ISIS_CONTEXT_LSP, ISIS_TLV_OLDSTYLE_IP_REACH_EXT,
+                  &tlvs->oldstyle_ip_reach_ext);
+       free_items(ISIS_CONTEXT_LSP, ISIS_TLV_IPV4_ADDRESS,
+                  &tlvs->ipv4_address);
+       free_items(ISIS_CONTEXT_LSP, ISIS_TLV_IPV6_ADDRESS,
+                  &tlvs->ipv6_address);
+       free_tlv_te_router_id(tlvs->te_router_id);
+       free_items(ISIS_CONTEXT_LSP, ISIS_TLV_EXTENDED_IP_REACH,
+                  &tlvs->extended_ip_reach);
+       free_mt_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_IP_REACH,
+                     &tlvs->mt_ip_reach);
+       free_tlv_dynamic_hostname(tlvs->hostname);
+       free_items(ISIS_CONTEXT_LSP, ISIS_TLV_IPV6_REACH, &tlvs->ipv6_reach);
+       free_mt_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_IPV6_REACH,
+                     &tlvs->mt_ipv6_reach);
+
+       XFREE(MTYPE_ISIS_TLV, tlvs);
+}
+
+static void add_padding(struct stream *s)
+{
+       while (STREAM_WRITEABLE(s)) {
+               if (STREAM_WRITEABLE(s) == 1)
+                       break;
+               uint32_t padding_len = STREAM_WRITEABLE(s) - 2;
+
+               if (padding_len > 255) {
+                       if (padding_len == 256)
+                               padding_len = 254;
+                       else
+                               padding_len = 255;
+               }
+
+               stream_putc(s, ISIS_TLV_PADDING);
+               stream_putc(s, padding_len);
+               stream_put(s, NULL, padding_len);
+       }
+}
+
+#define LSP_REM_LIFETIME_OFF 10
+#define LSP_CHECKSUM_OFF 24
+static void safe_auth_md5(struct stream *s, uint16_t *checksum,
+                         uint16_t *rem_lifetime)
+{
+       memcpy(rem_lifetime, STREAM_DATA(s) + LSP_REM_LIFETIME_OFF,
+              sizeof(*rem_lifetime));
+       memset(STREAM_DATA(s) + LSP_REM_LIFETIME_OFF, 0, sizeof(*rem_lifetime));
+       memcpy(checksum, STREAM_DATA(s) + LSP_CHECKSUM_OFF, sizeof(*checksum));
+       memset(STREAM_DATA(s) + LSP_CHECKSUM_OFF, 0, sizeof(*checksum));
+}
+
+static void restore_auth_md5(struct stream *s, uint16_t checksum,
+                            uint16_t rem_lifetime)
+{
+       memcpy(STREAM_DATA(s) + LSP_REM_LIFETIME_OFF, &rem_lifetime,
+              sizeof(rem_lifetime));
+       memcpy(STREAM_DATA(s) + LSP_CHECKSUM_OFF, &checksum, sizeof(checksum));
+}
+
+static void update_auth_hmac_md5(struct isis_auth *auth, struct stream *s,
+                                bool is_lsp)
+{
+       uint8_t digest[16];
+       uint16_t checksum, rem_lifetime;
+
+       if (is_lsp)
+               safe_auth_md5(s, &checksum, &rem_lifetime);
+
+       memset(STREAM_DATA(s) + auth->offset, 0, 16);
+       hmac_md5(STREAM_DATA(s), stream_get_endp(s), auth->passwd,
+                auth->plength, digest);
+       memcpy(auth->value, digest, 16);
+       memcpy(STREAM_DATA(s) + auth->offset, digest, 16);
+
+       if (is_lsp)
+               restore_auth_md5(s, checksum, rem_lifetime);
+}
+
+static void update_auth(struct isis_tlvs *tlvs, struct stream *s, bool is_lsp)
+{
+       struct isis_auth *auth_head = (struct isis_auth *)tlvs->isis_auth.head;
+
+       for (struct isis_auth *auth = auth_head; auth; auth = auth->next) {
+               if (auth->type == ISIS_PASSWD_TYPE_HMAC_MD5)
+                       update_auth_hmac_md5(auth, s, is_lsp);
+       }
+}
+
+static int handle_pack_entry(struct pack_order_entry *pe,
+                            struct isis_tlvs *tlvs, struct stream *stream,
+                            struct isis_tlvs **fragment_tlvs,
+                            struct isis_tlvs *(*new_fragment)(struct list *l),
+                            struct list *new_fragment_arg)
+{
+       int rv;
+
+       if (pe->how_to_pack == ISIS_ITEMS) {
+               struct isis_item_list *l;
+               l = (struct isis_item_list *)(((char *)tlvs)
+                                             + pe->what_to_pack);
+               rv = pack_items(pe->context, pe->type, l, stream, fragment_tlvs,
+                               pe, new_fragment, new_fragment_arg);
+       } else {
+               struct isis_mt_item_list *l;
+               l = (struct isis_mt_item_list *)(((char *)tlvs)
+                                                + pe->what_to_pack);
+               rv = pack_mt_items(pe->context, pe->type, l, stream,
+                                  fragment_tlvs, pe, new_fragment,
+                                  new_fragment_arg);
+       }
+
+       return rv;
+}
+
+static int pack_tlvs(struct isis_tlvs *tlvs, struct stream *stream,
+                    struct isis_tlvs *fragment_tlvs,
+                    struct isis_tlvs *(*new_fragment)(struct list *l),
+                    struct list *new_fragment_arg)
+{
+       int rv;
+
+       /* When fragmenting, don't add auth as it's already accounted for in the
+        * size we are given. */
+       if (!fragment_tlvs) {
+               rv = pack_items(ISIS_CONTEXT_LSP, ISIS_TLV_AUTH, &tlvs->isis_auth,
+                               stream, NULL, NULL, NULL, NULL);
+               if (rv)
+                       return rv;
+       }
+
+       rv = pack_tlv_protocols_supported(&tlvs->protocols_supported, stream);
+       if (rv)
+               return rv;
+       if (fragment_tlvs) {
+               copy_tlv_protocols_supported(
+                       &tlvs->protocols_supported,
+                       &fragment_tlvs->protocols_supported);
+       }
+
+       rv = pack_items(ISIS_CONTEXT_LSP, ISIS_TLV_AREA_ADDRESSES,
+                       &tlvs->area_addresses, stream, NULL, NULL, NULL, NULL);
+       if (rv)
+               return rv;
+       if (fragment_tlvs) {
+               copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_AREA_ADDRESSES,
+                          &tlvs->area_addresses,
+                          &fragment_tlvs->area_addresses);
+       }
+
+
+       if (tlvs->mt_router_info_empty) {
+               if (STREAM_WRITEABLE(stream) < 2)
+                       return 1;
+               stream_putc(stream, ISIS_TLV_MT_ROUTER_INFO);
+               stream_putc(stream, 0);
+               if (fragment_tlvs)
+                       fragment_tlvs->mt_router_info_empty = true;
+       } else {
+               rv = pack_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_ROUTER_INFO,
+                               &tlvs->mt_router_info, stream, NULL, NULL, NULL,
+                               NULL);
+               if (rv)
+                       return rv;
+               if (fragment_tlvs) {
+                       copy_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_ROUTER_INFO,
+                                  &tlvs->mt_router_info,
+                                  &fragment_tlvs->mt_router_info);
+               }
+       }
+
+       rv = pack_tlv_dynamic_hostname(tlvs->hostname, stream);
+       if (rv)
+               return rv;
+       if (fragment_tlvs)
+               fragment_tlvs->hostname =
+                       copy_tlv_dynamic_hostname(tlvs->hostname);
+
+       rv = pack_tlv_te_router_id(tlvs->te_router_id, stream);
+       if (rv)
+               return rv;
+       if (fragment_tlvs) {
+               fragment_tlvs->te_router_id =
+                       copy_tlv_te_router_id(tlvs->te_router_id);
+       }
+
+       for (size_t pack_idx = 0; pack_idx < array_size(pack_order);
+            pack_idx++) {
+               rv = handle_pack_entry(&pack_order[pack_idx], tlvs, stream,
+                                      fragment_tlvs ? &fragment_tlvs : NULL,
+                                      new_fragment, new_fragment_arg);
+
+               if (rv)
+                       return rv;
+       }
+
+       return 0;
+}
+
+int isis_pack_tlvs(struct isis_tlvs *tlvs, struct stream *stream,
+                  size_t len_pointer, bool pad, bool is_lsp)
+{
+       int rv;
+
+       rv = pack_tlvs(tlvs, stream, NULL, NULL, NULL);
+       if (rv)
+               return rv;
+
+       if (pad)
+               add_padding(stream);
+
+       if (len_pointer != (size_t)-1) {
+               stream_putw_at(stream, len_pointer, stream_get_endp(stream));
+       }
+
+       update_auth(tlvs, stream, is_lsp);
+
+       return 0;
+}
+
+static struct isis_tlvs *new_fragment(struct list *l)
+{
+       struct isis_tlvs *rv = isis_alloc_tlvs();
+
+       listnode_add(l, rv);
+       return rv;
+}
+
+struct list *isis_fragment_tlvs(struct isis_tlvs *tlvs, size_t size)
+{
+       struct stream *dummy_stream = stream_new(size);
+       struct list *rv = list_new();
+       struct isis_tlvs *fragment_tlvs = new_fragment(rv);
+
+       if (pack_tlvs(tlvs, dummy_stream, fragment_tlvs, new_fragment, rv)) {
+               struct listnode *node;
+               for (ALL_LIST_ELEMENTS_RO(rv, node, fragment_tlvs))
+                       isis_free_tlvs(fragment_tlvs);
+               list_delete(rv);
+               rv = NULL;
+       }
+
+       stream_free(dummy_stream);
+       return rv;
+}
+
+static int unpack_tlv_unknown(enum isis_tlv_context context, uint8_t tlv_type,
+                             uint8_t tlv_len, struct stream *s,
+                             struct sbuf *log, int indent)
+{
+       stream_forward_getp(s, tlv_len);
+       sbuf_push(log, indent,
+                 "Skipping unknown TLV %" PRIu8 " (%" PRIu8 " bytes)\n",
+                 tlv_type, tlv_len);
+       return 0;
+}
+
+static int unpack_tlv(enum isis_tlv_context context, size_t avail_len,
+                     struct stream *stream, struct sbuf *log, void *dest,
+                     int indent)
+{
+       uint8_t tlv_type, tlv_len;
+       const struct tlv_ops *ops;
+
+       sbuf_push(log, indent, "Unpacking TLV...\n");
+
+       if (avail_len < 2) {
+               sbuf_push(
+                       log, indent + 2,
+                       "Available data %zu too short to contain a TLV header.\n",
+                       avail_len);
+               return 1;
+       }
+
+       tlv_type = stream_getc(stream);
+       tlv_len = stream_getc(stream);
+
+       sbuf_push(log, indent + 2,
+                 "Found TLV of type %" PRIu8 " and len %" PRIu8 ".\n",
+                 tlv_type, tlv_len);
+
+       if (avail_len < ((size_t)tlv_len) + 2) {
+               sbuf_push(log, indent + 2,
+                         "Available data %zu too short for claimed TLV len %" PRIu8 ".\n",
+                         avail_len - 2, tlv_len);
+               return 1;
+       }
+
+       ops = tlv_table[context][tlv_type];
+       if (ops && ops->unpack) {
+               return ops->unpack(context, tlv_type, tlv_len, stream, log,
+                                  dest, indent + 2);
+       }
+
+       return unpack_tlv_unknown(context, tlv_type, tlv_len, stream, log,
+                                 indent + 2);
+}
+
+static int unpack_tlvs(enum isis_tlv_context context, size_t avail_len,
+                      struct stream *stream, struct sbuf *log, void *dest,
+                      int indent)
+{
+       int rv;
+       size_t tlv_start, tlv_pos;
+
+       tlv_start = stream_get_getp(stream);
+       tlv_pos = 0;
+
+       sbuf_push(log, indent, "Unpacking %zu bytes of %s...\n", avail_len,
+                 (context == ISIS_CONTEXT_LSP) ? "TLVs" : "sub-TLVs");
+
+       while (tlv_pos < avail_len) {
+               rv = unpack_tlv(context, avail_len - tlv_pos, stream, log, dest,
+                               indent + 2);
+               if (rv)
+                       return rv;
+
+               tlv_pos = stream_get_getp(stream) - tlv_start;
+       }
+
+       return 0;
+}
+
+int isis_unpack_tlvs(size_t avail_len, struct stream *stream,
+                    struct isis_tlvs **dest, const char **log)
+{
+       static struct sbuf logbuf;
+       int indent = 0;
+       int rv;
+       struct isis_tlvs *result;
+
+       if (!sbuf_buf(&logbuf))
+               sbuf_init(&logbuf, NULL, 0);
+
+       sbuf_reset(&logbuf);
+       if (avail_len > STREAM_READABLE(stream)) {
+               sbuf_push(&logbuf, indent,
+                         "Stream doesn't contain sufficient data. "
+                         "Claimed %zu, available %zu\n",
+                         avail_len, STREAM_READABLE(stream));
+               return 1;
+       }
+
+       result = isis_alloc_tlvs();
+       rv = unpack_tlvs(ISIS_CONTEXT_LSP, avail_len, stream, &logbuf, result,
+                        indent);
+
+       *log = sbuf_buf(&logbuf);
+       *dest = result;
+
+       return rv;
+}
+
+#define TLV_OPS(_name_, _desc_)                                                \
+       static const struct tlv_ops tlv_##_name_##_ops = {                     \
+               .name = _desc_, .unpack = unpack_tlv_##_name_,                 \
+       }
+
+#define ITEM_TLV_OPS(_name_, _desc_)                                           \
+       static const struct tlv_ops tlv_##_name_##_ops = {                     \
+               .name = _desc_,                                                \
+               .unpack = unpack_tlv_with_items,                               \
+                                                                              \
+               .pack_item = pack_item_##_name_,                               \
+               .free_item = free_item_##_name_,                               \
+               .unpack_item = unpack_item_##_name_,                           \
+               .format_item = format_item_##_name_,                           \
+               .copy_item = copy_item_##_name_}
+
+#define SUBTLV_OPS(_name_, _desc_)                                             \
+       static const struct tlv_ops subtlv_##_name_##_ops = {                  \
+               .name = _desc_, .unpack = unpack_subtlv_##_name_,              \
+       }
+
+ITEM_TLV_OPS(area_address, "TLV 1 Area Addresses");
+ITEM_TLV_OPS(oldstyle_reach, "TLV 2 IS Reachability");
+ITEM_TLV_OPS(lan_neighbor, "TLV 6 LAN Neighbors");
+ITEM_TLV_OPS(lsp_entry, "TLV 9 LSP Entries");
+ITEM_TLV_OPS(auth, "TLV 10 IS-IS Auth");
+ITEM_TLV_OPS(extended_reach, "TLV 22 Extended Reachability");
+ITEM_TLV_OPS(oldstyle_ip_reach, "TLV 128/130 IP Reachability");
+TLV_OPS(protocols_supported, "TLV 129 Protocols Supported");
+ITEM_TLV_OPS(ipv4_address, "TLV 132 IPv4 Interface Address");
+TLV_OPS(te_router_id, "TLV 134 TE Router ID");
+ITEM_TLV_OPS(extended_ip_reach, "TLV 135 Extended IP Reachability");
+TLV_OPS(dynamic_hostname, "TLV 137 Dynamic Hostname");
+ITEM_TLV_OPS(mt_router_info, "TLV 229 MT Router Information");
+ITEM_TLV_OPS(ipv6_address, "TLV 232 IPv6 Interface Address");
+ITEM_TLV_OPS(ipv6_reach, "TLV 236 IPv6 Reachability");
+
+SUBTLV_OPS(ipv6_source_prefix, "Sub-TLV 22 IPv6 Source Prefix");
+
+static const struct tlv_ops *tlv_table[ISIS_CONTEXT_MAX][ISIS_TLV_MAX] = {
+       [ISIS_CONTEXT_LSP] = {
+               [ISIS_TLV_AREA_ADDRESSES] = &tlv_area_address_ops,
+               [ISIS_TLV_OLDSTYLE_REACH] = &tlv_oldstyle_reach_ops,
+               [ISIS_TLV_LAN_NEIGHBORS] = &tlv_lan_neighbor_ops,
+               [ISIS_TLV_LSP_ENTRY] = &tlv_lsp_entry_ops,
+               [ISIS_TLV_AUTH] = &tlv_auth_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_MT_ROUTER_INFO] = &tlv_mt_router_info_ops,
+               [ISIS_TLV_IPV6_ADDRESS] = &tlv_ipv6_address_ops,
+               [ISIS_TLV_IPV6_REACH] = &tlv_ipv6_reach_ops,
+               [ISIS_TLV_MT_IPV6_REACH] = &tlv_ipv6_reach_ops,
+       },
+       [ISIS_CONTEXT_SUBTLV_NE_REACH] = {},
+       [ISIS_CONTEXT_SUBTLV_IP_REACH] = {},
+       [ISIS_CONTEXT_SUBTLV_IPV6_REACH] = {
+               [ISIS_SUBTLV_IPV6_SOURCE_PREFIX] = &subtlv_ipv6_source_prefix_ops,
+       }
+};
+
+/* Accessor functions */
+
+void isis_tlvs_add_auth(struct isis_tlvs *tlvs, struct isis_passwd *passwd)
+{
+       free_items(ISIS_CONTEXT_LSP, ISIS_TLV_AUTH, &tlvs->isis_auth);
+       init_item_list(&tlvs->isis_auth);
+
+       if (passwd->type == ISIS_PASSWD_TYPE_UNUSED)
+               return;
+
+       struct isis_auth *auth = XCALLOC(MTYPE_ISIS_TLV, sizeof(*auth));
+
+       auth->type = passwd->type;
+
+       auth->plength = passwd->len;
+       memcpy(auth->passwd, passwd->passwd,
+              MIN(sizeof(auth->passwd), sizeof(passwd->passwd)));
+
+       if (auth->type == ISIS_PASSWD_TYPE_CLEARTXT) {
+               auth->length = passwd->len;
+               memcpy(auth->value, passwd->passwd,
+                      MIN(sizeof(auth->value), sizeof(passwd->passwd)));
+       }
+
+       append_item(&tlvs->isis_auth, (struct isis_item *)auth);
+}
+
+void isis_tlvs_add_area_addresses(struct isis_tlvs *tlvs,
+                                 struct list *addresses)
+{
+       struct listnode *node;
+       struct area_addr *area_addr;
+
+       for (ALL_LIST_ELEMENTS_RO(addresses, node, area_addr)) {
+               struct isis_area_address *a =
+                       XCALLOC(MTYPE_ISIS_TLV, sizeof(*a));
+
+               a->len = area_addr->addr_len;
+               memcpy(a->addr, area_addr->area_addr, 20);
+               append_item(&tlvs->area_addresses, (struct isis_item *)a);
+       }
+}
+
+void isis_tlvs_add_lan_neighbors(struct isis_tlvs *tlvs, struct list *neighbors)
+{
+       struct listnode *node;
+       u_char *snpa;
+
+       for (ALL_LIST_ELEMENTS_RO(neighbors, node, snpa)) {
+               struct isis_lan_neighbor *n =
+                       XCALLOC(MTYPE_ISIS_TLV, sizeof(*n));
+
+               memcpy(n->mac, snpa, 6);
+               append_item(&tlvs->lan_neighbor, (struct isis_item *)n);
+       }
+}
+
+void isis_tlvs_set_protocols_supported(struct isis_tlvs *tlvs,
+                                      struct nlpids *nlpids)
+{
+       tlvs->protocols_supported.count = nlpids->count;
+       if (tlvs->protocols_supported.protocols)
+               XFREE(MTYPE_ISIS_TLV, tlvs->protocols_supported.protocols);
+       if (nlpids->count) {
+               tlvs->protocols_supported.protocols =
+                       XCALLOC(MTYPE_ISIS_TLV, nlpids->count);
+               memcpy(tlvs->protocols_supported.protocols, nlpids->nlpids,
+                      nlpids->count);
+       } else {
+               tlvs->protocols_supported.protocols = NULL;
+       }
+}
+
+void isis_tlvs_add_mt_router_info(struct isis_tlvs *tlvs, uint16_t mtid,
+                                 bool overload, bool attached)
+{
+       struct isis_mt_router_info *i = XCALLOC(MTYPE_ISIS_TLV, sizeof(*i));
+
+       i->overload = overload;
+       i->attached = attached;
+       i->mtid = mtid;
+       append_item(&tlvs->mt_router_info, (struct isis_item *)i);
+}
+
+void isis_tlvs_add_ipv4_address(struct isis_tlvs *tlvs, struct in_addr *addr)
+{
+       struct isis_ipv4_address *a = XCALLOC(MTYPE_ISIS_TLV, sizeof(*a));
+       a->addr = *addr;
+       append_item(&tlvs->ipv4_address, (struct isis_item *)a);
+}
+
+
+void isis_tlvs_add_ipv4_addresses(struct isis_tlvs *tlvs,
+                                 struct list *addresses)
+{
+       struct listnode *node;
+       struct prefix_ipv4 *ip_addr;
+       unsigned int addr_count = 0;
+
+       for (ALL_LIST_ELEMENTS_RO(addresses, node, ip_addr)) {
+               isis_tlvs_add_ipv4_address(tlvs, &ip_addr->prefix);
+               addr_count++;
+               if (addr_count >= 63)
+                       break;
+       }
+}
+
+void isis_tlvs_add_ipv6_addresses(struct isis_tlvs *tlvs,
+                                 struct list *addresses)
+{
+       struct listnode *node;
+       struct prefix_ipv6 *ip_addr;
+
+       for (ALL_LIST_ELEMENTS_RO(addresses, node, ip_addr)) {
+               struct isis_ipv6_address *a =
+                       XCALLOC(MTYPE_ISIS_TLV, sizeof(*a));
+
+               a->addr = ip_addr->prefix;
+               append_item(&tlvs->ipv6_address, (struct isis_item *)a);
+       }
+}
+
+typedef bool (*auth_validator_func)(struct isis_passwd *passwd,
+                                   struct stream *stream,
+                                   struct isis_auth *auth, bool is_lsp);
+
+static bool auth_validator_cleartxt(struct isis_passwd *passwd,
+                                   struct stream *stream,
+                                   struct isis_auth *auth, bool is_lsp)
+{
+       return (auth->length == passwd->len
+               && !memcmp(auth->value, passwd->passwd, passwd->len));
+}
+
+static bool auth_validator_hmac_md5(struct isis_passwd *passwd,
+                                   struct stream *stream,
+                                   struct isis_auth *auth, bool is_lsp)
+{
+       uint8_t digest[16];
+       uint16_t checksum;
+       uint16_t rem_lifetime;
+
+       if (is_lsp)
+               safe_auth_md5(stream, &checksum, &rem_lifetime);
+
+       memset(STREAM_DATA(stream) + auth->offset, 0, 16);
+       hmac_md5(STREAM_DATA(stream), stream_get_endp(stream), passwd->passwd,
+                passwd->len, digest);
+       memcpy(STREAM_DATA(stream) + auth->offset, auth->value, 16);
+
+       bool rv = !memcmp(digest, auth->value, 16);
+
+       if (is_lsp)
+               restore_auth_md5(stream, checksum, rem_lifetime);
+
+       return rv;
+}
+
+static const auth_validator_func auth_validators[] = {
+               [ISIS_PASSWD_TYPE_CLEARTXT] = auth_validator_cleartxt,
+               [ISIS_PASSWD_TYPE_HMAC_MD5] = auth_validator_hmac_md5,
+};
+
+bool isis_tlvs_auth_is_valid(struct isis_tlvs *tlvs, struct isis_passwd *passwd,
+                            struct stream *stream, bool is_lsp)
+{
+       /* If no auth is set, always pass authentication */
+       if (!passwd->type)
+               return true;
+
+       /* If we don't known how to validate the auth, return invalid */
+       if (passwd->type >= array_size(auth_validators)
+           || !auth_validators[passwd->type])
+               return false;
+
+       struct isis_auth *auth_head = (struct isis_auth *)tlvs->isis_auth.head;
+       struct isis_auth *auth;
+       for (auth = auth_head; auth; auth = auth->next) {
+               if (auth->type == passwd->type)
+                       break;
+       }
+
+       /* If matching auth TLV could not be found, return invalid */
+       if (!auth)
+               return false;
+
+       /* Perform validation and return result */
+       return auth_validators[passwd->type](passwd, stream, auth, is_lsp);
+}
+
+bool isis_tlvs_area_addresses_match(struct isis_tlvs *tlvs,
+                                   struct list *addresses)
+{
+       struct isis_area_address *addr_head;
+
+       addr_head = (struct isis_area_address *)tlvs->area_addresses.head;
+       for (struct isis_area_address *addr = addr_head; addr;
+            addr = addr->next) {
+               struct listnode *node;
+               struct area_addr *a;
+
+               for (ALL_LIST_ELEMENTS_RO(addresses, node, a)) {
+                       if (a->addr_len == addr->len
+                           && !memcmp(a->area_addr, addr->addr, addr->len))
+                               return true;
+               }
+       }
+
+       return false;
+}
+
+static void tlvs_area_addresses_to_adj(struct isis_tlvs *tlvs,
+                                      struct isis_adjacency *adj,
+                                      bool *changed)
+{
+       if (adj->area_address_count != tlvs->area_addresses.count) {
+               *changed = true;
+               adj->area_address_count = tlvs->area_addresses.count;
+               adj->area_addresses = XREALLOC(
+                       MTYPE_ISIS_ADJACENCY_INFO, adj->area_addresses,
+                       adj->area_address_count * sizeof(*adj->area_addresses));
+       }
+
+       struct isis_area_address *addr = NULL;
+       for (unsigned int i = 0; i < tlvs->area_addresses.count; i++) {
+               if (!addr)
+                       addr = (struct isis_area_address *)
+                                      tlvs->area_addresses.head;
+               else
+                       addr = addr->next;
+
+               if (adj->area_addresses[i].addr_len == addr->len
+                   && !memcmp(adj->area_addresses[i].area_addr, addr->addr,
+                              addr->len)) {
+                       continue;
+               }
+
+               *changed = true;
+               adj->area_addresses[i].addr_len = addr->len;
+               memcpy(adj->area_addresses[i].area_addr, addr->addr, addr->len);
+       }
+}
+
+static void tlvs_protocols_supported_to_adj(struct isis_tlvs *tlvs,
+                                           struct isis_adjacency *adj,
+                                           bool *changed)
+{
+       bool ipv4_supported = false, ipv6_supported = false;
+
+       for (uint8_t i = 0; i < tlvs->protocols_supported.count; i++) {
+               if (tlvs->protocols_supported.protocols[i] == NLPID_IP)
+                       ipv4_supported = true;
+               if (tlvs->protocols_supported.protocols[i] == NLPID_IPV6)
+                       ipv6_supported = true;
+       }
+
+       struct nlpids reduced = {};
+
+       if (ipv4_supported && ipv6_supported) {
+               reduced.count = 2;
+               reduced.nlpids[0] = NLPID_IP;
+               reduced.nlpids[1] = NLPID_IPV6;
+       } else if (ipv4_supported) {
+               reduced.count = 1;
+               reduced.nlpids[0] = NLPID_IP;
+       } else if (ipv6_supported) {
+               reduced.count = 1;
+               reduced.nlpids[1] = NLPID_IPV6;
+       } else {
+               reduced.count = 0;
+       }
+
+       if (adj->nlpids.count == reduced.count
+           && !memcmp(adj->nlpids.nlpids, reduced.nlpids, reduced.count))
+               return;
+
+       *changed = true;
+       adj->nlpids.count = reduced.count;
+       memcpy(adj->nlpids.nlpids, reduced.nlpids, reduced.count);
+}
+
+static void tlvs_ipv4_addresses_to_adj(struct isis_tlvs *tlvs,
+                                      struct isis_adjacency *adj,
+                                      bool *changed)
+{
+       if (adj->ipv4_address_count != tlvs->ipv4_address.count) {
+               *changed = true;
+               adj->ipv4_address_count = tlvs->ipv4_address.count;
+               adj->ipv4_addresses = XREALLOC(
+                       MTYPE_ISIS_ADJACENCY_INFO, adj->ipv4_addresses,
+                       adj->ipv4_address_count * sizeof(*adj->ipv4_addresses));
+       }
+
+       struct isis_ipv4_address *addr = NULL;
+       for (unsigned int i = 0; i < tlvs->ipv4_address.count; i++) {
+               if (!addr)
+                       addr = (struct isis_ipv4_address *)
+                                      tlvs->ipv4_address.head;
+               else
+                       addr = addr->next;
+
+               if (!memcmp(&adj->ipv4_addresses[i], &addr->addr,
+                           sizeof(addr->addr)))
+                       continue;
+
+               *changed = true;
+               adj->ipv4_addresses[i] = addr->addr;
+       }
+}
+
+static void tlvs_ipv6_addresses_to_adj(struct isis_tlvs *tlvs,
+                                      struct isis_adjacency *adj,
+                                      bool *changed)
+{
+       if (adj->ipv6_address_count != tlvs->ipv6_address.count) {
+               *changed = true;
+               adj->ipv6_address_count = tlvs->ipv6_address.count;
+               adj->ipv6_addresses = XREALLOC(
+                       MTYPE_ISIS_ADJACENCY_INFO, adj->ipv6_addresses,
+                       adj->ipv6_address_count * sizeof(*adj->ipv6_addresses));
+       }
+
+       struct isis_ipv6_address *addr = NULL;
+       for (unsigned int i = 0; i < tlvs->ipv6_address.count; i++) {
+               if (!addr)
+                       addr = (struct isis_ipv6_address *)
+                                      tlvs->ipv6_address.head;
+               else
+                       addr = addr->next;
+
+               if (!memcmp(&adj->ipv6_addresses[i], &addr->addr,
+                           sizeof(addr->addr)))
+                       continue;
+
+               *changed = true;
+               adj->ipv6_addresses[i] = addr->addr;
+       }
+}
+
+void isis_tlvs_to_adj(struct isis_tlvs *tlvs, struct isis_adjacency *adj,
+                     bool *changed)
+{
+       *changed = false;
+
+       tlvs_area_addresses_to_adj(tlvs, adj, changed);
+       tlvs_protocols_supported_to_adj(tlvs, adj, changed);
+       tlvs_ipv4_addresses_to_adj(tlvs, adj, changed);
+       tlvs_ipv6_addresses_to_adj(tlvs, adj, changed);
+}
+
+bool isis_tlvs_own_snpa_found(struct isis_tlvs *tlvs, uint8_t *snpa)
+{
+       struct isis_lan_neighbor *ne_head;
+
+       ne_head = (struct isis_lan_neighbor *)tlvs->lan_neighbor.head;
+       for (struct isis_lan_neighbor *ne = ne_head; ne; ne = ne->next) {
+               if (!memcmp(ne->mac, snpa, ETH_ALEN))
+                       return true;
+       }
+
+       return false;
+}
+
+void isis_tlvs_add_lsp_entry(struct isis_tlvs *tlvs, struct isis_lsp *lsp)
+{
+       struct isis_lsp_entry *entry = XCALLOC(MTYPE_ISIS_TLV, sizeof(*entry));
+
+       entry->rem_lifetime = lsp->hdr.rem_lifetime;
+       memcpy(entry->id, lsp->hdr.lsp_id, ISIS_SYS_ID_LEN + 2);
+       entry->checksum = lsp->hdr.checksum;
+       entry->seqno = lsp->hdr.seqno;
+       entry->lsp = lsp;
+
+       append_item(&tlvs->lsp_entries, (struct isis_item *)entry);
+}
+
+void isis_tlvs_add_csnp_entries(struct isis_tlvs *tlvs, uint8_t *start_id,
+                               uint8_t *stop_id, uint16_t num_lsps,
+                               dict_t *lspdb, struct isis_lsp **last_lsp)
+{
+       dnode_t *first = dict_lower_bound(lspdb, start_id);
+       if (!first)
+               return;
+
+       dnode_t *last = dict_upper_bound(lspdb, stop_id);
+       dnode_t *curr = first;
+
+       isis_tlvs_add_lsp_entry(tlvs, first->dict_data);
+       *last_lsp = first->dict_data;
+
+       while (curr) {
+               curr = dict_next(lspdb, curr);
+               if (curr) {
+                       isis_tlvs_add_lsp_entry(tlvs, curr->dict_data);
+                       *last_lsp = curr->dict_data;
+               }
+               if (curr == last || tlvs->lsp_entries.count == num_lsps)
+                       break;
+       }
+}
+
+void isis_tlvs_set_dynamic_hostname(struct isis_tlvs *tlvs,
+                                   const char *hostname)
+{
+       XFREE(MTYPE_ISIS_TLV, tlvs->hostname);
+       if (hostname)
+               tlvs->hostname = XSTRDUP(MTYPE_ISIS_TLV, hostname);
+}
+
+void isis_tlvs_set_te_router_id(struct isis_tlvs *tlvs,
+                               const struct in_addr *id)
+{
+       XFREE(MTYPE_ISIS_TLV, tlvs->te_router_id);
+       if (!id)
+               return;
+       tlvs->te_router_id = XCALLOC(MTYPE_ISIS_TLV, sizeof(*id));
+       memcpy(tlvs->te_router_id, id, sizeof(*id));
+}
+
+void isis_tlvs_add_oldstyle_ip_reach(struct isis_tlvs *tlvs,
+                                    struct prefix_ipv4 *dest, uint8_t metric)
+{
+       struct isis_oldstyle_ip_reach *r = XCALLOC(MTYPE_ISIS_TLV, sizeof(*r));
+
+       r->metric = metric;
+       memcpy(&r->prefix, dest, sizeof(*dest));
+       apply_mask_ipv4(&r->prefix);
+       append_item(&tlvs->oldstyle_ip_reach, (struct isis_item *)r);
+}
+
+void isis_tlvs_add_extended_ip_reach(struct isis_tlvs *tlvs,
+                                    struct prefix_ipv4 *dest, uint32_t metric)
+{
+       struct isis_extended_ip_reach *r = XCALLOC(MTYPE_ISIS_TLV, sizeof(*r));
+
+       r->metric = metric;
+       memcpy(&r->prefix, dest, sizeof(*dest));
+       apply_mask_ipv4(&r->prefix);
+       append_item(&tlvs->extended_ip_reach, (struct isis_item *)r);
+}
+
+void isis_tlvs_add_ipv6_reach(struct isis_tlvs *tlvs, uint16_t mtid,
+                             struct prefix_ipv6 *dest, uint32_t metric)
+{
+       struct isis_ipv6_reach *r = XCALLOC(MTYPE_ISIS_TLV, sizeof(*r));
+
+       r->metric = metric;
+       memcpy(&r->prefix, dest, sizeof(*dest));
+       apply_mask_ipv6(&r->prefix);
+
+       struct isis_item_list *l;
+       l = (mtid == ISIS_MT_IPV4_UNICAST)
+                   ? &tlvs->ipv6_reach
+                   : isis_get_mt_items(&tlvs->mt_ipv6_reach, mtid);
+       append_item(l, (struct isis_item *)r);
+}
+
+void isis_tlvs_add_oldstyle_reach(struct isis_tlvs *tlvs, uint8_t *id,
+                                 uint8_t metric)
+{
+       struct isis_oldstyle_reach *r = XCALLOC(MTYPE_ISIS_TLV, sizeof(*r));
+
+       r->metric = metric;
+       memcpy(r->id, id, sizeof(r->id));
+       append_item(&tlvs->oldstyle_reach, (struct isis_item *)r);
+}
+
+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_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;
+       }
+
+       struct isis_item_list *l;
+       if (mtid == ISIS_MT_IPV4_UNICAST)
+               l = &tlvs->extended_reach;
+       else
+               l = isis_get_mt_items(&tlvs->mt_reach, mtid);
+       append_item(l, (struct isis_item *)r);
+}
+
+struct isis_mt_router_info *
+isis_tlvs_lookup_mt_router_info(struct isis_tlvs *tlvs, uint16_t mtid)
+{
+       if (tlvs->mt_router_info_empty)
+               return NULL;
+
+       struct isis_mt_router_info *rv;
+       for (rv = (struct isis_mt_router_info *)tlvs->mt_router_info.head; rv;
+            rv = rv->next) {
+               if (rv->mtid == mtid)
+                       return rv;
+       }
+
+       return NULL;
+}
diff --git a/isisd/isis_tlvs.h b/isisd/isis_tlvs.h
new file mode 100644 (file)
index 0000000..6ade0af
--- /dev/null
@@ -0,0 +1,308 @@
+/*
+ * IS-IS TLV Serializer/Deserializer
+ *
+ * Copyright (C) 2015,2017 Christian Franke
+ *
+ * This file is part of FRR.
+ *
+ * FRR is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * FRR is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with FRR; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+#ifndef ISIS_TLVS_H
+#define ISIS_TLVS_H
+
+#include "openbsd-tree.h"
+#include "prefix.h"
+#include "isisd/dict.h"
+
+struct isis_subtlvs;
+
+struct isis_area_address;
+struct isis_area_address {
+       struct isis_area_address *next;
+
+       uint8_t addr[20];
+       uint8_t len;
+};
+
+struct isis_oldstyle_reach;
+struct isis_oldstyle_reach {
+       struct isis_oldstyle_reach *next;
+
+       uint8_t id[7];
+       uint8_t metric;
+};
+
+struct isis_oldstyle_ip_reach;
+struct isis_oldstyle_ip_reach {
+       struct isis_oldstyle_ip_reach *next;
+
+       uint8_t metric;
+       struct prefix_ipv4 prefix;
+};
+
+struct isis_lsp_entry;
+struct isis_lsp_entry {
+       struct isis_lsp_entry *next;
+
+       uint16_t rem_lifetime;
+       uint8_t id[8];
+       uint16_t checksum;
+       uint32_t seqno;
+
+       struct isis_lsp *lsp;
+};
+
+struct isis_extended_reach;
+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_extended_ip_reach;
+struct isis_extended_ip_reach {
+       struct isis_extended_ip_reach *next;
+
+       uint32_t metric;
+       bool down;
+       struct prefix_ipv4 prefix;
+};
+
+struct isis_ipv6_reach;
+struct isis_ipv6_reach {
+       struct isis_ipv6_reach *next;
+
+       uint32_t metric;
+       bool down;
+       bool external;
+
+       struct prefix_ipv6 prefix;
+
+       struct isis_subtlvs *subtlvs;
+};
+
+struct isis_protocols_supported {
+       uint8_t count;
+       uint8_t *protocols;
+};
+
+struct isis_item;
+struct isis_item {
+       struct isis_item *next;
+};
+
+struct isis_lan_neighbor;
+struct isis_lan_neighbor {
+       struct isis_lan_neighbor *next;
+
+       uint8_t mac[6];
+};
+
+struct isis_ipv4_address;
+struct isis_ipv4_address {
+       struct isis_ipv4_address *next;
+
+       struct in_addr addr;
+};
+
+struct isis_ipv6_address;
+struct isis_ipv6_address {
+       struct isis_ipv6_address *next;
+
+       struct in6_addr addr;
+};
+
+struct isis_mt_router_info;
+struct isis_mt_router_info {
+       struct isis_mt_router_info *next;
+
+       bool overload;
+       bool attached;
+       uint16_t mtid;
+};
+
+struct isis_auth;
+struct isis_auth {
+       struct isis_auth *next;
+
+       uint8_t type;
+       uint8_t length;
+       uint8_t value[256];
+
+       uint8_t plength;
+       uint8_t passwd[256];
+
+       size_t offset; /* Only valid after packing */
+};
+
+struct isis_item_list;
+struct isis_item_list {
+       struct isis_item *head;
+       struct isis_item **tail;
+
+       RB_ENTRY(isis_item_list) mt_tree;
+       uint16_t mtid;
+       unsigned int count;
+};
+
+RB_HEAD(isis_mt_item_list, isis_item_list);
+
+struct isis_item_list *isis_get_mt_items(struct isis_mt_item_list *m,
+                                        uint16_t mtid);
+struct isis_item_list *isis_lookup_mt_items(struct isis_mt_item_list *m,
+                                           uint16_t mtid);
+
+struct isis_tlvs {
+       struct isis_item_list isis_auth;
+       struct isis_item_list area_addresses;
+       struct isis_item_list oldstyle_reach;
+       struct isis_item_list lan_neighbor;
+       struct isis_item_list lsp_entries;
+       struct isis_item_list extended_reach;
+       struct isis_mt_item_list mt_reach;
+       struct isis_item_list oldstyle_ip_reach;
+       struct isis_protocols_supported protocols_supported;
+       struct isis_item_list oldstyle_ip_reach_ext;
+       struct isis_item_list ipv4_address;
+       struct isis_item_list ipv6_address;
+       struct isis_item_list mt_router_info;
+       bool mt_router_info_empty;
+       struct in_addr *te_router_id;
+       struct isis_item_list extended_ip_reach;
+       struct isis_mt_item_list mt_ip_reach;
+       char *hostname;
+       struct isis_item_list ipv6_reach;
+       struct isis_mt_item_list mt_ipv6_reach;
+};
+
+struct isis_subtlvs {
+       /* draft-baker-ipv6-isis-dst-src-routing-06 */
+       struct prefix_ipv6 *source_prefix;
+};
+
+enum isis_tlv_context {
+       ISIS_CONTEXT_LSP,
+       ISIS_CONTEXT_SUBTLV_NE_REACH,
+       ISIS_CONTEXT_SUBTLV_IP_REACH,
+       ISIS_CONTEXT_SUBTLV_IPV6_REACH,
+       ISIS_CONTEXT_MAX
+};
+
+enum isis_tlv_type {
+       ISIS_TLV_AREA_ADDRESSES = 1,
+       ISIS_TLV_OLDSTYLE_REACH = 2,
+       ISIS_TLV_LAN_NEIGHBORS = 6,
+       ISIS_TLV_PADDING = 8,
+       ISIS_TLV_LSP_ENTRY = 9,
+       ISIS_TLV_AUTH = 10,
+       ISIS_TLV_EXTENDED_REACH = 22,
+
+       ISIS_TLV_OLDSTYLE_IP_REACH = 128,
+       ISIS_TLV_PROTOCOLS_SUPPORTED = 129,
+       ISIS_TLV_OLDSTYLE_IP_REACH_EXT = 130,
+       ISIS_TLV_IPV4_ADDRESS = 132,
+       ISIS_TLV_TE_ROUTER_ID = 134,
+       ISIS_TLV_EXTENDED_IP_REACH = 135,
+       ISIS_TLV_DYNAMIC_HOSTNAME = 137,
+       ISIS_TLV_MT_REACH = 222,
+       ISIS_TLV_MT_ROUTER_INFO = 229,
+       ISIS_TLV_IPV6_ADDRESS = 232,
+       ISIS_TLV_MT_IP_REACH = 235,
+       ISIS_TLV_IPV6_REACH = 236,
+       ISIS_TLV_MT_IPV6_REACH = 237,
+       ISIS_TLV_MAX = 256,
+
+       ISIS_SUBTLV_IPV6_SOURCE_PREFIX = 22
+};
+
+#define IS_COMPAT_MT_TLV(tlv_type)                                             \
+       ((tlv_type == ISIS_TLV_MT_REACH) || (tlv_type == ISIS_TLV_MT_IP_REACH) \
+        || (tlv_type == ISIS_TLV_MT_IPV6_REACH))
+
+struct stream;
+int isis_pack_tlvs(struct isis_tlvs *tlvs, struct stream *stream,
+                  size_t len_pointer, bool pad, bool is_lsp);
+void isis_free_tlvs(struct isis_tlvs *tlvs);
+struct isis_tlvs *isis_alloc_tlvs(void);
+int isis_unpack_tlvs(size_t avail_len, struct stream *stream,
+                    struct isis_tlvs **dest, const char **error_log);
+const char *isis_format_tlvs(struct isis_tlvs *tlvs);
+struct isis_tlvs *isis_copy_tlvs(struct isis_tlvs *tlvs);
+struct list *isis_fragment_tlvs(struct isis_tlvs *tlvs, size_t size);
+
+#define ISIS_EXTENDED_IP_REACH_DOWN 0x80
+#define ISIS_EXTENDED_IP_REACH_SUBTLV 0x40
+
+#define ISIS_IPV6_REACH_DOWN 0x80
+#define ISIS_IPV6_REACH_EXTERNAL 0x40
+#define ISIS_IPV6_REACH_SUBTLV 0x20
+
+#ifndef ISIS_MT_MASK
+#define ISIS_MT_MASK           0x0fff
+#define ISIS_MT_OL_MASK        0x8000
+#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);
+void isis_tlvs_add_lan_neighbors(struct isis_tlvs *tlvs,
+                                struct list *neighbors);
+void isis_tlvs_set_protocols_supported(struct isis_tlvs *tlvs,
+                                      struct nlpids *nlpids);
+void isis_tlvs_add_mt_router_info(struct isis_tlvs *tlvs, uint16_t mtid,
+                                 bool overload, bool attached);
+void isis_tlvs_add_ipv4_address(struct isis_tlvs *tlvs, struct in_addr *addr);
+void isis_tlvs_add_ipv4_addresses(struct isis_tlvs *tlvs,
+                                 struct list *addresses);
+void isis_tlvs_add_ipv6_addresses(struct isis_tlvs *tlvs,
+                                 struct list *addresses);
+bool isis_tlvs_auth_is_valid(struct isis_tlvs *tlvs, struct isis_passwd *passwd,
+                            struct stream *stream, bool is_lsp);
+bool isis_tlvs_area_addresses_match(struct isis_tlvs *tlvs,
+                                   struct list *addresses);
+struct isis_adjacency;
+void isis_tlvs_to_adj(struct isis_tlvs *tlvs, struct isis_adjacency *adj,
+                     bool *changed);
+bool isis_tlvs_own_snpa_found(struct isis_tlvs *tlvs, uint8_t *snpa);
+void isis_tlvs_add_lsp_entry(struct isis_tlvs *tlvs, struct isis_lsp *lsp);
+void isis_tlvs_add_csnp_entries(struct isis_tlvs *tlvs, uint8_t *start_id,
+                               uint8_t *stop_id, uint16_t num_lsps,
+                               dict_t *lspdb, struct isis_lsp **last_lsp);
+void isis_tlvs_set_dynamic_hostname(struct isis_tlvs *tlvs,
+                                   const char *hostname);
+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,
+                                    struct prefix_ipv4 *dest, uint8_t metric);
+void isis_tlvs_add_extended_ip_reach(struct isis_tlvs *tlvs,
+                                    struct prefix_ipv4 *dest, uint32_t metric);
+void isis_tlvs_add_ipv6_reach(struct isis_tlvs *tlvs, uint16_t mtid,
+                             struct prefix_ipv6 *dest, uint32_t metric);
+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_mt_router_info *
+isis_tlvs_lookup_mt_router_info(struct isis_tlvs *tlvs, uint16_t mtid);
+#endif
index 18a59d1fc5ac2f244bbc14dee726574b8bc653a8..8c6968f8ececb27686c963de912b9c8776dd171d 100644 (file)
@@ -42,7 +42,6 @@
 #include "isisd/isis_flags.h"
 #include "isisd/isis_misc.h"
 #include "isisd/isis_circuit.h"
-#include "isisd/isis_tlv.h"
 #include "isisd/isisd.h"
 #include "isisd/isis_circuit.h"
 #include "isisd/isis_csm.h"
index 8bbb5cf94909e54b01b9947fd5ba0fb3d47df3b5..60b9367da9907baf0cb3dedd82cc19d232e21c63 100644 (file)
@@ -49,7 +49,6 @@
 #include "isisd/isis_pdu.h"
 #include "isisd/isis_misc.h"
 #include "isisd/isis_constants.h"
-#include "isisd/isis_tlv.h"
 #include "isisd/isis_lsp.h"
 #include "isisd/isis_spf.h"
 #include "isisd/isis_route.h"
@@ -1232,27 +1231,6 @@ DEFUN (show_hostname,
        return CMD_SUCCESS;
 }
 
-static void vty_out_timestr(struct vty *vty, time_t uptime)
-{
-       struct tm *tm;
-       time_t difftime = time(NULL);
-       difftime -= uptime;
-       tm = gmtime(&difftime);
-
-#define ONE_DAY_SECOND 60*60*24
-#define ONE_WEEK_SECOND 60*60*24*7
-       if (difftime < ONE_DAY_SECOND)
-               vty_out(vty, "%02d:%02d:%02d", tm->tm_hour, tm->tm_min,
-                       tm->tm_sec);
-       else if (difftime < ONE_WEEK_SECOND)
-               vty_out(vty, "%dd%02dh%02dm", tm->tm_yday, tm->tm_hour,
-                       tm->tm_min);
-       else
-               vty_out(vty, "%02dw%dd%02dh", tm->tm_yday / 7,
-                       tm->tm_yday - ((tm->tm_yday / 7) * 7), tm->tm_hour);
-       vty_out(vty, " ago");
-}
-
 DEFUN (show_isis_spf_ietf,
        show_isis_spf_ietf_cmd,
        "show isis spf-delay-ietf",
@@ -1309,7 +1287,6 @@ DEFUN (show_isis_summary,
 {
        struct listnode *node, *node2;
        struct isis_area *area;
-       struct isis_spftree *spftree;
        int level;
 
        if (isis == NULL) {
@@ -1350,7 +1327,6 @@ DEFUN (show_isis_summary,
                                continue;
 
                        vty_out(vty, "  Level-%d:\n", level);
-                       spftree = area->spftree[level - 1];
                        if (area->spf_timer[level - 1])
                                vty_out(vty, "    SPF: (pending)\n");
                        else
@@ -1364,28 +1340,10 @@ DEFUN (show_isis_summary,
                        vty_out(vty, "\n");
 
                        vty_out(vty, "    IPv4 route computation:\n");
-                       vty_out(vty, "      last run elapsed  : ");
-                       vty_out_timestr(vty, spftree->last_run_timestamp);
-                       vty_out(vty, "\n");
+                       isis_spf_print(area->spftree[level - 1], vty);
 
-                       vty_out(vty, "      last run duration : %u usec\n",
-                               (u_int32_t)spftree->last_run_duration);
-
-                       vty_out(vty, "      run count         : %d\n",
-                               spftree->runcount);
-
-                       spftree = area->spftree6[level - 1];
                        vty_out(vty, "    IPv6 route computation:\n");
-
-                       vty_out(vty, "      last run elapsed  : ");
-                       vty_out_timestr(vty, spftree->last_run_timestamp);
-                       vty_out(vty, "\n");
-
-                       vty_out(vty, "      last run duration : %llu msec\n",
-                               (unsigned long long)spftree->last_run_duration);
-
-                       vty_out(vty, "      run count         : %d\n",
-                               spftree->runcount);
+                       isis_spf_print(area->spftree6[level - 1], vty);
                }
        }
        vty_out(vty, "\n");
index 1aacea881f6efc9dd4010ff04a2961e5798119eb..da02854f5c4d678e89feb2b5bf52e5c2d925f2b8 100644 (file)
@@ -37,7 +37,7 @@
 
 /* uncomment if you are a developer in bug hunt */
 /* #define EXTREME_DEBUG  */
-/* #define EXTREME_TLV_DEBUG */
+/* #define EXTREME_DICT_DEBUG */
 
 struct isis {
        u_long process_id;
index e0a4ba3700530a0cdd7c25c2282aa960bf04daa1..25a870991a9a22c4abaf781ddbc428483c7d3e5a 100644 (file)
@@ -67,7 +67,7 @@ int iso_csum_verify(u_char *buffer, int len, uint16_t csum, int offset)
                return 1;
 
        checksum = fletcher_checksum(buffer, len, offset);
-       if (checksum == csum)
+       if (checksum == htons(csum))
                return 0;
        return 1;
 }
index 584240de8495514150703b1029a9f3e21810307a..18ab03776057279d1d91b468787b53eabb3668ce 100644 (file)
@@ -160,7 +160,7 @@ send_mac_withdrawal(struct nbr *nbr, struct map *fec, uint8_t *mac)
        size = LDP_HDR_SIZE + LDP_MSG_SIZE + ADDR_LIST_SIZE + len_fec_tlv(fec) +
            TLV_HDR_SIZE;
        if (mac)
-               size += ETHER_ADDR_LEN;
+               size += ETH_ALEN;
 
        if ((buf = ibuf_open(size)) == NULL)
                fatal(__func__);
@@ -372,10 +372,10 @@ gen_mac_list_tlv(struct ibuf *buf, uint8_t *mac)
        memset(&tlv, 0, sizeof(tlv));
        tlv.type = htons(TLV_TYPE_MAC_LIST);
        if (mac)
-               tlv.length = htons(ETHER_ADDR_LEN);
+               tlv.length = htons(ETH_ALEN);
        err = ibuf_add(buf, &tlv, sizeof(tlv));
        if (mac)
-               err |= ibuf_add(buf, mac, ETHER_ADDR_LEN);
+               err |= ibuf_add(buf, mac, ETH_ALEN);
 
        return (err);
 }
index f15461d3d2b0176d0f4f1bc6ff603a71b82d85bd..9bad503b9c815f47a4294cdcff48d97394ae69ac 100644 (file)
@@ -235,6 +235,7 @@ void
 l2vpn_pw_init(struct l2vpn_pw *pw)
 {
        struct fec       fec;
+       struct zapi_pw   zpw;
 
        l2vpn_pw_reset(pw);
 
@@ -242,16 +243,23 @@ l2vpn_pw_init(struct l2vpn_pw *pw)
        lde_kernel_insert(&fec, AF_INET, (union ldpd_addr*)&pw->lsr_id, 0, 0,
            0, (void *)pw);
        lde_kernel_update(&fec);
+
+       pw2zpw(pw, &zpw);
+       lde_imsg_compose_parent(IMSG_KPW_ADD, 0, &zpw, sizeof(zpw));
 }
 
 void
 l2vpn_pw_exit(struct l2vpn_pw *pw)
 {
        struct fec       fec;
+       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_update(&fec);
+
+       pw2zpw(pw, &zpw);
+       lde_imsg_compose_parent(IMSG_KPW_DELETE, 0, &zpw, sizeof(zpw));
 }
 
 static void
@@ -269,7 +277,8 @@ l2vpn_pw_reset(struct l2vpn_pw *pw)
 {
        pw->remote_group = 0;
        pw->remote_mtu = 0;
-       pw->remote_status = 0;
+       pw->local_status = PW_FORWARDING;
+       pw->remote_status = PW_NOT_FORWARDING;
 
        if (pw->flags & F_PW_CWORD_CONF)
                pw->flags |= F_PW_CWORD;
@@ -475,6 +484,56 @@ l2vpn_recv_pw_status_wcard(struct lde_nbr *ln, struct notify_msg *nm)
        }
 }
 
+int
+l2vpn_pw_status_update(struct zapi_pw_status *zpw)
+{
+       struct l2vpn            *l2vpn;
+       struct l2vpn_pw         *pw = NULL;
+       struct lde_nbr          *ln;
+       struct fec               fec;
+       uint32_t                 local_status;
+
+       RB_FOREACH(l2vpn, l2vpn_head, &ldeconf->l2vpn_tree) {
+               pw = l2vpn_pw_find(l2vpn, zpw->ifname);
+               if (pw)
+                       break;
+       }
+       if (!pw) {
+               log_warnx("%s: pseudowire %s not found", __func__, zpw->ifname);
+               return (1);
+       }
+
+       if (zpw->status == PW_STATUS_UP)
+               local_status = PW_FORWARDING;
+       else
+               local_status = PW_NOT_FORWARDING;
+
+       /* local status didn't change */
+       if (pw->local_status == local_status)
+               return (0);
+       pw->local_status = local_status;
+
+       /* notify remote peer about the status update */
+       ln = lde_nbr_find_by_lsrid(pw->lsr_id);
+       if (ln == NULL)
+               return (0);
+       l2vpn_pw_fec(pw, &fec);
+       if (pw->flags & F_PW_STATUSTLV)
+               l2vpn_send_pw_status(ln, local_status, &fec);
+       else {
+               struct fec_node *fn;
+               fn = (struct fec_node *)fec_find(&ft, &fec);
+               if (fn) {
+                       if (pw->local_status == PW_FORWARDING)
+                               lde_send_labelmapping(ln, fn, 1);
+                       else
+                               lde_send_labelwithdraw(ln, fn, NULL, NULL);
+               }
+       }
+
+       return (0);
+}
+
 void
 l2vpn_pw_ctl(pid_t pid)
 {
@@ -491,7 +550,9 @@ l2vpn_pw_ctl(pid_t pid)
                            sizeof(pwctl.ifname));
                        pwctl.pwid = pw->pwid;
                        pwctl.lsr_id = pw->lsr_id;
-                       pwctl.status = pw->flags & F_PW_STATUS_UP;
+                       if (pw->local_status == PW_FORWARDING &&
+                           pw->remote_status == PW_FORWARDING)
+                               pwctl.status = 1;
 
                        lde_imsg_compose_ldpe(IMSG_CTL_SHOW_L2VPN_PW, 0,
                            pid, &pwctl, sizeof(pwctl));
index 77643ff48bbad3ca037925dcd020cfe35faa7309..588ccd695272984d9a1d8d32d845dfb0d1cea8f9 100644 (file)
@@ -472,6 +472,15 @@ lde_dispatch_parent(struct thread *thread)
                                }
                        }
                        break;
+               case IMSG_PW_UPDATE:
+                       if (imsg.hdr.len != IMSG_HEADER_SIZE +
+                           sizeof(struct zapi_pw_status))
+                               fatalx("PW_UPDATE imsg with wrong len");
+
+                       if (l2vpn_pw_status_update(imsg.data) != 0)
+                               log_warnx("%s: error updating PW status",
+                                   __func__);
+                       break;
                case IMSG_NETWORK_ADD:
                case IMSG_NETWORK_UPDATE:
                        if (imsg.hdr.len != IMSG_HEADER_SIZE +
@@ -712,8 +721,8 @@ lde_update_label(struct fec_node *fn)
 void
 lde_send_change_klabel(struct fec_node *fn, struct fec_nh *fnh)
 {
-       struct kroute   kr;
-       struct kpw      kpw;
+       struct kroute    kr;
+       struct zapi_pw   zpw;
        struct l2vpn_pw *pw;
 
        switch (fn->fec.type) {
@@ -751,19 +760,10 @@ lde_send_change_klabel(struct fec_node *fn, struct fec_nh *fnh)
                        return;
 
                pw = (struct l2vpn_pw *) fn->data;
-               pw->flags |= F_PW_STATUS_UP;
-
-               memset(&kpw, 0, sizeof(kpw));
-               kpw.ifindex = pw->ifindex;
-               kpw.pw_type = fn->fec.u.pwid.type;
-               kpw.af = pw->af;
-               kpw.nexthop = pw->addr;
-               kpw.local_label = fn->local_label;
-               kpw.remote_label = fnh->remote_label;
-               kpw.flags = pw->flags;
-
-               lde_imsg_compose_parent(IMSG_KPWLABEL_CHANGE, 0, &kpw,
-                   sizeof(kpw));
+               pw2zpw(pw, &zpw);
+               zpw.local_label = fn->local_label;
+               zpw.remote_label = fnh->remote_label;
+               lde_imsg_compose_parent(IMSG_KPW_SET, 0, &zpw, sizeof(zpw));
                break;
        }
 }
@@ -772,7 +772,7 @@ void
 lde_send_delete_klabel(struct fec_node *fn, struct fec_nh *fnh)
 {
        struct kroute    kr;
-       struct kpw       kpw;
+       struct zapi_pw   zpw;
        struct l2vpn_pw *pw;
 
        switch (fn->fec.type) {
@@ -806,21 +806,10 @@ lde_send_delete_klabel(struct fec_node *fn, struct fec_nh *fnh)
                break;
        case FEC_TYPE_PWID:
                pw = (struct l2vpn_pw *) fn->data;
-               if (!(pw->flags & F_PW_STATUS_UP))
-                       return;
-               pw->flags &= ~F_PW_STATUS_UP;
-
-               memset(&kpw, 0, sizeof(kpw));
-               kpw.ifindex = pw->ifindex;
-               kpw.pw_type = fn->fec.u.pwid.type;
-               kpw.af = pw->af;
-               kpw.nexthop = pw->addr;
-               kpw.local_label = fn->local_label;
-               kpw.remote_label = fnh->remote_label;
-               kpw.flags = pw->flags;
-
-               lde_imsg_compose_parent(IMSG_KPWLABEL_DELETE, 0, &kpw,
-                   sizeof(kpw));
+               pw2zpw(pw, &zpw);
+               zpw.local_label = fn->local_label;
+               zpw.remote_label = fnh->remote_label;
+               lde_imsg_compose_parent(IMSG_KPW_UNSET, 0, &zpw, sizeof(zpw));
                break;
        }
 }
@@ -901,8 +890,12 @@ lde_send_labelmapping(struct lde_nbr *ln, struct fec_node *fn, int single)
         */
        lw = (struct lde_wdraw *)fec_find(&ln->sent_wdraw, &fn->fec);
        if (lw) {
-               if (!fec_find(&ln->sent_map_pending, &fn->fec))
+               if (!fec_find(&ln->sent_map_pending, &fn->fec)) {
+                       debug_evt("%s: FEC %s: scheduling to send label "
+                           "mapping later (waiting for pending label release)",
+                           __func__, log_fec(&fn->fec));
                        lde_map_pending_add(ln, fn);
+               }
                return;
        }
 
@@ -948,8 +941,7 @@ lde_send_labelmapping(struct lde_nbr *ln, struct fec_node *fn, int single)
                        map.flags |= F_MAP_PW_CWORD;
                if (pw->flags & F_PW_STATUSTLV) {
                        map.flags |= F_MAP_PW_STATUS;
-                       /* VPLS are always up */
-                       map.pw_status = PW_FORWARDING;
+                       map.pw_status = pw->local_status;
                }
                break;
        }
index 1cce483832d19283e81a1466f5d2530259faedf1..43f1d36481767029d997a91d2c221f6b96a821b8 100644 (file)
@@ -238,6 +238,7 @@ void                 l2vpn_send_pw_status_wcard(struct lde_nbr *, uint32_t,
 void            l2vpn_recv_pw_status(struct lde_nbr *, struct notify_msg *);
 void            l2vpn_recv_pw_status_wcard(struct lde_nbr *,
                    struct notify_msg *);
+int             l2vpn_pw_status_update(struct zapi_pw_status *);
 void            l2vpn_pw_ctl(pid_t);
 void            l2vpn_binding_ctl(pid_t);
 
index edf686537fdd5cb37832d501e4cef7f7a19838fe..c56b7e33d096c56acddc49719fe99eb0915aceb1 100644 (file)
@@ -396,8 +396,7 @@ lde_kernel_update(struct fec *fec)
                lde_gc_start_timer();
        } else {
                fn->local_label = lde_update_label(fn);
-               if (fn->local_label != NO_LABEL &&
-                   RB_EMPTY(lde_map_head, &fn->upstream))
+               if (fn->local_label != NO_LABEL)
                        /* FEC.1: perform lsr label distribution procedure */
                        RB_FOREACH(ln, nbr_tree, &lde_nbrs)
                                lde_send_labelmapping(ln, fn, 1);
@@ -531,6 +530,8 @@ lde_check_mapping(struct map *map, struct lde_nbr *ln)
                                pw->remote_mtu = map->fec.pwid.ifmtu;
                        if (map->flags & F_MAP_PW_STATUS)
                                pw->remote_status = map->pw_status;
+                       else
+                               pw->remote_status = PW_FORWARDING;
                        fnh->remote_label = map->label;
                        if (l2vpn_pw_ok(pw, fnh))
                                lde_send_change_klabel(fn, fnh);
@@ -774,6 +775,7 @@ lde_check_withdraw(struct map *map, struct lde_nbr *ln)
                        pw = (struct l2vpn_pw *) fn->data;
                        if (pw == NULL)
                                continue;
+                       pw->remote_status = PW_NOT_FORWARDING;
                        break;
                default:
                        break;
@@ -802,6 +804,7 @@ lde_check_withdraw_wcard(struct map *map, struct lde_nbr *ln)
        struct fec_node *fn;
        struct fec_nh   *fnh;
        struct lde_map  *me;
+       struct l2vpn_pw *pw;
 
        /* LWd.2: send label release */
        lde_send_labelrelease(ln, NULL, map, map->label);
@@ -825,6 +828,9 @@ lde_check_withdraw_wcard(struct map *map, struct lde_nbr *ln)
                        case FEC_TYPE_PWID:
                                if (f->u.pwid.lsr_id.s_addr != ln->id.s_addr)
                                        continue;
+                               pw = (struct l2vpn_pw *) fn->data;
+                               if (pw)
+                                       pw->remote_status = PW_NOT_FORWARDING;
                                break;
                        default:
                                break;
index c2b64d20c67458cb9f413df9157ecfcb1edc62a4..cac3da7c55d0259a5310e6e92cc9b30f294dfd61 100644 (file)
@@ -285,9 +285,6 @@ struct address_list_tlv {
 #define        MAP_TYPE_GENPWID        0x81
 
 #define CONTROL_WORD_FLAG      0x8000
-#define PW_TYPE_ETHERNET_TAGGED        0x0004
-#define PW_TYPE_ETHERNET       0x0005
-#define PW_TYPE_WILDCARD       0x7FFF
 #define DEFAULT_PW_TYPE                PW_TYPE_ETHERNET
 
 #define PW_TWCARD_RESERVED_BIT 0x8000
index 7da76185c636cf8662ffd4ca6c55622f2798faa9..3f39ad926c085d622e91edec219ced9ca2433cd5 100644 (file)
@@ -37,7 +37,7 @@ DEFUN_NOSH(ldp_mpls_ldp,
 DEFPY  (no_ldp_mpls_ldp,
        no_ldp_mpls_ldp_cmd,
        "no mpls ldp",
-       "Negate a command or set its defaults\n"
+       NO_STR
        "Global MPLS configuration subcommands\n"
        "Label Distribution Protocol\n")
 {
@@ -64,7 +64,7 @@ DEFUN_NOSH(ldp_l2vpn,
 DEFPY  (no_ldp_l2vpn,
        no_ldp_l2vpn_cmd,
        "no l2vpn WORD$l2vpn_name type vpls",
-       "Negate a command or set its defaults\n"
+       NO_STR
        "Configure l2vpn commands\n"
        "L2VPN name\n"
        "L2VPN type\n"
@@ -92,7 +92,7 @@ DEFUN_NOSH(ldp_address_family,
 DEFPY  (no_ldp_address_family,
        no_ldp_address_family_cmd,
        "no address-family <ipv4|ipv6>$af",
-       "Negate a command or set its defaults\n"
+       NO_STR
        "Configure Address Family and its parameters\n"
        "IPv4\n"
        "IPv6\n")
@@ -113,7 +113,7 @@ DEFUN_NOSH(ldp_exit_address_family,
 DEFPY  (ldp_discovery_holdtime,
        ldp_discovery_holdtime_cmd,
        "[no] discovery <hello|targeted-hello>$hello_type holdtime (1-65535)$holdtime",
-       "Negate a command or set its defaults\n"
+       NO_STR
        "Configure discovery parameters\n"
        "LDP Link Hellos\n"
        "LDP Targeted Hellos\n"
@@ -126,7 +126,7 @@ DEFPY  (ldp_discovery_holdtime,
 DEFPY  (ldp_discovery_interval,
        ldp_discovery_interval_cmd,
        "[no] discovery <hello|targeted-hello>$hello_type interval (1-65535)$interval",
-       "Negate a command or set its defaults\n"
+       NO_STR
        "Configure discovery parameters\n"
        "LDP Link Hellos\n"
        "LDP Targeted Hellos\n"
@@ -139,7 +139,7 @@ DEFPY  (ldp_discovery_interval,
 DEFPY  (ldp_dual_stack_transport_connection_prefer_ipv4,
        ldp_dual_stack_transport_connection_prefer_ipv4_cmd,
        "[no] dual-stack transport-connection prefer ipv4",
-       "Negate a command or set its defaults\n"
+       NO_STR
        "Configure dual stack parameters\n"
        "Configure TCP transport parameters\n"
        "Configure prefered address family for TCP transport connection with neighbor\n"
@@ -151,7 +151,7 @@ DEFPY  (ldp_dual_stack_transport_connection_prefer_ipv4,
 DEFPY  (ldp_dual_stack_cisco_interop,
        ldp_dual_stack_cisco_interop_cmd,
        "[no] dual-stack cisco-interop",
-       "Negate a command or set its defaults\n"
+       NO_STR
        "Configure dual stack parameters\n"
        "Use Cisco non-compliant format to send and interpret the Dual-Stack capability TLV\n")
 {
@@ -161,7 +161,7 @@ DEFPY  (ldp_dual_stack_cisco_interop,
 DEFPY  (ldp_neighbor_password,
        ldp_neighbor_password_cmd,
        "[no] neighbor A.B.C.D$neighbor password WORD$password",
-       "Negate a command or set its defaults\n"
+       NO_STR
        "Configure neighbor parameters\n"
        "LDP Id of neighbor\n"
        "Configure password for MD5 authentication\n"
@@ -173,7 +173,7 @@ DEFPY  (ldp_neighbor_password,
 DEFPY  (ldp_neighbor_session_holdtime,
        ldp_neighbor_session_holdtime_cmd,
        "[no] neighbor A.B.C.D$neighbor session holdtime (15-65535)$holdtime",
-       "Negate a command or set its defaults\n"
+       NO_STR
        "Configure neighbor parameters\n"
        "LDP Id of neighbor\n"
        "Configure session parameters\n"
@@ -186,7 +186,7 @@ DEFPY  (ldp_neighbor_session_holdtime,
 DEFPY  (ldp_neighbor_ttl_security,
        ldp_neighbor_ttl_security_cmd,
        "[no] neighbor A.B.C.D$neighbor ttl-security <disable|hops (1-254)$hops>",
-       "Negate a command or set its defaults\n"
+       NO_STR
        "Configure neighbor parameters\n"
        "LDP Id of neighbor\n"
        "LDP ttl security check\n"
@@ -200,7 +200,7 @@ DEFPY  (ldp_neighbor_ttl_security,
 DEFPY  (ldp_router_id,
        ldp_router_id_cmd,
        "[no] router-id A.B.C.D$address",
-       "Negate a command or set its defaults\n"
+       NO_STR
        "Configure router Id\n"
        "LSR Id (in form of an IPv4 address)\n")
 {
@@ -210,7 +210,7 @@ DEFPY  (ldp_router_id,
 DEFPY  (ldp_discovery_targeted_hello_accept,
        ldp_discovery_targeted_hello_accept_cmd,
        "[no] discovery targeted-hello accept [from <(1-199)|(1300-2699)|WORD>$from_acl]",
-       "Negate a command or set its defaults\n"
+       NO_STR
        "Configure discovery parameters\n"
        "LDP Targeted Hellos\n"
        "Accept and respond to targeted hellos\n"
@@ -225,7 +225,7 @@ DEFPY  (ldp_discovery_targeted_hello_accept,
 DEFPY  (ldp_discovery_transport_address_ipv4,
        ldp_discovery_transport_address_ipv4_cmd,
        "[no] discovery transport-address A.B.C.D$address",
-       "Negate a command or set its defaults\n"
+       NO_STR
        "Configure discovery parameters\n"
        "Specify transport address for TCP connection\n"
        "IP address to be used as transport address\n")
@@ -236,7 +236,7 @@ DEFPY  (ldp_discovery_transport_address_ipv4,
 DEFPY  (ldp_discovery_transport_address_ipv6,
        ldp_discovery_transport_address_ipv6_cmd,
        "[no] discovery transport-address X:X::X:X$address",
-       "Negate a command or set its defaults\n"
+       NO_STR
        "Configure discovery parameters\n"
        "Specify transport address for TCP connection\n"
        "IPv6 address to be used as transport address\n")
@@ -247,7 +247,7 @@ DEFPY  (ldp_discovery_transport_address_ipv6,
 DEFPY  (ldp_label_local_advertise,
        ldp_label_local_advertise_cmd,
        "[no] label local advertise [{to <(1-199)|(1300-2699)|WORD>$to_acl|for <(1-199)|(1300-2699)|WORD>$for_acl}]",
-       "Negate a command or set its defaults\n"
+       NO_STR
        "Configure label control and policies\n"
        "Configure local label control and policies\n"
        "Configure outbound label advertisement control\n"
@@ -266,7 +266,7 @@ DEFPY  (ldp_label_local_advertise,
 DEFPY  (ldp_label_local_advertise_explicit_null,
        ldp_label_local_advertise_explicit_null_cmd,
        "[no] label local advertise explicit-null [for <(1-199)|(1300-2699)|WORD>$for_acl]",
-       "Negate a command or set its defaults\n"
+       NO_STR
        "Configure label control and policies\n"
        "Configure local label control and policies\n"
        "Configure outbound label advertisement control\n"
@@ -282,7 +282,7 @@ DEFPY  (ldp_label_local_advertise_explicit_null,
 DEFPY  (ldp_label_local_allocate,
        ldp_label_local_allocate_cmd,
        "[no] label local allocate <host-routes$host_routes|for <(1-199)|(1300-2699)|WORD>$for_acl>",
-       "Negate a command or set its defaults\n"
+       NO_STR
        "Configure label control and policies\n"
        "Configure local label control and policies\n"
        "Configure label allocation control\n"
@@ -298,7 +298,7 @@ DEFPY  (ldp_label_local_allocate,
 DEFPY  (ldp_label_remote_accept,
        ldp_label_remote_accept_cmd,
        "[no] label remote accept {from <(1-199)|(1300-2699)|WORD>$from_acl|for <(1-199)|(1300-2699)|WORD>$for_acl}",
-       "Negate a command or set its defaults\n"
+       NO_STR
        "Configure label control and policies\n"
        "Configure remote/peer label control and policies\n"
        "Configure inbound label acceptance control\n"
@@ -317,7 +317,7 @@ DEFPY  (ldp_label_remote_accept,
 DEFPY  (ldp_ttl_security_disable,
        ldp_ttl_security_disable_cmd,
        "[no] ttl-security disable",
-       "Negate a command or set its defaults\n"
+       NO_STR
        "LDP ttl security check\n"
        "Disable ttl security\n")
 {
@@ -327,7 +327,7 @@ DEFPY  (ldp_ttl_security_disable,
 DEFPY  (ldp_session_holdtime,
        ldp_session_holdtime_cmd,
        "[no] session holdtime (15-65535)$holdtime",
-       "Negate a command or set its defaults\n"
+       NO_STR
        "Configure session parameters\n"
        "Configure session holdtime\n"
        "Time (seconds)\n")
@@ -353,7 +353,7 @@ DEFUN_NOSH(ldp_interface,
 DEFPY  (no_ldp_interface,
        no_ldp_interface_cmd,
        "no interface IFNAME$ifname",
-       "Negate a command or set its defaults\n"
+       NO_STR
        "Enable LDP on an interface and enter interface submode\n"
        "Interface's name\n")
 {
@@ -363,7 +363,7 @@ DEFPY  (no_ldp_interface,
 DEFPY  (ldp_neighbor_ipv4_targeted,
        ldp_neighbor_ipv4_targeted_cmd,
        "[no] neighbor A.B.C.D$address targeted",
-       "Negate a command or set its defaults\n"
+       NO_STR
        "Configure neighbor parameters\n"
        "IP address of neighbor\n"
        "Establish targeted session\n")
@@ -374,7 +374,7 @@ DEFPY  (ldp_neighbor_ipv4_targeted,
 DEFPY  (ldp_neighbor_ipv6_targeted,
        ldp_neighbor_ipv6_targeted_cmd,
        "[no] neighbor X:X::X:X$address targeted",
-       "Negate a command or set its defaults\n"
+       NO_STR
        "Configure neighbor parameters\n"
        "IPv6 address of neighbor\n"
        "Establish targeted session\n")
@@ -385,7 +385,7 @@ DEFPY  (ldp_neighbor_ipv6_targeted,
 DEFPY  (ldp_bridge,
        ldp_bridge_cmd,
        "[no] bridge IFNAME$ifname",
-       "Negate a command or set its defaults\n"
+       NO_STR
        "Bridge interface\n"
        "Interface's name\n")
 {
@@ -395,7 +395,7 @@ DEFPY  (ldp_bridge,
 DEFPY  (ldp_mtu,
        ldp_mtu_cmd,
        "[no] mtu (1500-9180)$mtu",
-       "Negate a command or set its defaults\n"
+       NO_STR
        "Set Maximum Transmission Unit\n"
        "Maximum Transmission Unit value\n")
 {
@@ -405,7 +405,7 @@ DEFPY  (ldp_mtu,
 DEFPY  (ldp_member_interface,
        ldp_member_interface_cmd,
        "[no] member interface IFNAME$ifname",
-       "Negate a command or set its defaults\n"
+       NO_STR
        "L2VPN member configuration\n"
        "Local interface\n"
        "Interface's name\n")
@@ -432,7 +432,7 @@ DEFUN_NOSH(ldp_member_pseudowire,
 DEFPY  (no_ldp_member_pseudowire,
        no_ldp_member_pseudowire_cmd,
        "no member pseudowire IFNAME$ifname",
-       "Negate a command or set its defaults\n"
+       NO_STR
        "L2VPN member configuration\n"
        "Pseudowire interface\n"
        "Interface's name\n")
@@ -443,7 +443,7 @@ DEFPY  (no_ldp_member_pseudowire,
 DEFPY  (ldp_vc_type,
        ldp_vc_type_cmd,
        "[no] vc type <ethernet|ethernet-tagged>$vc_type",
-       "Negate a command or set its defaults\n"
+       NO_STR
        "Virtual Circuit options\n"
        "Virtual Circuit type to use\n"
        "Ethernet (type 5)\n"
@@ -455,7 +455,7 @@ DEFPY  (ldp_vc_type,
 DEFPY  (ldp_control_word,
        ldp_control_word_cmd,
        "[no] control-word <exclude|include>$preference",
-       "Negate a command or set its defaults\n"
+       NO_STR
        "Control-word options\n"
        "Exclude control-word in pseudowire packets\n"
        "Include control-word in pseudowire packets\n")
@@ -466,7 +466,7 @@ DEFPY  (ldp_control_word,
 DEFPY  (ldp_neighbor_address,
        ldp_neighbor_address_cmd,
        "[no] neighbor address <A.B.C.D|X:X::X:X>$pw_address",
-       "Negate a command or set its defaults\n"
+       NO_STR
        "Remote endpoint configuration\n"
        "Specify the IPv4 or IPv6 address of the remote endpoint\n"
        "IPv4 address\n"
@@ -478,7 +478,7 @@ DEFPY  (ldp_neighbor_address,
 DEFPY  (ldp_neighbor_lsr_id,
        ldp_neighbor_lsr_id_cmd,
        "[no] neighbor lsr-id A.B.C.D$address",
-       "Negate a command or set its defaults\n"
+       NO_STR
        "Remote endpoint configuration\n"
        "Specify the LSR-ID of the remote endpoint\n"
        "IPv4 address\n")
@@ -489,7 +489,7 @@ DEFPY  (ldp_neighbor_lsr_id,
 DEFPY  (ldp_pw_id,
        ldp_pw_id_cmd,
        "[no] pw-id (1-4294967295)$pwid",
-       "Negate a command or set its defaults\n"
+       NO_STR
        "Set the Virtual Circuit ID\n"
        "Virtual Circuit ID value\n")
 {
@@ -499,7 +499,7 @@ DEFPY  (ldp_pw_id,
 DEFPY  (ldp_pw_status_disable,
        ldp_pw_status_disable_cmd,
        "[no] pw-status disable",
-       "Negate a command or set its defaults\n"
+       NO_STR
        "Configure PW status\n"
        "Disable PW status\n")
 {
@@ -522,7 +522,7 @@ DEFPY  (ldp_clear_mpls_ldp_neighbor,
 DEFPY  (ldp_debug_mpls_ldp_discovery_hello,
        ldp_debug_mpls_ldp_discovery_hello_cmd,
        "[no] debug mpls ldp discovery hello <recv|sent>$dir",
-       "Negate a command or set its defaults\n"
+       NO_STR
        "Debugging functions\n"
        "MPLS information\n"
        "Label Distribution Protocol\n"
@@ -537,7 +537,7 @@ DEFPY  (ldp_debug_mpls_ldp_discovery_hello,
 DEFPY  (ldp_debug_mpls_ldp_type,
        ldp_debug_mpls_ldp_type_cmd,
        "[no] debug mpls ldp <errors|event|zebra>$type",
-       "Negate a command or set its defaults\n"
+       NO_STR
        "Debugging functions\n"
        "MPLS information\n"
        "Label Distribution Protocol\n"
@@ -551,7 +551,7 @@ DEFPY  (ldp_debug_mpls_ldp_type,
 DEFPY  (ldp_debug_mpls_ldp_messages_recv,
        ldp_debug_mpls_ldp_messages_recv_cmd,
        "[no] debug mpls ldp messages recv [all]$all",
-       "Negate a command or set its defaults\n"
+       NO_STR
        "Debugging functions\n"
        "MPLS information\n"
        "Label Distribution Protocol\n"
@@ -565,7 +565,7 @@ DEFPY  (ldp_debug_mpls_ldp_messages_recv,
 DEFPY  (ldp_debug_mpls_ldp_messages_sent,
        ldp_debug_mpls_ldp_messages_sent_cmd,
        "[no] debug mpls ldp messages sent [all]$all",
-       "Negate a command or set its defaults\n"
+       NO_STR
        "Debugging functions\n"
        "MPLS information\n"
        "Label Distribution Protocol\n"
index 79fff01c4cf5a91005de46666994a4b8a2f2b469..ecc7db8f2ebb30ec6dffb87bd2f92e380f89e276 100644 (file)
@@ -52,6 +52,8 @@ static int     ldp_interface_address_delete(int, struct zclient *,
                    zebra_size_t, vrf_id_t);
 static int      ldp_zebra_read_route(int, struct zclient *, zebra_size_t,
                    vrf_id_t);
+static int      ldp_zebra_read_pw_status_update(int, struct zclient *,
+                   zebra_size_t, vrf_id_t);
 static void     ldp_zebra_connected(struct zclient *);
 
 static struct zclient  *zclient;
@@ -64,7 +66,7 @@ ifp2kif(struct interface *ifp, struct kif *kif)
        kif->ifindex = ifp->ifindex;
        kif->operative = if_is_operative(ifp);
        if (ifp->ll_type == ZEBRA_LLT_ETHER)
-               memcpy(kif->mac, ifp->hw_addr, ETHER_ADDR_LEN);
+               memcpy(kif->mac, ifp->hw_addr, ETH_ALEN);
 }
 
 static void
@@ -92,6 +94,25 @@ ifc2kaddr(struct interface *ifp, struct connected *ifc, struct kaddr *ka)
        }
 }
 
+void
+pw2zpw(struct l2vpn_pw *pw, struct zapi_pw *zpw)
+{
+       memset(zpw, 0, sizeof(*zpw));
+       strlcpy(zpw->ifname, pw->ifname, sizeof(zpw->ifname));
+       zpw->ifindex = pw->ifindex;
+       zpw->type = pw->l2vpn->pw_type;
+       zpw->af = pw->af;
+       zpw->nexthop.ipv6 = pw->addr.v6;
+       zpw->local_label = NO_LABEL;
+       zpw->remote_label = NO_LABEL;
+       if (pw->flags & F_PW_CWORD)
+               zpw->flags = F_PSEUDOWIRE_CWORD;
+       zpw->data.ldp.lsr_id = pw->lsr_id;
+       zpw->data.ldp.pwid = pw->pwid;
+       strlcpy(zpw->data.ldp.vpn_name, pw->l2vpn->name,
+           sizeof(zpw->data.ldp.vpn_name));
+}
+
 static int
 zebra_send_mpls_labels(int cmd, struct kroute *kr)
 {
@@ -152,17 +173,40 @@ kr_delete(struct kroute *kr)
 }
 
 int
-kmpw_set(struct kpw *kpw)
+kmpw_add(struct zapi_pw *zpw)
 {
-       /* TODO */
-       return (0);
+       debug_zebra_out("pseudowire %s nexthop %s (add)",
+           zpw->ifname, log_addr(zpw->af, (union ldpd_addr *)&zpw->nexthop));
+
+       return (zebra_send_pw(zclient, ZEBRA_PW_ADD, zpw));
 }
 
 int
-kmpw_unset(struct kpw *kpw)
+kmpw_del(struct zapi_pw *zpw)
 {
-       /* TODO */
-       return (0);
+       debug_zebra_out("pseudowire %s nexthop %s (del)",
+           zpw->ifname, log_addr(zpw->af, (union ldpd_addr *)&zpw->nexthop));
+
+       return (zebra_send_pw(zclient, ZEBRA_PW_DELETE, zpw));
+}
+
+int
+kmpw_set(struct zapi_pw *zpw)
+{
+       debug_zebra_out("pseudowire %s nexthop %s labels %u/%u (set)",
+           zpw->ifname, log_addr(zpw->af, (union ldpd_addr *)&zpw->nexthop),
+           zpw->local_label, zpw->remote_label);
+
+       return (zebra_send_pw(zclient, ZEBRA_PW_SET, zpw));
+}
+
+int
+kmpw_unset(struct zapi_pw *zpw)
+{
+       debug_zebra_out("pseudowire %s nexthop %s (unset)",
+           zpw->ifname, log_addr(zpw->af, (union ldpd_addr *)&zpw->nexthop));
+
+       return (zebra_send_pw(zclient, ZEBRA_PW_UNSET, zpw));
 }
 
 void
@@ -464,6 +508,25 @@ ldp_zebra_read_route(int command, struct zclient *zclient, zebra_size_t length,
        return (0);
 }
 
+/*
+ * Receive PW status update from Zebra and send it to LDE process.
+ */
+static int
+ldp_zebra_read_pw_status_update(int command, struct zclient *zclient,
+    zebra_size_t length, vrf_id_t vrf_id)
+{
+       struct zapi_pw_status    zpw;
+
+       zebra_read_pw_status_update(command, zclient, length, vrf_id, &zpw);
+
+       debug_zebra_in("pseudowire %s status %s", zpw.ifname,
+           (zpw.status == PW_STATUS_UP) ? "up" : "down");
+
+       main_imsg_compose_lde(IMSG_PW_UPDATE, 0, &zpw, sizeof(zpw));
+
+       return (0);
+}
+
 static void
 ldp_zebra_connected(struct zclient *zclient)
 {
@@ -494,6 +557,7 @@ ldp_zebra_init(struct thread_master *master)
        zclient->redistribute_route_ipv4_del = ldp_zebra_read_route;
        zclient->redistribute_route_ipv6_add = ldp_zebra_read_route;
        zclient->redistribute_route_ipv6_del = ldp_zebra_read_route;
+       zclient->pw_status_update = ldp_zebra_read_pw_status_update;
 }
 
 void
index abcad79d67cad6a6ca4cf5106e8e5bcb3cde3eb5..2d7afd5df8afe051485b5abcd638d913836516e7 100644 (file)
@@ -578,21 +578,36 @@ main_dispatch_lde(struct thread *thread)
                        if (kr_delete(imsg.data))
                                log_warnx("%s: error deleting route", __func__);
                        break;
-               case IMSG_KPWLABEL_CHANGE:
+               case IMSG_KPW_ADD:
+               case IMSG_KPW_DELETE:
+               case IMSG_KPW_SET:
+               case IMSG_KPW_UNSET:
                        if (imsg.hdr.len - IMSG_HEADER_SIZE !=
-                           sizeof(struct kpw))
+                           sizeof(struct zapi_pw))
                                fatalx("invalid size of IMSG_KPWLABEL_CHANGE");
-                       if (kmpw_set(imsg.data))
-                               log_warnx("%s: error changing pseudowire",
-                                   __func__);
-                       break;
-               case IMSG_KPWLABEL_DELETE:
-                       if (imsg.hdr.len - IMSG_HEADER_SIZE !=
-                           sizeof(struct kpw))
-                               fatalx("invalid size of IMSG_KPWLABEL_DELETE");
-                       if (kmpw_unset(imsg.data))
-                               log_warnx("%s: error unsetting pseudowire",
-                                   __func__);
+
+                       switch (imsg.hdr.type) {
+                       case IMSG_KPW_ADD:
+                               if (kmpw_add(imsg.data))
+                                       log_warnx("%s: error adding "
+                                           "pseudowire", __func__);
+                               break;
+                       case IMSG_KPW_DELETE:
+                               if (kmpw_del(imsg.data))
+                                       log_warnx("%s: error deleting "
+                                           "pseudowire", __func__);
+                               break;
+                       case IMSG_KPW_SET:
+                               if (kmpw_set(imsg.data))
+                                       log_warnx("%s: error setting "
+                                           "pseudowire", __func__);
+                               break;
+                       case IMSG_KPW_UNSET:
+                               if (kmpw_unset(imsg.data))
+                                       log_warnx("%s: error unsetting "
+                                           "pseudowire", __func__);
+                               break;
+                       }
                        break;
                case IMSG_ACL_CHECK:
                        if (imsg.hdr.len != IMSG_HEADER_SIZE +
index 352a7b0d7ece9e536b97b4578f872acd47d86a8a..31d0bc69b159b7c586a4ef8f6b3cfeafadb00546 100644 (file)
@@ -30,6 +30,8 @@
 #include "prefix.h"
 #include "filter.h"
 #include "vty.h"
+#include "pw.h"
+#include "zclient.h"
 
 #include "ldp.h"
 
@@ -44,7 +46,6 @@
 #define LDPD_OPT_NOACTION      0x00000004
 
 #define TCP_MD5_KEY_LEN                80
-#define L2VPN_NAME_LEN         32
 
 #define        RT_BUF_SIZE             16384
 #define        MAX_RTSOCK_BUF          128 * 1024
@@ -102,8 +103,10 @@ enum imsg_type {
        IMSG_CTL_LOG_VERBOSE,
        IMSG_KLABEL_CHANGE,
        IMSG_KLABEL_DELETE,
-       IMSG_KPWLABEL_CHANGE,
-       IMSG_KPWLABEL_DELETE,
+       IMSG_KPW_ADD,
+       IMSG_KPW_DELETE,
+       IMSG_KPW_SET,
+       IMSG_KPW_UNSET,
        IMSG_IFSTATUS,
        IMSG_NEWADDR,
        IMSG_DELADDR,
@@ -147,7 +150,8 @@ enum imsg_type {
        IMSG_DEBUG_UPDATE,
        IMSG_LOG,
        IMSG_ACL_CHECK,
-       IMSG_INIT
+       IMSG_INIT,
+       IMSG_PW_UPDATE
 };
 
 struct ldpd_init {
@@ -389,7 +393,7 @@ struct l2vpn_if {
        char                     ifname[IF_NAMESIZE];
        unsigned int             ifindex;
        int                      operative;
-       uint8_t                  mac[ETHER_ADDR_LEN];
+       uint8_t                  mac[ETH_ALEN];
        QOBJ_FIELDS
 };
 RB_HEAD(l2vpn_if_head, l2vpn_if);
@@ -407,6 +411,7 @@ struct l2vpn_pw {
        unsigned int             ifindex;
        uint32_t                 remote_group;
        uint16_t                 remote_mtu;
+       uint32_t                 local_status;
        uint32_t                 remote_status;
        uint8_t                  flags;
        QOBJ_FIELDS
@@ -418,8 +423,7 @@ DECLARE_QOBJ_TYPE(l2vpn_pw)
 #define F_PW_STATUSTLV         0x02    /* status tlv negotiated */
 #define F_PW_CWORD_CONF                0x04    /* control word configured */
 #define F_PW_CWORD             0x08    /* control word negotiated */
-#define F_PW_STATUS_UP         0x10    /* pseudowire is operational */
-#define F_PW_STATIC_NBR_ADDR   0x20    /* static neighbor address configured */
+#define F_PW_STATIC_NBR_ADDR   0x10    /* static neighbor address configured */
 
 struct l2vpn {
        RB_ENTRY(l2vpn)          entry;
@@ -542,16 +546,6 @@ struct kroute {
        uint16_t                 flags;
 };
 
-struct kpw {
-       unsigned short           ifindex;
-       int                      pw_type;
-       int                      af;
-       union ldpd_addr          nexthop;
-       uint32_t                 local_label;
-       uint32_t                 remote_label;
-       uint8_t                  flags;
-};
-
 struct kaddr {
        char                     ifname[IF_NAMESIZE];
        unsigned short           ifindex;
@@ -566,7 +560,7 @@ struct kif {
        unsigned short           ifindex;
        int                      flags;
        int                      operative;
-       uint8_t                  mac[ETHER_ADDR_LEN];
+       uint8_t                  mac[ETH_ALEN];
        int                      mtu;
 };
 
@@ -668,11 +662,14 @@ struct ldpd_conf  *parse_config(char *);
 int                     cmdline_symset(char *);
 
 /* kroute.c */
+void            pw2zpw(struct l2vpn_pw *, struct zapi_pw *);
 void            kif_redistribute(const char *);
 int             kr_change(struct kroute *);
 int             kr_delete(struct kroute *);
-int             kmpw_set(struct kpw *);
-int             kmpw_unset(struct kpw *);
+int             kmpw_add(struct zapi_pw *);
+int             kmpw_del(struct zapi_pw *);
+int             kmpw_set(struct zapi_pw *);
+int             kmpw_unset(struct zapi_pw *);
 
 /* util.c */
 uint8_t                 mask2prefixlen(in_addr_t);
index f8d4b5f5fd7897397a814053b0261e543d9f4847..39860a185981d0492ed88466d60f2e176a249ce6 100644 (file)
@@ -289,6 +289,8 @@ nbr_new(struct in_addr id, int af, int ds_tlv, union ldpd_addr *addr,
 void
 nbr_del(struct nbr *nbr)
 {
+       struct adj              *adj;
+
        log_debug("%s: lsr-id %s", __func__, inet_ntoa(nbr->id));
 
        nbr_fsm(nbr, NBR_EVT_CLOSE_SESSION);
@@ -314,6 +316,11 @@ nbr_del(struct nbr *nbr)
        mapping_list_clr(&nbr->release_list);
        mapping_list_clr(&nbr->abortreq_list);
 
+       while ((adj = RB_ROOT(nbr_adj_head, &nbr->adj_tree)) != NULL) {
+               adj->nbr = NULL;
+               RB_REMOVE(nbr_adj_head, &nbr->adj_tree, adj);
+       }
+
        if (nbr->peerid)
                RB_REMOVE(nbr_pid_head, &nbrs_by_pid, nbr);
        RB_REMOVE(nbr_id_head, &nbrs_by_id, nbr);
index 60cde149f5e29e1774108ee99fcd48a49a64c608..94f401ebe6afe208235b6fec8cb1565acb1d66bc 100644 (file)
@@ -1,4 +1,4 @@
-Makefile
+!Makefile
 Makefile.in
 *.o
 *.lo
diff --git a/lib/Makefile b/lib/Makefile
new file mode 100644 (file)
index 0000000..62051ac
--- /dev/null
@@ -0,0 +1,10 @@
+all: ALWAYS
+       @$(MAKE) -s -C .. lib/libfrr.la
+%: ALWAYS
+       @$(MAKE) -s -C .. lib/$@
+
+Makefile:
+       #nothing
+ALWAYS:
+.PHONY: ALWAYS makefiles
+.SUFFIXES:
diff --git a/lib/Makefile.am b/lib/Makefile.am
deleted file mode 100644 (file)
index 5847ad4..0000000
+++ /dev/null
@@ -1,155 +0,0 @@
-## Process this file with automake to produce Makefile.in.
-
-include ../common.am
-
-AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib
-AM_CFLAGS = $(WERROR)
-DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\"
-AM_YFLAGS = -d -Dapi.prefix=@BISON_OPENBRACE@cmd_yy@BISON_CLOSEBRACE@ @BISON_VERBOSE@
-
-command_lex.h: command_lex.c
-       @if test ! -f $@; then rm -f command_lex.c; else :; fi
-       @if test ! -f $@; then $(MAKE) $(AM_MAKEFLAGS) command_lex.c; else :; fi
-command_parse.lo: command_lex.h
-clippy-command_parse.$(OBJEXT): command_lex.h
-
-lib_LTLIBRARIES = libfrr.la
-libfrr_la_LDFLAGS = -version-info 0:0:0 
-
-libfrr_la_SOURCES = \
-       network.c pid_output.c getopt.c getopt1.c \
-       checksum.c vector.c linklist.c vty.c openbsd-tree.c \
-       graph.c command_parse.y command_lex.l command_match.c \
-       command_graph.c \
-       command.c \
-       sockunion.c prefix.c thread.c if.c buffer.c table.c hash.c \
-       filter.c routemap.c distribute.c stream.c log.c plist.c \
-       zclient.c sockopt.c md5.c if_rmap.c keychain.c privs.c \
-       sigevent.c pqueue.c jhash.c workqueue.c nexthop.c json.c \
-       ptm_lib.c csv.c bfd.c vrf.c systemd.c ns.c memory.c memory_vty.c \
-       imsg-buffer.c imsg.c skiplist.c \
-       qobj.c wheel.c \
-       event_counter.c \
-       grammar_sandbox.c \
-       srcdest_table.c \
-       spf_backoff.c \
-       libfrr.c \
-       strlcpy.c \
-       strlcat.c \
-       sha256.c \
-       module.c \
-       hook.c \
-       frr_pthread.c \
-       termtable.c \
-       # end
-
-BUILT_SOURCES = route_types.h gitversion.h command_parse.h command_lex.h
-
-libfrr_la_LIBADD = @LIBCAP@
-
-if SNMP
-lib_LTLIBRARIES +=  libfrrsnmp.la
-endif
-
-libfrrsnmp_la_CFLAGS = $(WERROR) $(SNMP_CFLAGS)
-libfrrsnmp_la_LDFLAGS = -version-info 0:0:0
-libfrrsnmp_la_LIBADD = libfrr.la $(SNMP_LIBS)
-libfrrsnmp_la_SOURCES = \
-       agentx.c \
-       smux.c \
-       snmp.c \
-       #end
-
-pkginclude_HEADERS = \
-       frratomic.h \
-       buffer.h checksum.h filter.h getopt.h hash.h \
-       if.h linklist.h log.h \
-       graph.h command_match.h \
-       command_graph.h \
-       command.h \
-       memory.h network.h prefix.h routemap.h distribute.h sockunion.h \
-       stream.h table.h thread.h vector.h version.h vty.h zebra.h \
-       plist.h zclient.h sockopt.h smux.h md5.h if_rmap.h keychain.h \
-       privs.h sigevent.h pqueue.h jhash.h zassert.h \
-       workqueue.h route_types.h libospf.h nexthop.h json.h \
-       ptm_lib.h csv.h bfd.h vrf.h ns.h systemd.h bitfield.h \
-       fifo.h memory_vty.h mpls.h imsg.h openbsd-queue.h openbsd-tree.h \
-       skiplist.h qobj.h wheel.h \
-       event_counter.h \
-       monotime.h \
-       spf_backoff.h \
-       srcdest_table.h \
-       module.h \
-       hook.h \
-       libfrr.h \
-       sha256.h \
-       frr_pthread.h \
-       vrf_int.h \
-       termtable.h \
-       vlan.h \
-       vxlan.h \
-       ipaddr.h \
-       # end
-
-noinst_HEADERS = \
-       plist_int.h \
-       log_int.h \
-       clippy.h \
-       # end
-
-noinst_PROGRAMS = grammar_sandbox
-if BUILD_CLIPPY
-noinst_PROGRAMS += clippy
-endif
-
-grammar_sandbox_SOURCES = grammar_sandbox_main.c
-grammar_sandbox_LDADD = libfrr.la
-
-clippy_SOURCES = \
-       defun_lex.l \
-       command_parse.y \
-       command_lex.l \
-       command_graph.c \
-       command_py.c \
-       memory.c \
-       graph.c \
-       vector.c \
-       clippy.c \
-       # end
-clippy_CPPFLAGS = -D_GNU_SOURCE
-clippy_CFLAGS   = $(PYTHON_CFLAGS)
-clippy_LDADD    = $(PYTHON_LIBS)
-clippy-command_graph.$(OBJEXT): route_types.h
-
-plist.lo: plist_clippy.c
-
-EXTRA_DIST = \
-       queue.h \
-       command_lex.h \
-       route_types.pl route_types.txt \
-       gitversion.pl
-
-route_types.h: $(srcdir)/route_types.txt $(srcdir)/route_types.pl
-       @PERL@ $(srcdir)/route_types.pl < $(srcdir)/route_types.txt > $@
-
-if GIT_VERSION
-
-# bit of a trick here to always have up-to-date git stamps without triggering
-# unneccessary rebuilds.  .PHONY causes the .tmp file to be rebuilt always,
-# but if we use that on gitversion.h it'll ripple through the .c file deps.
-# (even if gitversion.h's file timestamp doesn't change, make will think it
-# did, because of .PHONY...)
-
-.PHONY: gitversion.h.tmp
-.SILENT: gitversion.h gitversion.h.tmp
-GITH=gitversion.h
-gitversion.h.tmp: $(srcdir)/../.git
-       @PERL@ $(srcdir)/gitversion.pl $(srcdir) > ${GITH}.tmp
-gitversion.h: gitversion.h.tmp
-       { test -f ${GITH} && diff -s -q ${GITH}.tmp ${GITH}; } || cp -v ${GITH}.tmp ${GITH}
-
-else
-.PHONY: gitversion.h
-gitversion.h:
-       true
-endif
index f28a55ec6db64fcf277893eb0fd5db6c47db3a38..09ffa6ce56e702d8223ed5bd61dd1cbaa11faef3 100644 (file)
@@ -110,6 +110,7 @@ const char *node_names[] = {
        "forwarding",               // FORWARDING_NODE,
        "protocol",                 // PROTOCOL_NODE,
        "mpls",                     // MPLS_NODE,
+       "pw",                       // PW_NODE,
        "vty",                      // VTY_NODE,
        "link-params",              // LINK_PARAMS_NODE,
        "bgp evpn vni",             // BGP_EVPN_VNI_NODE,
@@ -1253,6 +1254,7 @@ void cmd_exit(struct vty *vty)
                vty_config_unlock(vty);
                break;
        case INTERFACE_NODE:
+       case PW_NODE:
        case NS_NODE:
        case VRF_NODE:
        case ZEBRA_NODE:
@@ -1338,6 +1340,7 @@ DEFUN (config_end,
                break;
        case CONFIG_NODE:
        case INTERFACE_NODE:
+       case PW_NODE:
        case NS_NODE:
        case VRF_NODE:
        case ZEBRA_NODE:
index 533b4b32894a5994df5c0f3d9409642eea62ce00..d0c9f0eaf9c9a5ee7a4468778f9874471a3722ad 100644 (file)
@@ -132,6 +132,7 @@ enum node_type {
        FORWARDING_NODE,        /* IP forwarding node. */
        PROTOCOL_NODE,          /* protocol filtering node */
        MPLS_NODE,              /* MPLS config node */
+       PW_NODE,                /* Pseudowire config node */
        VTY_NODE,               /* Vty node. */
        LINK_PARAMS_NODE,       /* Link-parameters node */
        BGP_EVPN_VNI_NODE,      /* BGP EVPN VNI */
@@ -181,6 +182,7 @@ struct cmd_node {
 #define CMD_ERR_NO_FILE         11
 #define CMD_SUSPEND             12
 #define CMD_WARNING_CONFIG_FAILED 13
+#define CMD_NOT_MY_INSTANCE    14
 
 /* Argc max counts. */
 #define CMD_ARGC_MAX   25
index 3efa4d5cfc58a1f7144ffd3eeefe4ce5216c5e53..dc7233c1fe2df461dd5d6eadee7dbfeafaaeb9bb 100644 (file)
@@ -385,7 +385,6 @@ static void cmd_node_names(struct graph_node *gn, struct graph_node *join,
                break;
 
        case START_TKN:
-       case END_TKN:
        case JOIN_TKN:
                /* "<foo|bar> WORD" -> word is not "bar" or "foo" */
                prevname = NULL;
@@ -405,6 +404,9 @@ static void cmd_node_names(struct graph_node *gn, struct graph_node *join,
                        cmd_token_varname_set(tailtok, jointok->varname);
                }
                break;
+
+       case END_TKN:
+               return;
        }
 
        for (i = 0; i < vector_active(gn->to); i++) {
index c020d193a12515b45671ae12c9cb6ff44ee01c84..fddbf7b2873cf314ead02a7c7a475926fc419352 100644 (file)
@@ -49,8 +49,8 @@ RANGE           \({NUMBER}[ ]?\-[ ]?{NUMBER}\)
 %option noyywrap
 %option nounput
 %option noinput
-%option outfile="command_lex.c"
-%option header-file="command_lex.h"
+%option outfile="lib/command_lex.c"
+%option header-file="lib/command_lex.h"
 %option prefix="cmd_yy"
 %option reentrant
 %option bison-bridge
index ba042c33be9c97c4a887ebdc16ed55ba258a842b..1bc8ea1a445336f89c0a5da09908cf00ab7a21ff 100644 (file)
@@ -33,8 +33,8 @@
 /* define api.prefix {cmd_yy} */
 
 /* names for generated header and parser files */
-%defines "command_parse.h"
-%output  "command_parse.c"
+%defines "lib/command_parse.h"
+%output  "lib/command_parse.c"
 
 /* note: code blocks are output in order, to both .c and .h:
  *  1. %code requires
index 8aa37a62a205ee9d691735c993702dc39257589f..024445be638ca20c57e11a925664b63418e63f0f 100644 (file)
@@ -85,7 +85,7 @@ SPECIAL               [(),]
 %option noyywrap
 %option noinput
 %option nounput
-%option outfile="defun_lex.c"
+%option outfile="lib/defun_lex.c"
 %option prefix="def_yy"
 %option 8bit
 
index a7714f156930e8c4d46c3da45c1188c18a44956e..801871f8390c1bd96ae515249ffd6a4e5d14d13b 100644 (file)
@@ -94,6 +94,10 @@ static void hash_expand(struct hash *hash)
        struct hash_backet *hb, *hbnext, **new_index;
 
        new_size = hash->size * 2;
+
+       if (hash->max_size && new_size > hash->max_size)
+               return;
+
        new_index = XCALLOC(MTYPE_HASH_INDEX,
                            sizeof(struct hash_backet *) * new_size);
        if (new_index == NULL)
@@ -354,33 +358,26 @@ DEFUN(show_hash_stats,
 
        /* Summary statistics calculated are:
         *
-        * - Load factor: This is the number of elements in the table divided by
-        * the
-        *   number of buckets. Since this hash table implementation uses
-        * chaining,
-        *   this value can be greater than 1. This number provides information
-        * on
-        *   how 'full' the table is, but does not provide information on how
-        * evenly
-        *   distributed the elements are. Notably, a load factor >= 1 does not
-        * imply
-        *   that every bucket has an element; with a pathological hash
-        * function, all
-        *   elements could be in a single bucket.
+        * - Load factor: This is the number of elements in the table divided
+        *   by the number of buckets. Since this hash table implementation
+        *   uses chaining, this value can be greater than 1.
+        *   This number provides information on how 'full' the table is, but
+        *   does not provide information on how evenly distributed the
+        *   elements are.
+        *   Notably, a load factor >= 1 does not imply that every bucket has
+        *   an element; with a pathological hash function, all elements could
+        *   be in a single bucket.
         *
         * - Full load factor: this is the number of elements in the table
-        * divided by
-        *   the number of buckets that have some elements in them.
+        *   divided by the number of buckets that have some elements in them.
         *
         * - Std. Dev.: This is the standard deviation calculated from the
-        * relevant
-        *   load factor. If the load factor is the mean of number of elements
-        * per
-        *   bucket, the standard deviation measures how much any particular
-        * bucket
-        *   is likely to deviate from the mean. As a rule of thumb this number
-        *   should be less than 2, and ideally <= 1 for optimal performance. A
-        *   number larger than 3 generally indicates a poor hash function.
+        *   relevant load factor. If the load factor is the mean of number of
+        *   elements per bucket, the standard deviation measures how much any
+        *   particular bucket is likely to deviate from the mean.
+        *   As a rule of thumb this number should be less than 2, and ideally
+        *   <= 1 for optimal performance. A number larger than 3 generally
+        *   indicates a poor hash function.
         */
 
        double lf;    // load factor
@@ -407,7 +404,7 @@ DEFUN(show_hash_stats,
                        continue;
 
                ssq = (long double)h->stats.ssq;
-               x2 = powl(h->count, 2.0);
+               x2 = h->count * h->count;
                ldc = (long double)h->count;
                full = h->size - h->stats.empty;
                lf = h->count / (double)h->size;
index 6ce29f0426dc6ff70afad24d8c0699b8b4988074..236abbbd6a2c573f34204dfa365343091c476f29 100644 (file)
@@ -64,6 +64,9 @@ struct hash {
        /* Hash table size. Must be power of 2 */
        unsigned int size;
 
+       /* If max_size is 0 there is no limit */
+       unsigned int max_size;
+
        /* Key make function. */
        unsigned int (*hash_key)(void *);
 
index c9483a4c65e38eed2a22b597b6495defc2b280bd..45aedb6a7de7066758f59421bf3d880c4f87b924 100644 (file)
@@ -34,7 +34,7 @@
 
 /* Architectual Constants */
 #ifdef DEBUG
-#define OSPF_LS_REFRESH_TIME                    60
+#define OSPF_LS_REFRESH_TIME                   120
 #else
 #define OSPF_LS_REFRESH_TIME                  1800
 #endif
index 28e086535412218f70dbde14dc2fed64f9cf65c5..63afbf51373f7f2f432a191f66b98d6af3786594 100644 (file)
--- a/lib/log.c
+++ b/lib/log.c
@@ -857,6 +857,7 @@ static const struct zebra_desc_table command_types[] = {
        DESC_ENTRY(ZEBRA_INTERFACE_ADDRESS_DELETE),
        DESC_ENTRY(ZEBRA_INTERFACE_UP),
        DESC_ENTRY(ZEBRA_INTERFACE_DOWN),
+       DESC_ENTRY(ZEBRA_INTERFACE_SET_MASTER),
        DESC_ENTRY(ZEBRA_IPV4_ROUTE_ADD),
        DESC_ENTRY(ZEBRA_IPV4_ROUTE_DELETE),
        DESC_ENTRY(ZEBRA_IPV6_ROUTE_ADD),
@@ -915,6 +916,11 @@ static const struct zebra_desc_table command_types[] = {
        DESC_ENTRY(ZEBRA_MACIP_DEL),
        DESC_ENTRY(ZEBRA_REMOTE_MACIP_ADD),
        DESC_ENTRY(ZEBRA_REMOTE_MACIP_DEL),
+       DESC_ENTRY(ZEBRA_PW_ADD),
+       DESC_ENTRY(ZEBRA_PW_DELETE),
+       DESC_ENTRY(ZEBRA_PW_SET),
+       DESC_ENTRY(ZEBRA_PW_UNSET),
+       DESC_ENTRY(ZEBRA_PW_STATUS_UPDATE),
 };
 #undef DESC_ENTRY
 
index 7bd338649830901ebb713592174f5ef9adf5d06e..8e50c1874ade466415ac85b4c34b083783738b99 100644 (file)
@@ -49,6 +49,10 @@ static inline time_t monotime(struct timeval *tvo)
        return ts.tv_sec;
 }
 
+#define ONE_DAY_SECOND 60*60*24
+#define ONE_WEEK_SECOND ONE_DAY_SECOND*7
+#define ONE_YEAR_SECOND ONE_DAY_SECOND*365
+
 /* the following two return microseconds, not time_t!
  *
  * also, they're negative forms of each other, but having both makes the
index 88b13cd99f209c506ee969cd67c02610b214f09f..33b6ff198776f0b39a4b7ffce6d12b9d4f0f1171 100644 (file)
@@ -26,6 +26,7 @@
 #include "sockunion.h"
 #include "memory.h"
 #include "log.h"
+#include "jhash.h"
 
 DEFINE_MTYPE_STATIC(LIB, PREFIX, "Prefix")
 
@@ -507,8 +508,9 @@ const char *safi2str(safi_t safi)
                return "evpn";
        case SAFI_LABELED_UNICAST:
                return "labeled-unicast";
+       default:
+               return "unknown";
        }
-       return NULL;
 }
 
 /* If n includes p prefix then return 1 else return 0. */
@@ -1060,7 +1062,7 @@ int prefix_blen(const struct prefix *p)
                return IPV6_MAX_BYTELEN;
                break;
        case AF_ETHERNET:
-               return ETHER_ADDR_LEN;
+               return ETH_ALEN;
        }
        return 0;
 }
@@ -1334,3 +1336,15 @@ char *prefix_mac2str(const struct ethaddr *mac, char *buf, int size)
                 (uint8_t)mac->octet[4], (uint8_t)mac->octet[5]);
        return ptr;
 }
+
+unsigned prefix_hash_key(void *pp)
+{
+       struct prefix copy;
+
+       /* make sure *all* unused bits are zero, particularly including
+        * alignment /
+        * padding and unused prefix bytes. */
+       memset(&copy, 0, sizeof(copy));
+       prefix_copy(&copy, (struct prefix *)pp);
+       return jhash(&copy, sizeof(copy), 0x55aa5a5a);
+}
index ce13dcfa0a71a1f9c4f055502d47780eb526ac78..5f2b57ccce2613aba71ec00bb360c894bc036931 100644 (file)
 #include "sockunion.h"
 #include "ipaddr.h"
 
-#ifndef ETHER_ADDR_LEN
-#ifdef ETHERADDRL
-#define ETHER_ADDR_LEN  ETHERADDRL
+#ifndef ETH_ALEN
+#define ETH_ALEN 6
+#endif
+
+/* for compatibility */
+#if defined(__ICC)
+#define CPP_WARN_STR(X) #X
+#define CPP_WARN(text) _Pragma(CPP_WARN_STR(message __FILE__ ": " text))
+
+#elif (defined(__GNUC__)                                                       \
+       && (__GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)))           \
+       || (defined(__clang__)                                                 \
+           && (__clang_major__ >= 4                                           \
+               || (__clang_major__ == 3 && __clang_minor__ >= 5)))
+#define CPP_WARN_STR(X) #X
+#define CPP_WARN(text) _Pragma(CPP_WARN_STR(GCC warning text))
+
 #else
-#define ETHER_ADDR_LEN 6
+#define CPP_WARN(text)
 #endif
+
+#ifdef ETHER_ADDR_LEN
+#undef ETHER_ADDR_LEN
 #endif
+#define ETHER_ADDR_LEN 6 CPP_WARN("ETHER_ADDR_LEN is being replaced by ETH_ALEN.\\n")
 
-#define ETHER_ADDR_STRLEN (3*ETHER_ADDR_LEN)
+#define ETHER_ADDR_STRLEN (3*ETH_ALEN)
 /*
  * there isn't a portable ethernet address type. We define our
  * own to simplify internal handling
  */
 struct ethaddr {
-       u_char octet[ETHER_ADDR_LEN];
+       u_char octet[ETH_ALEN];
 } __attribute__((packed));
 
 
@@ -323,6 +341,8 @@ extern const char *inet6_ntoa(struct in6_addr);
 extern int prefix_str2mac(const char *str, struct ethaddr *mac);
 extern char *prefix_mac2str(const struct ethaddr *mac, char *buf, int size);
 
+extern unsigned prefix_hash_key(void *pp);
+
 static inline int ipv6_martian(struct in6_addr *addr)
 {
        struct in6_addr localhost_addr;
diff --git a/lib/pw.h b/lib/pw.h
new file mode 100644 (file)
index 0000000..2cfaa47
--- /dev/null
+++ b/lib/pw.h
@@ -0,0 +1,52 @@
+/* Pseudowire definitions
+ * Copyright (C) 2016 Volta Networks, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ */
+
+#ifndef _FRR_PW_H
+#define _FRR_PW_H
+
+/* L2VPN name length. */
+#define L2VPN_NAME_LEN         32
+
+/* Pseudowire type - LDP and BGP use the same values. */
+#define PW_TYPE_ETHERNET_TAGGED        0x0004  /* RFC 4446 */
+#define PW_TYPE_ETHERNET       0x0005  /* RFC 4446 */
+#define PW_TYPE_WILDCARD       0x7FFF  /* RFC 4863, RFC 6668 */
+
+/* Pseudowire flags. */
+#define F_PSEUDOWIRE_CWORD     0x01
+
+/* Pseudowire status. */
+#define PW_STATUS_DOWN         0
+#define PW_STATUS_UP           1
+
+/*
+ * Protocol-specific information about the pseudowire.
+ */
+union pw_protocol_fields {
+       struct {
+               struct in_addr lsr_id;
+               uint32_t pwid;
+               char vpn_name[L2VPN_NAME_LEN];
+       } ldp;
+       struct {
+               /* TODO */
+       } bgp;
+};
+
+#endif /* _FRR_PW_H */
diff --git a/lib/sbuf.c b/lib/sbuf.c
new file mode 100644 (file)
index 0000000..37c1e52
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * Simple string buffer
+ *
+ * Copyright (C) 2017 Christian Franke
+ *
+ * This file is part of FRR.
+ *
+ * FRR is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * FRR is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with FRR; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+#include <zebra.h>
+
+#include "sbuf.h"
+#include "memory.h"
+
+void sbuf_init(struct sbuf *dest, char *buf, size_t size)
+{
+       dest->fixed = (size > 0);
+       if (dest->fixed) {
+               dest->buf = buf;
+               dest->size = size;
+       } else {
+               dest->buf = XMALLOC(MTYPE_TMP, 4096);
+               dest->size = 4096;
+       }
+
+       dest->pos = 0;
+       dest->buf[0] = '\0';
+}
+
+void sbuf_reset(struct sbuf *dest)
+{
+       dest->pos = 0;
+       dest->buf[0] = '\0';
+}
+
+const char *sbuf_buf(struct sbuf *buf)
+{
+       return buf->buf;
+}
+
+void sbuf_free(struct sbuf *buf)
+{
+       if (!buf->fixed)
+               XFREE(MTYPE_TMP, buf->buf);
+}
+
+void sbuf_push(struct sbuf *buf, int indent, const char *format, ...)
+{
+       va_list args;
+       int written;
+
+       if (!buf->fixed) {
+               char dummy;
+               int written1, written2;
+               size_t new_size;
+
+               written1 = snprintf(&dummy, 0, "%*s", indent, "");
+               va_start(args, format);
+               written2 = vsnprintf(&dummy, 0, format, args);
+               va_end(args);
+
+               new_size = buf->size;
+               if (written1 >= 0 && written2 >= 0) {
+                       while (buf->pos + written1 + written2 >= new_size)
+                               new_size *= 2;
+                       if (new_size > buf->size) {
+                               buf->buf =
+                                       XREALLOC(MTYPE_TMP, buf->buf, new_size);
+                               buf->size = new_size;
+                       }
+               }
+       }
+
+       written = snprintf(buf->buf + buf->pos, buf->size - buf->pos, "%*s",
+                          indent, "");
+
+       if (written >= 0)
+               buf->pos += written;
+       if (buf->pos > buf->size)
+               buf->pos = buf->size;
+
+       va_start(args, format);
+       written = vsnprintf(buf->buf + buf->pos, buf->size - buf->pos, format,
+                           args);
+       va_end(args);
+
+       if (written >= 0)
+               buf->pos += written;
+       if (buf->pos > buf->size)
+               buf->pos = buf->size;
+
+       if (buf->pos == buf->size)
+               assert(!"Buffer filled up!");
+}
diff --git a/lib/sbuf.h b/lib/sbuf.h
new file mode 100644 (file)
index 0000000..3e49ada
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * Simple string buffer
+ *
+ * Copyright (C) 2017 Christian Franke
+ *
+ * This file is part of FRR.
+ *
+ * FRR is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * FRR is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with FRR; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+#ifndef SBUF_H
+#define SBUF_H
+
+/*
+ * sbuf provides a simple string buffer. One application where this comes
+ * in handy is the parsing of binary data: If there is an error in the parsing
+ * process due to invalid input data, printing an error message explaining what
+ * went wrong is definitely useful. However, just printing the actual error,
+ * without any information about the previous parsing steps, is usually not very
+ * helpful.
+ * Using sbuf, the parser can log the whole parsing process into a buffer using
+ * a printf like API. When an error ocurrs, all the information about previous
+ * parsing steps is there in the log, without any need for backtracking, and can
+ * be used to give a detailed and useful error description.
+ * When parsing completes successfully without any error, the log can just be
+ * discarded unless debugging is turned on, to not spam the log.
+ *
+ * For the described usecase, the code would look something like this:
+ *
+ * int sbuf_example(..., char **parser_log)
+ * {
+ *         struct sbuf logbuf;
+ *
+ *         sbuf_init(&logbuf, NULL, 0);
+ *         sbuf_push(&logbuf, 0, "Starting parser\n");
+ *
+ *         int rv = do_parse(&logbuf, ...);
+ *
+ *         *parser_log = sbuf_buf(&logbuf);
+ *
+ *         return 1;
+ * }
+ *
+ * In this case, sbuf_example uses a string buffer with undefined size, which will
+ * be allocated on the heap by sbuf. The caller of sbuf_example is expected to free
+ * the string returned in parser_log.
+ */
+
+struct sbuf {
+       bool fixed;
+       char *buf;
+       size_t size;
+       size_t pos;
+       int indent;
+};
+
+void sbuf_init(struct sbuf *dest, char *buf, size_t size);
+void sbuf_reset(struct sbuf *buf);
+const char *sbuf_buf(struct sbuf *buf);
+void sbuf_free(struct sbuf *buf);
+#include "lib/log.h"
+void sbuf_push(struct sbuf *buf, int indent, const char *format, ...)
+       PRINTF_ATTRIBUTE(3, 4);
+
+#endif
index af0054d6b23972ac2de25f239d1bd020695465d4..559ae37ffb09130928d014525ca1dc0d8acf157e 100644 (file)
@@ -354,13 +354,19 @@ int sockopt_ttl(int family, int sock, int ttl)
        return 0;
 }
 
+/*
+ * This function called setsockopt(.., TCP_CORK,...)
+ * Which on linux is a no-op since it is enabled by
+ * default and on BSD it uses TCP_NOPUSH to do
+ * the same thing( which it was not configured to
+ * use).  This cleanup of the api occured on 8/1/17
+ * I imagine if after more than 1 year of no-one
+ * complaining, and a major upgrade release we
+ * can deprecate and remove this function call
+ */
 int sockopt_cork(int sock, int onoff)
 {
-#ifdef TCP_CORK
-       return setsockopt(sock, IPPROTO_TCP, TCP_CORK, &onoff, sizeof(onoff));
-#else
        return 0;
-#endif
 }
 
 int sockopt_mark_default(int sock, int mark, struct zebra_privs_t *cap)
diff --git a/lib/subdir.am b/lib/subdir.am
new file mode 100644 (file)
index 0000000..15ce8ec
--- /dev/null
@@ -0,0 +1,263 @@
+#
+# libfrr
+#
+lib_LTLIBRARIES += lib/libfrr.la
+lib_libfrr_la_LDFLAGS = -version-info 0:0:0 
+lib_libfrr_la_LIBADD = @LIBCAP@
+
+lib_libfrr_la_SOURCES = \
+       lib/bfd.c \
+       lib/buffer.c \
+       lib/checksum.c \
+       lib/command.c \
+       lib/command_graph.c \
+       lib/command_lex.l \
+       lib/command_match.c \
+       lib/command_parse.y \
+       lib/csv.c \
+       lib/distribute.c \
+       lib/event_counter.c \
+       lib/filter.c \
+       lib/frr_pthread.c \
+       lib/getopt.c \
+       lib/getopt1.c \
+       lib/grammar_sandbox.c \
+       lib/graph.c \
+       lib/hash.c \
+       lib/hook.c \
+       lib/if.c \
+       lib/if_rmap.c \
+       lib/imsg-buffer.c \
+       lib/imsg.c \
+       lib/jhash.c \
+       lib/json.c \
+       lib/keychain.c \
+       lib/libfrr.c \
+       lib/linklist.c \
+       lib/log.c \
+       lib/md5.c \
+       lib/memory.c \
+       lib/memory_vty.c \
+       lib/module.c \
+       lib/network.c \
+       lib/nexthop.c \
+       lib/ns.c \
+       lib/openbsd-tree.c \
+       lib/pid_output.c \
+       lib/plist.c \
+       lib/pqueue.c \
+       lib/prefix.c \
+       lib/privs.c \
+       lib/ptm_lib.c \
+       lib/qobj.c \
+       lib/routemap.c \
+       lib/sbuf.c \
+       lib/sha256.c \
+       lib/sigevent.c \
+       lib/skiplist.c \
+       lib/sockopt.c \
+       lib/sockunion.c \
+       lib/spf_backoff.c \
+       lib/srcdest_table.c \
+       lib/stream.c \
+       lib/strlcat.c \
+       lib/strlcpy.c \
+       lib/systemd.c \
+       lib/table.c \
+       lib/termtable.c \
+       lib/thread.c \
+       lib/vector.c \
+       lib/vrf.c \
+       lib/vty.c \
+       lib/wheel.c \
+       lib/workqueue.c \
+       lib/zclient.c \
+       # end
+
+lib/plist_clippy.c: $(CLIPPY_DEPS)
+lib/plist.lo: lib/plist_clippy.c
+
+pkginclude_HEADERS += \
+       lib/bfd.h \
+       lib/bitfield.h \
+       lib/buffer.h \
+       lib/checksum.h \
+       lib/command.h \
+       lib/command_graph.h \
+       lib/command_match.h \
+       lib/csv.h \
+       lib/distribute.h \
+       lib/event_counter.h \
+       lib/fifo.h \
+       lib/filter.h \
+       lib/frr_pthread.h \
+       lib/frratomic.h \
+       lib/getopt.h \
+       lib/graph.h \
+       lib/hash.h \
+       lib/hook.h \
+       lib/if.h \
+       lib/if_rmap.h \
+       lib/imsg.h \
+       lib/ipaddr.h \
+       lib/jhash.h \
+       lib/json.h \
+       lib/keychain.h \
+       lib/libfrr.h \
+       lib/libospf.h \
+       lib/linklist.h \
+       lib/log.h \
+       lib/md5.h \
+       lib/memory.h \
+       lib/memory_vty.h \
+       lib/module.h \
+       lib/monotime.h \
+       lib/mpls.h \
+       lib/network.h \
+       lib/nexthop.h \
+       lib/ns.h \
+       lib/openbsd-queue.h \
+       lib/openbsd-tree.h \
+       lib/plist.h \
+       lib/pqueue.h \
+       lib/prefix.h \
+       lib/privs.h \
+       lib/ptm_lib.h \
+       lib/pw.h \
+       lib/qobj.h \
+       lib/route_types.h \
+       lib/routemap.h \
+       lib/sbuf.h \
+       lib/sha256.h \
+       lib/sigevent.h \
+       lib/skiplist.h \
+       lib/smux.h \
+       lib/sockopt.h \
+       lib/sockunion.h \
+       lib/spf_backoff.h \
+       lib/srcdest_table.h \
+       lib/stream.h \
+       lib/systemd.h \
+       lib/table.h \
+       lib/termtable.h \
+       lib/thread.h \
+       lib/vector.h \
+       lib/version.h \
+       lib/vlan.h \
+       lib/vrf.h \
+       lib/vrf_int.h \
+       lib/vty.h \
+       lib/vxlan.h \
+       lib/wheel.h \
+       lib/workqueue.h \
+       lib/zassert.h \
+       lib/zclient.h \
+       lib/zebra.h \
+       # end
+
+noinst_HEADERS += \
+       lib/clippy.h \
+       lib/log_int.h \
+       lib/plist_int.h \
+       #end
+
+#
+# SNMP support
+#
+if SNMP
+lib_LTLIBRARIES += lib/libfrrsnmp.la
+endif
+
+lib_libfrrsnmp_la_CFLAGS = $(WERROR) $(SNMP_CFLAGS)
+lib_libfrrsnmp_la_LDFLAGS = -version-info 0:0:0
+lib_libfrrsnmp_la_LIBADD = lib/libfrr.la $(SNMP_LIBS)
+lib_libfrrsnmp_la_SOURCES = \
+       lib/agentx.c \
+       lib/smux.c \
+       lib/snmp.c \
+       # end
+
+#
+# CLI utilities
+#
+noinst_PROGRAMS += \
+       lib/clippy \
+       lib/grammar_sandbox \
+       # end
+
+lib_grammar_sandbox_SOURCES = \
+       lib/grammar_sandbox_main.c
+lib_grammar_sandbox_LDADD = \
+       lib/libfrr.la
+
+lib_clippy_CPPFLAGS = -D_GNU_SOURCE -I$(top_srcdir)/lib
+lib_clippy_CFLAGS = $(PYTHON_CFLAGS)
+lib_clippy_LDADD = $(PYTHON_LIBS)
+lib_clippy_SOURCES = \
+       lib/clippy.c \
+       lib/command_graph.c \
+       lib/command_lex.l \
+       lib/command_parse.y \
+       lib/command_py.c \
+       lib/defun_lex.l \
+       lib/graph.c \
+       lib/memory.c \
+       lib/vector.c \
+       # end
+
+
+#
+# generated sources & extra foo
+#
+EXTRA_DIST += \
+       lib/command_lex.h \
+       lib/gitversion.pl \
+       lib/queue.h \
+       lib/route_types.pl \
+       lib/route_types.txt \
+       # end
+
+BUILT_SOURCES += \
+       lib/command_lex.h \
+       lib/command_parse.h \
+       lib/gitversion.h \
+       lib/route_types.h \
+       # end
+
+## force route_types.h
+$(lib_clippy_OBJECTS): lib/route_types.h
+$(lib_libfrr_la_OBJECTS): lib/route_types.h
+
+AM_YFLAGS = -d -Dapi.prefix=@BISON_OPENBRACE@cmd_yy@BISON_CLOSEBRACE@ @BISON_VERBOSE@
+
+lib/command_lex.h: lib/command_lex.c
+       @if test ! -f $@; then rm -f "lib/command_lex.c"; else :; fi
+       @if test ! -f $@; then $(MAKE) $(AM_MAKEFLAGS) "lib/command_lex.c"; else :; fi
+lib/command_lex.lo: lib/command_parse.h
+lib/command_parse.lo: lib/command_lex.h
+lib/lib_clippy-command_lex.$(OBJEXT): lib/command_parse.h
+lib/lib_clippy-command_parse.$(OBJEXT): lib/command_lex.h
+
+lib/route_types.h: $(top_srcdir)/lib/route_types.txt $(top_srcdir)/lib/route_types.pl
+       @PERL@ $(top_srcdir)/lib/route_types.pl < $(top_srcdir)/lib/route_types.txt > $@
+
+if GIT_VERSION
+# bit of a trick here to always have up-to-date git stamps without triggering
+# unneccessary rebuilds.  .PHONY causes the .tmp file to be rebuilt always,
+# but if we use that on gitversion.h it'll ripple through the .c file deps.
+# (even if gitversion.h's file timestamp doesn't change, make will think it
+# did, because of .PHONY...)
+
+.PHONY: lib/gitversion.h.tmp
+.SILENT: lib/gitversion.h lib/gitversion.h.tmp
+GITH=lib/gitversion.h
+lib/gitversion.h.tmp: $(top_srcdir)/.git
+       @PERL@ $(top_srcdir)/lib/gitversion.pl $(top_srcdir) > ${GITH}.tmp
+lib/gitversion.h: lib/gitversion.h.tmp
+       { test -f ${GITH} && diff -s -q ${GITH}.tmp ${GITH}; } || cp ${GITH}.tmp ${GITH}
+
+else
+.PHONY: lib/gitversion.h
+lib/gitversion.h:
+       true
+endif
index 2defa4fb62e9bc27d993c5fb1b6f7439566a1a17..833adb9a3702de80abf67d53b6caef039d101066 100644 (file)
@@ -27,7 +27,6 @@
 #include "table.h"
 #include "memory.h"
 #include "sockunion.h"
-#include "jhash.h"
 
 DEFINE_MTYPE(LIB, ROUTE_TABLE, "Route table")
 DEFINE_MTYPE(LIB, ROUTE_NODE, "Route node")
@@ -35,18 +34,6 @@ DEFINE_MTYPE(LIB, ROUTE_NODE, "Route node")
 static void route_node_delete(struct route_node *);
 static void route_table_free(struct route_table *);
 
-static unsigned route_table_hash_key(void *pp)
-{
-       struct prefix copy;
-
-       /* make sure *all* unused bits are zero, particularly including
-        * alignment /
-        * padding and unused prefix bytes. */
-       memset(&copy, 0, sizeof(copy));
-       prefix_copy(&copy, (struct prefix *)pp);
-       return jhash(&copy, sizeof(copy), 0x55aa5a5a);
-}
-
 static int route_table_hash_cmp(const void *a, const void *b)
 {
        const struct prefix *pa = a, *pb = b;
@@ -63,7 +50,7 @@ route_table_init_with_delegate(route_table_delegate_t *delegate)
 
        rt = XCALLOC(MTYPE_ROUTE_TABLE, sizeof(struct route_table));
        rt->delegate = delegate;
-       rt->hash = hash_create(route_table_hash_key, route_table_hash_cmp,
+       rt->hash = hash_create(prefix_hash_key, route_table_hash_cmp,
                               "route table hash");
        return rt;
 }
@@ -88,6 +75,7 @@ static struct route_node *route_node_set(struct route_table *table,
        node = route_node_new(table);
 
        prefix_copy(&node->p, prefix);
+       apply_mask(&node->p);
        node->table = table;
 
        inserted = hash_get(node->table->hash, node, hash_alloc_intern);
index 5db470ef488b843472da3d829e243378aed7fe1c..4a5c61d036f610d8753feb624c7ce2470a640d1e 100644 (file)
@@ -47,6 +47,9 @@ DEFINE_MTYPE_STATIC(LIB, THREAD_STATS, "Thread stats")
                write(m->io_pipe[1], &wakebyte, 1);                            \
        } while (0);
 
+/* max # of thread_fetch() calls before we force a poll() */
+#define MAX_TICK_IO 1000
+
 /* control variable for initializer */
 pthread_once_t init_once = PTHREAD_ONCE_INIT;
 pthread_key_t thread_current;
@@ -337,9 +340,6 @@ static void cancelreq_del(void *cr)
 /* initializer, only ever called once */
 static void initializer()
 {
-       if (!masters)
-               masters = list_new();
-
        pthread_key_create(&thread_current, NULL);
 }
 
@@ -412,9 +412,12 @@ struct thread_master *thread_master_create(const char *name)
        rv->handler.copy = XCALLOC(MTYPE_THREAD_MASTER,
                                   sizeof(struct pollfd) * rv->handler.pfdsize);
 
-       /* add to list */
+       /* add to list of threadmasters */
        pthread_mutex_lock(&masters_mtx);
        {
+               if (!masters)
+                       masters = list_new();
+
                listnode_add(masters, rv);
        }
        pthread_mutex_unlock(&masters_mtx);
@@ -548,6 +551,10 @@ void thread_master_free(struct thread_master *m)
        pthread_mutex_lock(&masters_mtx);
        {
                listnode_delete(masters, m);
+               if (masters->count == 0) {
+                       list_free (masters);
+                       masters = NULL;
+               }
        }
        pthread_mutex_unlock(&masters_mtx);
 
@@ -1312,16 +1319,16 @@ struct thread *thread_fetch(struct thread_master *m, struct thread *fetch)
                /* Process any pending cancellation requests */
                do_thread_cancel(m);
 
-               /* Post events to ready queue. This must come before the
-                * following block
-                * since events should occur immediately */
+               /*
+                * Post events to ready queue. This must come before the
+                * following block since events should occur immediately
+                */
                thread_process(&m->event);
 
-               /* If there are no tasks on the ready queue, we will poll()
-                * until a timer
-                * expires or we receive I/O, whichever comes first. The
-                * strategy for doing
-                * this is:
+               /*
+                * If there are no tasks on the ready queue, we will poll()
+                * until a timer expires or we receive I/O, whichever comes
+                * first. The strategy for doing this is:
                 *
                 * - If there are events pending, set the poll() timeout to zero
                 * - If there are no events pending, but there are timers
@@ -1333,9 +1340,8 @@ struct thread *thread_fetch(struct thread_master *m, struct thread *fetch)
                 * - If nothing is pending, it's time for the application to die
                 *
                 * In every case except the last, we need to hit poll() at least
-                * once per
-                * loop to avoid starvation by events */
-
+                * once per loop to avoid starvation by events
+                */
                if (m->ready.count == 0)
                        tw = thread_timer_wait(m->timer, &tv);
 
@@ -1348,37 +1354,53 @@ struct thread *thread_fetch(struct thread_master *m, struct thread *fetch)
                        break;
                }
 
-               /* Copy pollfd array + # active pollfds in it. Not necessary to
-                * copy
-                * the array size as this is fixed. */
+               /*
+                * Copy pollfd array + # active pollfds in it. Not necessary to
+                * copy the array size as this is fixed.
+                */
                m->handler.copycount = m->handler.pfdcount;
                memcpy(m->handler.copy, m->handler.pfds,
                       m->handler.copycount * sizeof(struct pollfd));
 
-               pthread_mutex_unlock(&m->mtx);
-               {
-                       num = fd_poll(m, m->handler.copy, m->handler.pfdsize,
-                                     m->handler.copycount, tw);
-               }
-               pthread_mutex_lock(&m->mtx);
+               /*
+                * Attempt to flush ready queue before going into poll().
+                * This is performance-critical. Think twice before modifying.
+                */
+               if (m->ready.count == 0 || m->tick_since_io >= MAX_TICK_IO) {
+                       pthread_mutex_unlock(&m->mtx);
+                       {
+                               m->tick_since_io = 0;
+                               num = fd_poll(m, m->handler.copy,
+                                             m->handler.pfdsize,
+                                             m->handler.copycount, tw);
+                       }
+                       pthread_mutex_lock(&m->mtx);
+
+                       /* Handle any errors received in poll() */
+                       if (num < 0) {
+                               if (errno == EINTR) {
+                                       pthread_mutex_unlock(&m->mtx);
+                                       /* loop around to signal handler */
+                                       continue;
+                               }
 
-               /* Handle any errors received in poll() */
-               if (num < 0) {
-                       if (errno == EINTR) {
+                               /* else die */
+                               zlog_warn("poll() error: %s",
+                                         safe_strerror(errno));
                                pthread_mutex_unlock(&m->mtx);
-                               continue; /* loop around to signal handler */
+                               fetch = NULL;
+                               break;
                        }
 
-                       /* else die */
-                       zlog_warn("poll() error: %s", safe_strerror(errno));
-                       pthread_mutex_unlock(&m->mtx);
-                       fetch = NULL;
-                       break;
-               }
+                       /*
+                        * Since we could have received more cancellation
+                        * requests during poll(), process those
+                        */
+                       do_thread_cancel(m);
 
-               /* Since we could have received more cancellation requests
-                * during poll(), process those */
-               do_thread_cancel(m);
+               } else {
+                       m->tick_since_io++;
+               }
 
                /* Post timers to ready queue. */
                monotime(&now);
@@ -1388,8 +1410,7 @@ struct thread *thread_fetch(struct thread_master *m, struct thread *fetch)
                if (num > 0)
                        thread_process_io(m, num);
 
-               /* If we have a ready task, break the loop and return it to the
-                * caller */
+               /* have a ready task ==> return it to caller */
                if ((thread = thread_trim_head(&m->ready))) {
                        fetch = thread_run(m, thread, fetch);
                        if (fetch->ref)
index c830446e10209f4ead167c06729fae3d757eef41..86bf4df7c0c5facb96b091b86dc0de5de682799f 100644 (file)
@@ -70,6 +70,7 @@ struct cancel_req {
 struct thread_master {
        char *name;
 
+       int tick_since_io;
        struct thread **read;
        struct thread **write;
        struct pqueue *timer;
index 00579550e4723a2891d584b721c5cfad3524247e..31fcaf1026f4b883aa94fd37e004c6d7069b184b 100644 (file)
--- a/lib/vty.c
+++ b/lib/vty.c
@@ -306,6 +306,7 @@ struct vty *vty_new()
 {
        struct vty *new = XCALLOC(MTYPE_VTY, sizeof(struct vty));
 
+       new->fd = new->wfd = -1;
        new->obuf = buffer_new(0); /* Use default buffer size. */
        new->buf = XCALLOC(MTYPE_VTY, VTY_BUFSIZ);
        new->error_buf = XCALLOC(MTYPE_VTY, VTY_BUFSIZ);
@@ -683,6 +684,7 @@ static void vty_end_config(struct vty *vty)
                break;
        case CONFIG_NODE:
        case INTERFACE_NODE:
+       case PW_NODE:
        case ZEBRA_NODE:
        case RIP_NODE:
        case RIPNG_NODE:
@@ -1093,6 +1095,7 @@ static void vty_stop_input(struct vty *vty)
                break;
        case CONFIG_NODE:
        case INTERFACE_NODE:
+       case PW_NODE:
        case ZEBRA_NODE:
        case RIP_NODE:
        case RIPNG_NODE:
@@ -2129,16 +2132,21 @@ void vty_close(struct vty *vty)
                        XFREE(MTYPE_VTY_HIST, vty->hist[i]);
 
        /* Unset vector. */
-       vector_unset(vtyvec, vty->fd);
+       if (vty->fd != -1)
+               vector_unset(vtyvec, vty->fd);
 
        if (vty->wfd > 0 && vty->type == VTY_FILE)
                fsync(vty->wfd);
 
-       /* Close socket. */
-       if (vty->fd > 0) {
+       /* Close socket.
+        * note check is for fd > STDERR_FILENO, not fd != -1.
+        * We never close stdin/stdout/stderr here, because we may be
+        * running in foreground mode with logging to stdout.  Also,
+        * additionally, we'd need to replace these fds with /dev/null. */
+       if (vty->wfd > STDERR_FILENO && vty->wfd != vty->fd)
+               close(vty->wfd);
+       if (vty->fd > STDERR_FILENO) {
                close(vty->fd);
-               if (vty->wfd > 0 && vty->wfd != vty->fd)
-                       close(vty->wfd);
        } else
                was_stdio = true;
 
@@ -2186,13 +2194,14 @@ static void vty_read_file(FILE *confp)
        unsigned int line_num = 0;
 
        vty = vty_new();
-       vty->wfd = dup(STDERR_FILENO); /* vty_close() will close this */
-       if (vty->wfd < 0) {
-               /* Fine, we couldn't make a new fd. vty_close doesn't close
-                * stdout. */
-               vty->wfd = STDOUT_FILENO;
-       }
-       vty->fd = STDIN_FILENO;
+       /* vty_close won't close stderr;  if some config command prints
+        * something it'll end up there.  (not ideal; it'd be beter if output
+        * from a file-load went to logging instead.  Also note that if this
+        * function is called after daemonizing, stderr will be /dev/null.)
+        *
+        * vty->fd will be -1 from vty_new()
+        */
+       vty->wfd = STDERR_FILENO;
        vty->type = VTY_FILE;
        vty->node = CONFIG_NODE;
 
@@ -2200,7 +2209,7 @@ static void vty_read_file(FILE *confp)
        ret = config_from_file(vty, confp, &line_num);
 
        /* Flush any previous errors before printing messages below */
-       buffer_flush_all(vty->obuf, vty->fd);
+       buffer_flush_all(vty->obuf, vty->wfd);
 
        if (!((ret == CMD_SUCCESS) || (ret == CMD_ERR_NOTHING_TODO))) {
                const char *message = NULL;
index 0839f7fb68dd836d0759dfddef5f20667d8fa27c..0980f73afabcb759e67aea2b0b6bf16f6efafae2 100644 (file)
--- a/lib/vty.h
+++ b/lib/vty.h
@@ -166,6 +166,11 @@ static inline void vty_push_context(struct vty *vty, int node, uint64_t id)
 #define VTY_DECLVAR_CONTEXT_SUB(structname, ptr)                               \
        struct structname *ptr = VTY_GET_CONTEXT_SUB(structname);              \
        VTY_CHECK_CONTEXT(ptr);
+#define VTY_DECLVAR_INSTANCE_CONTEXT(structname, ptr)                          \
+       if (vty->qobj_index == 0)                                              \
+               return CMD_NOT_MY_INSTANCE;                                    \
+       struct structname *ptr = VTY_GET_CONTEXT(structname);                  \
+       VTY_CHECK_CONTEXT(ptr);
 
 struct vty_arg {
        const char *name;
index a54d8749a399d2b99ef6c8d0ad2ff97dfd4c6b8a..893d769e3af725e00b127974adffe75854e719a6 100644 (file)
@@ -1834,6 +1834,69 @@ int lm_release_label_chunk(struct zclient *zclient, uint32_t start,
        return 0;
 }
 
+int zebra_send_pw(struct zclient *zclient, int command, struct zapi_pw *pw)
+{
+       struct stream *s;
+
+       /* Reset stream. */
+       s = zclient->obuf;
+       stream_reset(s);
+
+       zclient_create_header(s, command, VRF_DEFAULT);
+       stream_write(s, pw->ifname, IF_NAMESIZE);
+       stream_putl(s, pw->ifindex);
+
+       /* Put type */
+       stream_putl(s, pw->type);
+
+       /* Put nexthop */
+       stream_putl(s, pw->af);
+       switch (pw->af) {
+       case AF_INET:
+               stream_put_in_addr(s, &pw->nexthop.ipv4);
+               break;
+       case AF_INET6:
+               stream_write(s, (u_char *)&pw->nexthop.ipv6, 16);
+               break;
+       default:
+               zlog_err("%s: unknown af", __func__);
+               return -1;
+       }
+
+       /* Put labels */
+       stream_putl(s, pw->local_label);
+       stream_putl(s, pw->remote_label);
+
+       /* Put flags */
+       stream_putc(s, pw->flags);
+
+       /* Protocol specific fields */
+       stream_write(s, &pw->data, sizeof(union pw_protocol_fields));
+
+       /* Put length at the first point of the stream. */
+       stream_putw_at(s, 0, stream_get_endp(s));
+
+       return zclient_send_message(zclient);
+}
+
+/*
+ * Receive PW status update from Zebra and send it to LDE process.
+ */
+void zebra_read_pw_status_update(int command, struct zclient *zclient,
+                                zebra_size_t length, vrf_id_t vrf_id,
+                                struct zapi_pw_status *pw)
+{
+       struct stream *s;
+
+       memset(pw, 0, sizeof(struct zapi_pw_status));
+       s = zclient->ibuf;
+
+       /* Get data. */
+       stream_get(pw->ifname, s, IF_NAMESIZE);
+       pw->ifindex = stream_getl(s);
+       pw->status = stream_getl(s);
+}
+
 /* Zebra client message read function. */
 static int zclient_read(struct thread *thread)
 {
@@ -2061,6 +2124,11 @@ static int zclient_read(struct thread *thread)
                        (*zclient->local_macip_del)(command, zclient, length,
                                                    vrf_id);
                break;
+       case ZEBRA_PW_STATUS_UPDATE:
+               if (zclient->pw_status_update)
+                       (*zclient->pw_status_update)(command, zclient, length,
+                                                    vrf_id);
+               break;
        default:
                break;
        }
@@ -2184,3 +2252,23 @@ void zclient_serv_path_set(char *path)
        /* it seems that path is unix socket */
        zclient_serv_path = path;
 }
+
+void zclient_interface_set_master(struct zclient *client,
+                                 struct interface *master,
+                                 struct interface *slave)
+{
+       struct stream *s;
+
+       s = client->obuf;
+       stream_reset(s);
+
+       zclient_create_header(s, ZEBRA_INTERFACE_SET_MASTER, master->vrf_id);
+
+       stream_putw(s, master->vrf_id);
+       stream_putl(s, master->ifindex);
+       stream_putw(s, slave->vrf_id);
+       stream_putl(s, slave->ifindex);
+
+       stream_putw_at(s, 0, stream_get_endp(s));
+       zclient_send_message(client);
+}
index efa5c32c16ef8bcecccb693d26b225c5db7907c6..8a2729543fd9785be667839fd1fdac173733dc62 100644 (file)
 /* For vrf_bitmap_t. */
 #include "vrf.h"
 
+/* For union g_addr */
+#include "nexthop.h"
+
+/* For union pw_protocol_fields */
+#include "pw.h"
+
 /* For input/output buffer to zebra. */
 #define ZEBRA_MAX_PACKET_SIZ          4096
 
@@ -44,6 +50,7 @@ typedef enum {
        ZEBRA_INTERFACE_ADDRESS_DELETE,
        ZEBRA_INTERFACE_UP,
        ZEBRA_INTERFACE_DOWN,
+       ZEBRA_INTERFACE_SET_MASTER,
        ZEBRA_IPV4_ROUTE_ADD,
        ZEBRA_IPV4_ROUTE_DELETE,
        ZEBRA_IPV6_ROUTE_ADD,
@@ -105,6 +112,11 @@ typedef enum {
        ZEBRA_MACIP_DEL,
        ZEBRA_REMOTE_MACIP_ADD,
        ZEBRA_REMOTE_MACIP_DEL,
+       ZEBRA_PW_ADD,
+       ZEBRA_PW_DELETE,
+       ZEBRA_PW_SET,
+       ZEBRA_PW_UNSET,
+       ZEBRA_PW_STATUS_UPDATE,
 } zebra_message_types_t;
 
 struct redist_proto {
@@ -186,6 +198,7 @@ struct zclient {
        int (*local_vni_del)(int, struct zclient *, uint16_t, vrf_id_t);
        int (*local_macip_add)(int, struct zclient *, uint16_t, vrf_id_t);
        int (*local_macip_del)(int, struct zclient *, uint16_t, vrf_id_t);
+       int (*pw_status_update)(int, struct zclient *, uint16_t, vrf_id_t);
 };
 
 /* Zebra API message flag. */
@@ -265,6 +278,25 @@ struct zapi_ipv4 {
        vrf_id_t vrf_id;
 };
 
+struct zapi_pw {
+       char ifname[IF_NAMESIZE];
+       ifindex_t ifindex;
+       int type;
+       int af;
+       union g_addr nexthop;
+       uint32_t local_label;
+       uint32_t remote_label;
+       uint8_t flags;
+       union pw_protocol_fields data;
+       uint8_t protocol;
+};
+
+struct zapi_pw_status {
+       char ifname[IF_NAMESIZE];
+       ifindex_t ifindex;
+       uint32_t status;
+};
+
 /* Prototypes of zebra client service functions. */
 extern struct zclient *zclient_new(struct thread_master *);
 extern void zclient_init(struct zclient *, int, u_short);
@@ -311,6 +343,9 @@ extern int zclient_read_header(struct stream *s, int sock, u_int16_t *size,
                               u_char *marker, u_char *version,
                               vrf_id_t *vrf_id, u_int16_t *cmd);
 
+extern void zclient_interface_set_master(struct zclient *client,
+                                        struct interface *master,
+                                        struct interface *slave);
 extern struct interface *zebra_interface_add_read(struct stream *, vrf_id_t);
 extern struct interface *zebra_interface_state_read(struct stream *s, vrf_id_t);
 extern struct connected *zebra_interface_address_read(int, struct stream *,
@@ -334,6 +369,12 @@ extern int lm_get_label_chunk(struct zclient *zclient, u_char keep,
                              uint32_t *end);
 extern int lm_release_label_chunk(struct zclient *zclient, uint32_t start,
                                  uint32_t end);
+extern int zebra_send_pw(struct zclient *zclient, int command,
+                        struct zapi_pw *pw);
+extern void zebra_read_pw_status_update(int command, struct zclient *zclient,
+                                       zebra_size_t length, vrf_id_t vrf_id,
+                                       struct zapi_pw_status *pw);
+
 /* IPv6 prefix add and delete function prototype. */
 
 struct zapi_ipv6 {
index 8e1c4db8043a49cc446da7fc9610ce19836eca77..6d64bbd670cd036a901d4da89ed5dd68fd1f2d73 100644 (file)
@@ -126,6 +126,13 @@ typedef unsigned char u_int8_t;
 #define __APPLE_USE_RFC_3542
 #endif
 
+#ifndef HAVE_LIBCRYPT
+#   ifdef HAVE_LIBCRYPTO
+#      include <openssl/des.h>
+#      define crypt DES_crypt
+#   endif
+#endif
+
 #include "openbsd-tree.h"
 
 #include <netinet/in.h>
@@ -416,22 +423,15 @@ extern const char *zserv_command_string(unsigned int command);
 typedef enum { AFI_IP = 1, AFI_IP6 = 2, AFI_L2VPN = 3, AFI_MAX = 4 } afi_t;
 
 /* Subsequent Address Family Identifier. */
-#define SAFI_UNICAST              1
-#define SAFI_MULTICAST            2
-#define SAFI_MPLS_VPN             3
-#define SAFI_RESERVED_4           4
-#define SAFI_ENCAP               5
-#define SAFI_RESERVED_5           5
-#define SAFI_EVPN                 6
-#define SAFI_LABELED_UNICAST      7
-#define SAFI_MAX                  8
-
-#define IANA_SAFI_RESERVED            0
-#define IANA_SAFI_UNICAST             1
-#define IANA_SAFI_MULTICAST           2
-#define IANA_SAFI_LABELED_UNICAST     4
-#define IANA_SAFI_ENCAP               7
-#define IANA_SAFI_MPLS_VPN            128
+typedef enum {
+       SAFI_UNICAST = 1,
+       SAFI_MULTICAST = 2,
+       SAFI_MPLS_VPN = 3,
+       SAFI_ENCAP = 4,
+       SAFI_EVPN = 5,
+       SAFI_LABELED_UNICAST = 6,
+       SAFI_MAX = 7
+} safi_t;
 
 /*
  * The above AFI and SAFI definitions are for internal use. The protocol
@@ -451,12 +451,15 @@ typedef enum {
        IANA_AFI_IP6MR = 129
 } iana_afi_t;
 
-#define IANA_SAFI_RESERVED            0
-#define IANA_SAFI_UNICAST             1
-#define IANA_SAFI_MULTICAST           2
-#define IANA_SAFI_ENCAP               7
-#define IANA_SAFI_EVPN                70
-#define IANA_SAFI_MPLS_VPN            128
+typedef enum {
+       IANA_SAFI_RESERVED = 0,
+       IANA_SAFI_UNICAST = 1,
+       IANA_SAFI_MULTICAST = 2,
+       IANA_SAFI_LABELED_UNICAST = 4,
+       IANA_SAFI_ENCAP = 7,
+       IANA_SAFI_EVPN = 70,
+       IANA_SAFI_MPLS_VPN = 128
+} iana_safi_t;
 
 /* Default Administrative Distance of each protocol. */
 #define ZEBRA_KERNEL_DISTANCE_DEFAULT      0
@@ -477,8 +480,6 @@ typedef enum {
 #define UNSET_FLAG(V,F)      (V) &= ~(F)
 #define RESET_FLAG(V)        (V) = 0
 
-typedef u_int8_t safi_t;
-
 /* Zebra types. Used in Zserv message header. */
 typedef u_int16_t zebra_size_t;
 typedef u_int16_t zebra_command_t;
@@ -492,58 +493,70 @@ typedef uint32_t route_tag_t;
 
 static inline afi_t afi_iana2int(iana_afi_t afi)
 {
-       if (afi == IANA_AFI_IPV4)
+       switch (afi) {
+       case IANA_AFI_IPV4:
                return AFI_IP;
-       if (afi == IANA_AFI_IPV6)
+       case IANA_AFI_IPV6:
                return AFI_IP6;
-       if (afi == IANA_AFI_L2VPN)
+       case IANA_AFI_L2VPN:
                return AFI_L2VPN;
-       return AFI_MAX;
+       default:
+               return AFI_MAX;
+       }
 }
 
 static inline iana_afi_t afi_int2iana(afi_t afi)
 {
-       if (afi == AFI_IP)
+       switch (afi) {
+       case AFI_IP:
                return IANA_AFI_IPV4;
-       if (afi == AFI_IP6)
+       case AFI_IP6:
                return IANA_AFI_IPV6;
-       if (afi == AFI_L2VPN)
+       case AFI_L2VPN:
                return IANA_AFI_L2VPN;
-       return IANA_AFI_RESERVED;
+       default:
+               return IANA_AFI_RESERVED;
+       }
 }
 
-static inline safi_t safi_iana2int(safi_t safi)
+static inline safi_t safi_iana2int(iana_safi_t safi)
 {
-       if (safi == IANA_SAFI_UNICAST)
+       switch (safi) {
+       case IANA_SAFI_UNICAST:
                return SAFI_UNICAST;
-       if (safi == IANA_SAFI_MULTICAST)
+       case IANA_SAFI_MULTICAST:
                return SAFI_MULTICAST;
-       if (safi == IANA_SAFI_MPLS_VPN)
+       case IANA_SAFI_MPLS_VPN:
                return SAFI_MPLS_VPN;
-       if (safi == IANA_SAFI_ENCAP)
+       case IANA_SAFI_ENCAP:
                return SAFI_ENCAP;
-       if (safi == IANA_SAFI_EVPN)
+       case IANA_SAFI_EVPN:
                return SAFI_EVPN;
-       if (safi == IANA_SAFI_LABELED_UNICAST)
+       case IANA_SAFI_LABELED_UNICAST:
                return SAFI_LABELED_UNICAST;
-       return SAFI_MAX;
+       default:
+               return SAFI_MAX;
+       }
 }
 
-static inline safi_t safi_int2iana(safi_t safi)
+static inline iana_safi_t safi_int2iana(safi_t safi)
 {
-       if (safi == SAFI_UNICAST)
+       switch (safi) {
+       case SAFI_UNICAST:
                return IANA_SAFI_UNICAST;
-       if (safi == SAFI_MULTICAST)
+       case SAFI_MULTICAST:
                return IANA_SAFI_MULTICAST;
-       if (safi == SAFI_MPLS_VPN)
+       case SAFI_MPLS_VPN:
                return IANA_SAFI_MPLS_VPN;
-       if (safi == SAFI_ENCAP)
+       case SAFI_ENCAP:
                return IANA_SAFI_ENCAP;
-       if (safi == SAFI_EVPN)
+       case SAFI_EVPN:
                return IANA_SAFI_EVPN;
-       if (safi == SAFI_LABELED_UNICAST)
+       case SAFI_LABELED_UNICAST:
                return IANA_SAFI_LABELED_UNICAST;
-       return IANA_SAFI_RESERVED;
+       default:
+               return IANA_SAFI_RESERVED;
+       }
 }
 
 #endif /* _ZEBRA_H */
diff --git a/m4/Makefile.am b/m4/Makefile.am
deleted file mode 100644 (file)
index 49a29bd..0000000
+++ /dev/null
@@ -1 +0,0 @@
-EXTRA_DIST=Makefile.am README.txt
index bd884bbc51390781012e964afc65490406322257..3ebdbf27ba9e5b2418a2377ba3ef4ee670464aeb 100644 (file)
@@ -289,7 +289,7 @@ int nhrp_cache_update_binding(struct nhrp_cache *c, enum nhrp_cache_type type, i
                if (holding_time > 0)
                        c->new.expires = monotime(NULL) + holding_time;
                else if (holding_time < 0)
-                       c->new.type = NHRP_CACHE_INVALID;
+                       nhrp_cache_reset_new(c);
 
                if (c->new.type == NHRP_CACHE_INVALID ||
                    c->new.type >= NHRP_CACHE_STATIC ||
index 7c5d80336c01b0268a1d02c2066cd80982bb4a64..012d5cd87c0d143a10a9615f2b9fb2a4217634f3 100644 (file)
@@ -128,8 +128,8 @@ int main(int argc, char **argv)
 
        /* Library inits. */
        master = frr_init();
-       nhrp_interface_init();
        vrf_init(NULL, NULL, NULL, NULL);
+       nhrp_interface_init();
        resolver_init();
 
        /* Run with elevated capabilities, as for all netlink activity
index 89972f8f981054281e48fe74092149e975dd6960..c8a608c657e2887efab8c0e98964b566f6bb77a4 100644 (file)
@@ -205,17 +205,18 @@ int nhrp_route_read(int cmd, struct zclient *zclient, zebra_size_t length, vrf_i
 
        /* Type, flags, message. */
        /*type =*/ stream_getc(s);
-       /*flags =*/ stream_getc(s);
+       /*instance =*/ stream_getw(s);
+       /*flags =*/ stream_getl(s);
        message = stream_getc(s);
 
        /* Prefix */
        switch (cmd) {
-       case ZEBRA_IPV4_ROUTE_ADD:
-       case ZEBRA_IPV4_ROUTE_DELETE:
+       case ZEBRA_REDISTRIBUTE_IPV4_ADD:
+       case ZEBRA_REDISTRIBUTE_IPV4_DEL:
                prefix.family = AF_INET;
                break;
-       case ZEBRA_IPV6_ROUTE_ADD:
-       case ZEBRA_IPV6_ROUTE_DELETE:
+       case ZEBRA_REDISTRIBUTE_IPV6_ADD:
+       case ZEBRA_REDISTRIBUTE_IPV6_DEL:
                prefix.family = AF_INET6;
                break;
        default:
@@ -244,7 +245,7 @@ int nhrp_route_read(int cmd, struct zclient *zclient, zebra_size_t length, vrf_i
        if (CHECK_FLAG(message, ZAPI_MESSAGE_METRIC))
                /*metric =*/ stream_getl(s);
 
-       added = (cmd == ZEBRA_IPV4_ROUTE_ADD || cmd == ZEBRA_IPV6_ROUTE_ADD);
+       added = (cmd == ZEBRA_REDISTRIBUTE_IPV4_ADD || cmd == ZEBRA_REDISTRIBUTE_IPV6_ADD);
        debugf(NHRP_DEBUG_ROUTE, "if-route-%s: %s via %s dev %s",
                added ? "add" : "del",
                prefix2str(&prefix, buf[0], sizeof buf[0]),
@@ -342,12 +343,23 @@ enum nhrp_route_type nhrp_route_address(struct interface *in_ifp, union sockunio
        return NHRP_ROUTE_BLACKHOLE;
 }
 
+static void
+nhrp_zebra_connected (struct zclient *zclient)
+{
+       zclient_send_reg_requests(zclient, VRF_DEFAULT);
+       zebra_redistribute_send(ZEBRA_REDISTRIBUTE_ADD, zclient, AFI_IP,
+           ZEBRA_ROUTE_ALL, 0, VRF_DEFAULT);
+       zebra_redistribute_send(ZEBRA_REDISTRIBUTE_ADD, zclient, AFI_IP6,
+           ZEBRA_ROUTE_ALL, 0, VRF_DEFAULT);
+}
+
 void nhrp_zebra_init(void)
 {
        zebra_rib[AFI_IP] = route_table_init();
        zebra_rib[AFI_IP6] = route_table_init();
 
        zclient = zclient_new(master);
+       zclient->zebra_connected = nhrp_zebra_connected;
        zclient->interface_add = nhrp_interface_add;
        zclient->interface_delete = nhrp_interface_delete;
        zclient->interface_up = nhrp_interface_up;
@@ -360,20 +372,6 @@ void nhrp_zebra_init(void)
        zclient->redistribute_route_ipv6_del = nhrp_route_read;
 
        zclient_init(zclient, ZEBRA_ROUTE_NHRP, 0);
-       zclient_redistribute(ZEBRA_REDISTRIBUTE_ADD, zclient, AFI_IP, ZEBRA_ROUTE_KERNEL, 0, VRF_DEFAULT);
-       zclient_redistribute(ZEBRA_REDISTRIBUTE_ADD, zclient, AFI_IP, ZEBRA_ROUTE_CONNECT, 0, VRF_DEFAULT);
-       zclient_redistribute(ZEBRA_REDISTRIBUTE_ADD, zclient, AFI_IP, ZEBRA_ROUTE_STATIC, 0, VRF_DEFAULT);
-       zclient_redistribute(ZEBRA_REDISTRIBUTE_ADD, zclient, AFI_IP, ZEBRA_ROUTE_RIP, 0, VRF_DEFAULT);
-       zclient_redistribute(ZEBRA_REDISTRIBUTE_ADD, zclient, AFI_IP, ZEBRA_ROUTE_OSPF, 0, VRF_DEFAULT);
-       zclient_redistribute(ZEBRA_REDISTRIBUTE_ADD, zclient, AFI_IP, ZEBRA_ROUTE_ISIS, 0, VRF_DEFAULT);
-       zclient_redistribute(ZEBRA_REDISTRIBUTE_ADD, zclient, AFI_IP, ZEBRA_ROUTE_BGP, 0, VRF_DEFAULT);
-       zclient_redistribute(ZEBRA_REDISTRIBUTE_ADD, zclient, AFI_IP6, ZEBRA_ROUTE_KERNEL, 0, VRF_DEFAULT);
-       zclient_redistribute(ZEBRA_REDISTRIBUTE_ADD, zclient, AFI_IP6, ZEBRA_ROUTE_CONNECT, 0, VRF_DEFAULT);
-       zclient_redistribute(ZEBRA_REDISTRIBUTE_ADD, zclient, AFI_IP6, ZEBRA_ROUTE_STATIC, 0, VRF_DEFAULT);
-       zclient_redistribute(ZEBRA_REDISTRIBUTE_ADD, zclient, AFI_IP6, ZEBRA_ROUTE_RIP, 0, VRF_DEFAULT);
-       zclient_redistribute(ZEBRA_REDISTRIBUTE_ADD, zclient, AFI_IP6, ZEBRA_ROUTE_OSPF, 0, VRF_DEFAULT);
-       zclient_redistribute(ZEBRA_REDISTRIBUTE_ADD, zclient, AFI_IP6, ZEBRA_ROUTE_ISIS, 0, VRF_DEFAULT);
-       zclient_redistribute(ZEBRA_REDISTRIBUTE_ADD, zclient, AFI_IP6, ZEBRA_ROUTE_BGP, 0, VRF_DEFAULT);
 }
 
 void nhrp_zebra_terminate(void)
index 7f8341d0e42c67ab91a8fad2eca5c28760fc4853..dd3630af160ce32278a95c2a0f82531313c08757 100644 (file)
@@ -622,7 +622,8 @@ void ospf6_asbr_redistribute_remove(int type, ifindex_t ifindex,
        node = route_node_lookup(ospf6->external_id_table, &prefix_id);
        assert(node);
        node->info = NULL;
-       route_unlock_node(node);
+       route_unlock_node(node); /* to free the lookup lock */
+       route_unlock_node(node); /* to free the original lock */
 
        ospf6_route_remove(match, ospf6->external_table);
        XFREE(MTYPE_OSPF6_EXTERNAL_INFO, info);
index e1a431ea07245f57dd536897e2355077f65733b7..a0dad9344aa0a21cdb1901b4c0310659e5d0e2d0 100644 (file)
@@ -509,7 +509,8 @@ struct ospf6_lsa *ospf6_lsa_create(struct ospf6_lsa_header *header)
 
        /* allocate memory for this LSA */
        new_header =
-               (struct ospf6_lsa_header *)XMALLOC(MTYPE_OSPF6_LSA, lsa_size);
+               (struct ospf6_lsa_header *)XMALLOC(MTYPE_OSPF6_LSA_HEADER,
+                                                  lsa_size);
 
        /* copy LSA from original header */
        memcpy(new_header, header, lsa_size);
@@ -537,7 +538,7 @@ struct ospf6_lsa *ospf6_lsa_create_headeronly(struct ospf6_lsa_header *header)
 
        /* allocate memory for this LSA */
        new_header = (struct ospf6_lsa_header *)XMALLOC(
-               MTYPE_OSPF6_LSA, sizeof(struct ospf6_lsa_header));
+               MTYPE_OSPF6_LSA_HEADER, sizeof(struct ospf6_lsa_header));
 
        /* copy LSA from original header */
        memcpy(new_header, header, sizeof(struct ospf6_lsa_header));
@@ -568,7 +569,7 @@ void ospf6_lsa_delete(struct ospf6_lsa *lsa)
        THREAD_OFF(lsa->refresh);
 
        /* do free */
-       XFREE(MTYPE_OSPF6_LSA, lsa->header);
+       XFREE(MTYPE_OSPF6_LSA_HEADER, lsa->header);
        XFREE(MTYPE_OSPF6_LSA, lsa);
 }
 
index 7e08d58791e13ee57d7f8a31d58e2cfdec36d7f4..418f858a3256a6684b240248a00d404289864fd7 100644 (file)
@@ -83,8 +83,7 @@ static void _lsdb_count_assert(struct ospf6_lsdb *lsdb)
        zlog_debug("PANIC !! lsdb[%p]->count = %d, real = %d", lsdb,
                   lsdb->count, num);
        for (ALL_LSDB(lsdb, debug))
-               zlog_debug("%p %p %s lsdb[%p]", debug->prev, debug->next,
-                          debug->name, debug->lsdb);
+               zlog_debug("%s lsdb[%p]", debug->name, debug->lsdb);
        zlog_debug("DUMP END");
 
        assert(num == lsdb->count);
@@ -139,6 +138,8 @@ void ospf6_lsdb_add(struct ospf6_lsa *lsa, struct ospf6_lsdb *lsdb)
                                        (*lsdb->hook_add)(lsa);
                        }
                }
+               /* to free the lookup lock in node get*/
+               route_unlock_node(current);
                ospf6_lsa_unlock(old);
        }
 
index 133dc2cb3cbebe9e273d6e640bc5387308b1a833..56c232d6da98bbb90c07f2cef085e5fec8e56ca6 100644 (file)
@@ -34,6 +34,7 @@ DEFINE_MTYPE(OSPF6D, OSPF6_ROUTE, "OSPF6 route")
 DEFINE_MTYPE(OSPF6D, OSPF6_PREFIX, "OSPF6 prefix")
 DEFINE_MTYPE(OSPF6D, OSPF6_MESSAGE, "OSPF6 message")
 DEFINE_MTYPE(OSPF6D, OSPF6_LSA, "OSPF6 LSA")
+DEFINE_MTYPE(OSPF6D, OSPF6_LSA_HEADER, "OSPF6 LSA header")
 DEFINE_MTYPE(OSPF6D, OSPF6_LSA_SUMMARY, "OSPF6 LSA summary")
 DEFINE_MTYPE(OSPF6D, OSPF6_LSDB, "OSPF6 LSA database")
 DEFINE_MTYPE(OSPF6D, OSPF6_VERTEX, "OSPF6 vertex")
index 324065c3a10e50d50de5208c299a0449ecc99c86..fe72ee3669763e89cdd4fe490bdb446dc90864e8 100644 (file)
@@ -33,6 +33,7 @@ DECLARE_MTYPE(OSPF6_ROUTE)
 DECLARE_MTYPE(OSPF6_PREFIX)
 DECLARE_MTYPE(OSPF6_MESSAGE)
 DECLARE_MTYPE(OSPF6_LSA)
+DECLARE_MTYPE(OSPF6_LSA_HEADER)
 DECLARE_MTYPE(OSPF6_LSA_SUMMARY)
 DECLARE_MTYPE(OSPF6_LSDB)
 DECLARE_MTYPE(OSPF6_VERTEX)
index e0e9fc9449074f42b366f3deecf14c5d4deaa21d..bfe583a91149755bf16139c025659e5d9a06120e 100644 (file)
@@ -178,17 +178,6 @@ void ospf6_nexthop_delete(struct ospf6_nexthop *nh)
                XFREE(MTYPE_OSPF6_NEXTHOP, nh);
 }
 
-void ospf6_free_nexthops(struct list *nh_list)
-{
-       struct ospf6_nexthop *nh;
-       struct listnode *node, *nnode;
-
-       if (nh_list) {
-               for (ALL_LIST_ELEMENTS(nh_list, node, nnode, nh))
-                       ospf6_nexthop_delete(nh);
-       }
-}
-
 void ospf6_clear_nexthops(struct list *nh_list)
 {
        struct listnode *node;
@@ -340,19 +329,29 @@ int ospf6_route_get_first_nh_index(struct ospf6_route *route)
        return (-1);
 }
 
+static int ospf6_nexthop_cmp(struct ospf6_nexthop *a, struct ospf6_nexthop *b)
+{
+       if ((a)->ifindex == (b)->ifindex &&
+           IN6_ARE_ADDR_EQUAL(&(a)->address, &(b)->address))
+               return 1;
+       return 0;
+}
+
 struct ospf6_route *ospf6_route_create(void)
 {
        struct ospf6_route *route;
        route = XCALLOC(MTYPE_OSPF6_ROUTE, sizeof(struct ospf6_route));
        route->nh_list = list_new();
+       route->nh_list->cmp = (int (*)(void *, void *))ospf6_nexthop_cmp;
+       route->nh_list->del = (void (*) (void *))ospf6_nexthop_delete;
        return route;
 }
 
 void ospf6_route_delete(struct ospf6_route *route)
 {
        if (route) {
-               ospf6_free_nexthops(route->nh_list);
-               list_free(route->nh_list);
+               if (route->nh_list)
+                       list_delete(route->nh_list);
                XFREE(MTYPE_OSPF6_ROUTE, route);
        }
 }
@@ -439,6 +438,7 @@ struct ospf6_route *ospf6_route_lookup(struct prefix *prefix,
                return NULL;
 
        route = (struct ospf6_route *)node->info;
+       route_unlock_node(node); /* to free the lookup lock */
        return route;
 }
 
@@ -583,6 +583,8 @@ struct ospf6_route *ospf6_route_add(struct ospf6_route *route,
                        SET_FLAG(old->flag, OSPF6_ROUTE_ADD);
                        ospf6_route_table_assert(table);
 
+                       /* to free the lookup lock */
+                       route_unlock_node(node);
                        return old;
                }
 
@@ -628,9 +630,10 @@ struct ospf6_route *ospf6_route_add(struct ospf6_route *route,
        if (prev || next) {
                if (IS_OSPF6_DEBUG_ROUTE(MEMORY))
                        zlog_debug(
-                               "%s %p: route add %p: another path: prev %p, next %p",
+                               "%s %p: route add %p: another path: prev %p, next %p node refcount %u",
                                ospf6_route_table_name(table), (void *)table,
-                               (void *)route, (void *)prev, (void *)next);
+                               (void *)route, (void *)prev, (void *)next,
+                               node->lock);
                else if (IS_OSPF6_DEBUG_ROUTE(TABLE))
                        zlog_debug("%s: route add: another path found",
                                   ospf6_route_table_name(table));
@@ -755,9 +758,9 @@ void ospf6_route_remove(struct ospf6_route *route,
                prefix2str(&route->prefix, buf, sizeof(buf));
 
        if (IS_OSPF6_DEBUG_ROUTE(MEMORY))
-               zlog_debug("%s %p: route remove %p: %s",
+               zlog_debug("%s %p: route remove %p: %s rnode refcount %u",
                           ospf6_route_table_name(table), (void *)table,
-                          (void *)route, buf);
+                          (void *)route, buf, route->rnode->lock);
        else if (IS_OSPF6_DEBUG_ROUTE(TABLE))
                zlog_debug("%s: route remove: %s",
                           ospf6_route_table_name(table), buf);
@@ -768,11 +771,9 @@ void ospf6_route_remove(struct ospf6_route *route,
        /* find the route to remove, making sure that the route pointer
           is from the route table. */
        current = node->info;
-       while (current && ospf6_route_is_same(current, route)) {
-               if (current == route)
-                       break;
+       while (current && current != route)
                current = current->next;
-       }
+
        assert(current == route);
 
        /* adjust doubly linked list */
@@ -785,10 +786,14 @@ void ospf6_route_remove(struct ospf6_route *route,
                if (route->next && route->next->rnode == node) {
                        node->info = route->next;
                        SET_FLAG(route->next->flag, OSPF6_ROUTE_BEST);
-               } else
-                       node->info = NULL; /* should unlock route_node here ? */
+               } else {
+                       node->info = NULL;
+                       route->rnode = NULL;
+                       route_unlock_node(node); /* to free the original lock */
+               }
        }
 
+       route_unlock_node(node); /* to free the lookup lock */
        table->count--;
        ospf6_route_table_assert(table);
 
@@ -935,6 +940,7 @@ struct ospf6_route_table *ospf6_route_table_create(int s, int t)
 void ospf6_route_table_delete(struct ospf6_route_table *table)
 {
        ospf6_route_remove_all(table);
+       bf_free(table->idspace);
        route_table_finish(table->table);
        XFREE(MTYPE_OSPF6_ROUTE, table);
 }
@@ -1062,6 +1068,7 @@ void ospf6_route_show_detail(struct vty *vty, struct ospf6_route *route)
        vty_out(vty, "Metric: %d (%d)\n", route->path.cost,
                route->path.u.cost_e2);
 
+       vty_out(vty, "Nexthop count: %u\n", route->nh_list->count);
        /* Nexthops */
        vty_out(vty, "Nexthop:\n");
        for (ALL_LIST_ELEMENTS_RO(route->nh_list, node, nh)) {
index 69d275f8b119d315da30edbbe61d425d638275a0..166074fb705c5c2d239dac829eb5a07cf8f6d2d8 100644 (file)
@@ -256,7 +256,6 @@ extern void ospf6_linkstate_prefix2str(struct prefix *prefix, char *buf,
 
 extern struct ospf6_nexthop *ospf6_nexthop_create(void);
 extern void ospf6_nexthop_delete(struct ospf6_nexthop *nh);
-extern void ospf6_free_nexthops(struct list *nh_list);
 extern void ospf6_clear_nexthops(struct list *nh_list);
 extern int ospf6_num_nexthops(struct list *nh_list);
 extern void ospf6_copy_nexthops(struct list *dst, struct list *src);
index 86f893bc61b925506a26ad0aab187a31b297b92a..6d589aff8f9b960f869442acdfbcc0eb1c4653d1 100644 (file)
@@ -141,6 +141,7 @@ static struct ospf6_vertex *ospf6_vertex_create(struct ospf6_lsa *lsa)
        v->options[2] = *(u_char *)(OSPF6_LSA_HEADER_END(lsa->header) + 3);
 
        v->nh_list = list_new();
+       v->nh_list->del = (void (*) (void *))ospf6_nexthop_delete;
 
        v->parent = NULL;
        v->child_list = list_new();
index c0670012b8eadc9e5c7d1da4acd7490cea97e516..d3d1ffed5ec3f19b631d4ef0a03a2330e305b49e 100644 (file)
@@ -626,7 +626,7 @@ DEFUN (debug_ospf_packet,
        if (inst) // user passed instance ID
        {
                if (!ospf_lookup_instance(strtoul(argv[2]->arg, NULL, 10)))
-                       return CMD_SUCCESS;
+                       return CMD_NOT_MY_INSTANCE;
        }
 
        int type = 0;
@@ -702,7 +702,7 @@ DEFUN (no_debug_ospf_packet,
        if (inst) // user passed instance ID
        {
                if (!ospf_lookup_instance(strtoul(argv[3]->arg, NULL, 10)))
-                       return CMD_SUCCESS;
+                       return CMD_NOT_MY_INSTANCE;
        }
 
        int type = 0;
@@ -773,7 +773,7 @@ DEFUN (debug_ospf_ism,
        if (inst) // user passed instance ID
        {
                if (!ospf_lookup_instance(strtoul(argv[2]->arg, NULL, 10)))
-                       return CMD_SUCCESS;
+                       return CMD_NOT_MY_INSTANCE;
        }
 
        if (vty->node == CONFIG_NODE) {
@@ -824,7 +824,7 @@ DEFUN (no_debug_ospf_ism,
        if (inst) // user passed instance ID
        {
                if (!ospf_lookup_instance(strtoul(argv[3]->arg, NULL, 10)))
-                       return CMD_SUCCESS;
+                       return CMD_NOT_MY_INSTANCE;
        }
 
        if (vty->node == CONFIG_NODE) {
@@ -991,7 +991,7 @@ DEFUN (no_debug_ospf_instance_nsm,
 
        instance = strtoul(argv[idx_number]->arg, NULL, 10);
        if (!ospf_lookup_instance(instance))
-               return CMD_SUCCESS;
+               return CMD_NOT_MY_INSTANCE;
 
        return no_debug_ospf_nsm_common(vty, 5, argc, argv);
 }
@@ -1065,7 +1065,7 @@ DEFUN (debug_ospf_instance_lsa,
 
        instance = strtoul(argv[idx_number]->arg, NULL, 10);
        if (!ospf_lookup_instance(instance))
-               return CMD_SUCCESS;
+               return CMD_NOT_MY_INSTANCE;
 
        return debug_ospf_lsa_common(vty, 4, argc, argv);
 }
@@ -1141,7 +1141,7 @@ DEFUN (no_debug_ospf_instance_lsa,
 
        instance = strtoul(argv[idx_number]->arg, NULL, 10);
        if (!ospf_lookup_instance(instance))
-               return CMD_SUCCESS;
+               return CMD_NOT_MY_INSTANCE;
 
        return no_debug_ospf_lsa_common(vty, 5, argc, argv);
 }
@@ -1203,7 +1203,7 @@ DEFUN (debug_ospf_instance_zebra,
 
        instance = strtoul(argv[idx_number]->arg, NULL, 10);
        if (!ospf_lookup_instance(instance))
-               return CMD_SUCCESS;
+               return CMD_NOT_MY_INSTANCE;
 
        return debug_ospf_zebra_common(vty, 4, argc, argv);
 }
index a2c40923b1d776d442b3f838890d9f0f195c2956..db523bd2a430b064b18f02f09a818c4732a3d48a 100644 (file)
@@ -750,7 +750,7 @@ DEFUN (capability_opaque,
        "Enable specific OSPF feature\n"
        "Opaque LSA\n")
 {
-       VTY_DECLVAR_CONTEXT(ospf, ospf);
+       VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
 
        /* Turn on the "master switch" of opaque-lsa capability. */
        if (!CHECK_FLAG(ospf->config, OSPF_OPAQUE_CAPABLE)) {
@@ -779,7 +779,7 @@ DEFUN (no_capability_opaque,
        "Enable specific OSPF feature\n"
        "Opaque LSA\n")
 {
-       VTY_DECLVAR_CONTEXT(ospf, ospf);
+       VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
 
        /* Turn off the "master switch" of opaque-lsa capability. */
        if (CHECK_FLAG(ospf->config, OSPF_OPAQUE_CAPABLE)) {
index 8bad51e65e9e8fdb85294fbf61652a6f65cff2d9..2470cd2e2b2f1d7bb90cf8acb288c1c0a7c0d501 100644 (file)
        ((ntohs((lsahdr)->length) >= sizeof(struct lsa_header))                \
         && ((ntohs((lsahdr)->length) % sizeof(u_int32_t)) == 0))
 
+/*
+ * Following section defines generic TLV (type, length, value) macros,
+ * used for various LSA opaque usage e.g. Traffic Engineering.
+ */
+struct tlv_header {
+       u_int16_t type;         /* Type of Value */
+       u_int16_t length;       /* Length of Value portion only, in bytes */
+};
+
+#define TLV_HDR_SIZE   (sizeof(struct tlv_header))
+
+#define TLV_BODY_SIZE(tlvh) \
+       (ROUNDUP(ntohs((tlvh)->length), sizeof(u_int32_t)))
+
+#define TLV_SIZE(tlvh) (TLV_HDR_SIZE + TLV_BODY_SIZE(tlvh))
+
+#define TLV_HDR_TOP(lsah) \
+       (struct tlv_header *)((char *)(lsah) + OSPF_LSA_HEADER_SIZE)
+
+#define TLV_HDR_NEXT(tlvh) \
+       (struct tlv_header *)((char *)(tlvh) + TLV_SIZE(tlvh))
+
+#define TLV_HDR_SUBTLV(tlvh) \
+       (struct tlv_header *)((char *)(tlvh) + TLV_HDR_SIZE)
+
+#define TLV_DATA(tlvh) (void *)((char *)(tlvh) + TLV_HDR_SIZE)
+
+#define TLV_TYPE(tlvh) tlvh.header.type
+#define TLV_LEN(tlvh)  tlvh.header.length
+#define TLV_HDR(tlvh)  tlvh.header
+
+/* Following declaration concerns the Opaque LSA management */
+enum lsa_opcode {
+       REORIGINATE_THIS_LSA,
+       REFRESH_THIS_LSA,
+       FLUSH_THIS_LSA
+};
+
 /* Prototypes. */
 
 extern void ospf_opaque_init(void);
@@ -108,7 +146,7 @@ extern int ospf_opaque_new_if(struct interface *ifp);
 extern int ospf_opaque_del_if(struct interface *ifp);
 extern void ospf_opaque_ism_change(struct ospf_interface *oi, int old_status);
 extern void ospf_opaque_nsm_change(struct ospf_neighbor *nbr, int old_status);
-extern void ospf_opaque_config_write_router(struct vty *vty, struct ospf *);
+extern void ospf_opaque_config_write_router(struct vty *vty, struct ospf *ospf);
 extern void ospf_opaque_config_write_if(struct vty *vty, struct interface *ifp);
 extern void ospf_opaque_config_write_debug(struct vty *vty);
 extern void show_opaque_info_detail(struct vty *vty, struct ospf_lsa *lsa);
@@ -116,7 +154,7 @@ extern void ospf_opaque_lsa_dump(struct stream *s, u_int16_t length);
 
 extern void ospf_opaque_lsa_originate_schedule(struct ospf_interface *oi,
                                               int *init_delay);
-extern struct ospf_lsa *ospf_opaque_lsa_install(struct ospf_lsa *,
+extern struct ospf_lsa *ospf_opaque_lsa_install(struct ospf_lsa *lsa,
                                                int rt_recalc);
 extern struct ospf_lsa *ospf_opaque_lsa_refresh(struct ospf_lsa *lsa);
 
index 26d2ed7d135ca7f8e3427f6e56ac3cbee41cd39c..13013bf8cac055187f6ec238e717bf303c3d3e44 100644 (file)
@@ -58,9 +58,9 @@
 #include "ospfd/ospf_ri.h"
 #include "ospfd/ospf_te.h"
 
+/* Store Router Information PCE TLV and SubTLV in network byte order. */
 struct ospf_pce_info {
-
-       /* Store Router Information PCE TLV and SubTLV in network byte order. */
+       bool enabled;
        struct ri_tlv_pce pce_header;
        struct ri_pce_subtlv_address pce_address;
        struct ri_pce_subtlv_path_scope pce_scope;
@@ -71,15 +71,14 @@ struct ospf_pce_info {
 
 /* Following structure are internal use only. */
 struct ospf_router_info {
-       status_t status;
+       bool enabled;
 
        u_int8_t registered;
        u_int8_t scope;
 
 /* Flags to manage this router information. */
-#define RIFLG_LOOKUP_DONE                      0x1
-#define RIFLG_LSA_ENGAGED                      0x2
-#define RIFLG_LSA_FORCED_REFRESH       0x4
+#define RIFLG_LSA_ENGAGED                      0x1
+#define RIFLG_LSA_FORCED_REFRESH       0x2
        u_int32_t flags;
 
        /* area pointer if flooding is Type 10 Null if flooding is AS scope */
@@ -112,7 +111,7 @@ static void ospf_router_info_config_write_router(struct vty *vty);
 static void ospf_router_info_show_info(struct vty *vty, struct ospf_lsa *lsa);
 static int ospf_router_info_lsa_originate(void *arg);
 static struct ospf_lsa *ospf_router_info_lsa_refresh(struct ospf_lsa *lsa);
-static void ospf_router_info_lsa_schedule(opcode_t opcode);
+static void ospf_router_info_lsa_schedule(enum lsa_opcode opcode);
 static void ospf_router_info_register_vty(void);
 static void del_pce_info(void *val);
 
@@ -120,12 +119,13 @@ int ospf_router_info_init(void)
 {
 
        memset(&OspfRI, 0, sizeof(struct ospf_router_info));
-       OspfRI.status = disabled;
+       OspfRI.enabled = false;
        OspfRI.registered = 0;
        OspfRI.scope = OSPF_OPAQUE_AS_LSA;
        OspfRI.flags = 0;
 
        /* Initialize pce domain and neighbor list */
+       OspfRI.pce_info.enabled = false;
        OspfRI.pce_info.pce_domain = list_new();
        OspfRI.pce_info.pce_domain->del = del_pce_info;
        OspfRI.pce_info.pce_neighbor = list_new();
@@ -141,7 +141,7 @@ static int ospf_router_info_register(u_int8_t scope)
        int rc = 0;
 
        if (OspfRI.registered)
-               return 0;
+               return rc;
 
        zlog_info("Register Router Information with scope %s(%d)",
                  scope == OSPF_OPAQUE_AREA_LSA ? "Area" : "AS", scope);
@@ -165,7 +165,7 @@ static int ospf_router_info_register(u_int8_t scope)
 
        OspfRI.registered = 1;
        OspfRI.scope = scope;
-       return 0;
+       return rc;
 }
 
 static int ospf_router_info_unregister()
@@ -193,7 +193,7 @@ void ospf_router_info_term(void)
 
        OspfRI.pce_info.pce_domain = NULL;
        OspfRI.pce_info.pce_neighbor = NULL;
-       OspfRI.status = disabled;
+       OspfRI.enabled = false;
 
        ospf_router_info_unregister();
 
@@ -229,34 +229,36 @@ static int set_pce_header(struct ospf_pce_info *pce)
 
        /* PCE Address */
        if (ntohs(pce->pce_address.header.type) != 0)
-               length += RI_TLV_SIZE(&pce->pce_address.header);
+               length += TLV_SIZE(&pce->pce_address.header);
 
        /* PCE Path Scope */
        if (ntohs(pce->pce_scope.header.type) != 0)
-               length += RI_TLV_SIZE(&pce->pce_scope.header);
+               length += TLV_SIZE(&pce->pce_scope.header);
 
        /* PCE Domain */
        for (ALL_LIST_ELEMENTS_RO(pce->pce_domain, node, domain)) {
                if (ntohs(domain->header.type) != 0)
-                       length += RI_TLV_SIZE(&domain->header);
+                       length += TLV_SIZE(&domain->header);
        }
 
        /* PCE Neighbor */
        for (ALL_LIST_ELEMENTS_RO(pce->pce_neighbor, node, neighbor)) {
                if (ntohs(neighbor->header.type) != 0)
-                       length += RI_TLV_SIZE(&neighbor->header);
+                       length += TLV_SIZE(&neighbor->header);
        }
 
        /* PCE Capabilities */
        if (ntohs(pce->pce_cap_flag.header.type) != 0)
-               length += RI_TLV_SIZE(&pce->pce_cap_flag.header);
+               length += TLV_SIZE(&pce->pce_cap_flag.header);
 
        if (length != 0) {
                pce->pce_header.header.type = htons(RI_TLV_PCE);
                pce->pce_header.header.length = htons(length);
+               pce->enabled = true;
        } else {
                pce->pce_header.header.type = 0;
                pce->pce_header.header.length = 0;
+               pce->enabled = false;
        }
 
        return length;
@@ -279,8 +281,6 @@ static void set_pce_address(struct in_addr ipv4, struct ospf_pce_info *pce)
 static void set_pce_path_scope(u_int32_t scope, struct ospf_pce_info *pce)
 {
 
-       /* Enable PCE Info */
-       pce->pce_header.header.type = htons(RI_TLV_PCE);
        /* Set PCE Scope */
        pce->pce_scope.header.type = htons(RI_PCE_SUBTLV_PATH_SCOPE);
        pce->pce_scope.header.length = htons(RI_TLV_LENGTH);
@@ -295,9 +295,6 @@ static void set_pce_domain(u_int16_t type, u_int32_t domain,
 
        struct ri_pce_subtlv_domain *new;
 
-       /* Enable PCE Info */
-       pce->pce_header.header.type = htons(RI_TLV_PCE);
-
        /* Create new domain info */
        new = XCALLOC(MTYPE_OSPF_PCE_PARAMS,
                      sizeof(struct ri_pce_subtlv_domain));
@@ -348,9 +345,6 @@ static void set_pce_neighbor(u_int16_t type, u_int32_t domain,
 
        struct ri_pce_subtlv_neighbor *new;
 
-       /* Enable PCE Info */
-       pce->pce_header.header.type = htons(RI_TLV_PCE);
-
        /* Create new neighbor info */
        new = XCALLOC(MTYPE_OSPF_PCE_PARAMS,
                      sizeof(struct ri_pce_subtlv_neighbor));
@@ -399,8 +393,6 @@ static void unset_pce_neighbor(u_int16_t type, u_int32_t domain,
 static void set_pce_cap_flag(u_int32_t cap, struct ospf_pce_info *pce)
 {
 
-       /* Enable PCE Info */
-       pce->pce_header.header.type = htons(RI_TLV_PCE);
        /* Set PCE Capabilities flag */
        pce->pce_cap_flag.header.type = htons(RI_PCE_SUBTLV_CAP_FLAG);
        pce->pce_cap_flag.header.length = htons(RI_TLV_LENGTH);
@@ -410,12 +402,12 @@ static void set_pce_cap_flag(u_int32_t cap, struct ospf_pce_info *pce)
 }
 
 
-static void unset_param(struct ri_tlv_header *tlv)
+static void unset_param(struct tlv_header *tlv)
 {
 
        tlv->type = 0;
        /* Fill the Value to 0 */
-       memset((tlv + RI_TLV_HDR_SIZE), 0, RI_TLV_BODY_SIZE(tlv));
+       memset(TLV_DATA(tlv), 0, TLV_BODY_SIZE(tlv));
        tlv->length = 0;
 
        return;
@@ -423,14 +415,13 @@ static void unset_param(struct ri_tlv_header *tlv)
 
 static void initialize_params(struct ospf_router_info *ori)
 {
-       u_int32_t cap;
+       u_int32_t cap = 0;
        struct ospf *top;
 
        /*
         * Initialize default Router Information Capabilities.
         */
-       cap = 0;
-       cap = cap | RI_TE_SUPPORT;
+       cap = RI_TE_SUPPORT;
 
        set_router_info_capabilities(&ori->router_cap, cap);
 
@@ -462,9 +453,6 @@ static void initialize_params(struct ospf_router_info *ori)
              | PCE_CAP_ADDITIVE | PCE_CAP_MULTIPLE_REQ;
        set_pce_cap_flag(cap, &ori->pce_info);
 
-       /* Finally compute PCE header */
-       set_pce_header(&ori->pce_info);
-
        return;
 }
 
@@ -473,16 +461,15 @@ static int is_mandated_params_set(struct ospf_router_info ori)
        int rc = 0;
 
        if (ntohs(ori.router_cap.header.type) == 0)
-               goto out;
+               return rc;
 
        if ((ntohs(ori.pce_info.pce_header.header.type) == RI_TLV_PCE)
            && (ntohs(ori.pce_info.pce_address.header.type) == 0)
            && (ntohs(ori.pce_info.pce_cap_flag.header.type) == 0))
-               goto out;
+               return rc;
 
        rc = 1;
 
-out:
        return rc;
 }
 
@@ -499,7 +486,6 @@ static void ospf_router_info_ism_change(struct ospf_interface *oi,
 static void ospf_router_info_nsm_change(struct ospf_neighbor *nbr,
                                        int old_state)
 {
-
        /* So far, nothing to do here. */
        return;
 }
@@ -508,19 +494,19 @@ static void ospf_router_info_nsm_change(struct ospf_neighbor *nbr,
  * Followings are OSPF protocol processing functions for ROUTER INFORMATION
  *------------------------------------------------------------------------*/
 
-static void build_tlv_header(struct stream *s, struct ri_tlv_header *tlvh)
+static void build_tlv_header(struct stream *s, struct tlv_header *tlvh)
 {
 
-       stream_put(s, tlvh, sizeof(struct ri_tlv_header));
+       stream_put(s, tlvh, sizeof(struct tlv_header));
        return;
 }
 
-static void build_tlv(struct stream *s, struct ri_tlv_header *tlvh)
+static void build_tlv(struct stream *s, struct tlv_header *tlvh)
 {
 
        if (ntohs(tlvh->type) != 0) {
                build_tlv_header(s, tlvh);
-               stream_put(s, tlvh + 1, RI_TLV_BODY_SIZE(tlvh));
+               stream_put(s, TLV_DATA(tlvh), TLV_BODY_SIZE(tlvh));
        }
        return;
 }
@@ -535,9 +521,11 @@ static void ospf_router_info_lsa_body_set(struct stream *s)
        /* Build Router Information TLV */
        build_tlv(s, &OspfRI.router_cap.header);
 
-       /* Add RI PCE TLV if it is set */
        /* Compute PCE Info header first */
-       if ((set_pce_header(&OspfRI.pce_info)) != 0) {
+       set_pce_header (&OspfRI.pce_info);
+
+       /* Add RI PCE TLV if it is set */
+       if (OspfRI.pce_info.enabled) {
 
                /* Build PCE TLV */
                build_tlv_header(s, &OspfRI.pce_info.pce_header.header);
@@ -580,7 +568,7 @@ static struct ospf_lsa *ospf_router_info_lsa_new()
        /* Create a stream for LSA. */
        if ((s = stream_new(OSPF_MAX_LSA_SIZE)) == NULL) {
                zlog_warn("ospf_router_info_lsa_new: stream_new() ?");
-               goto out;
+               return NULL;
        }
        lsah = (struct lsa_header *)STREAM_DATA(s);
 
@@ -614,14 +602,14 @@ static struct ospf_lsa *ospf_router_info_lsa_new()
        if ((new = ospf_lsa_new()) == NULL) {
                zlog_warn("ospf_router_info_lsa_new: ospf_lsa_new() ?");
                stream_free(s);
-               goto out;
+               return NULL;
        }
        if ((new->data = ospf_lsa_data_new(length)) == NULL) {
                zlog_warn("ospf_router_info_lsa_new: ospf_lsa_data_new() ?");
                ospf_lsa_unlock(&new);
                new = NULL;
                stream_free(s);
-               goto out;
+               return new;
        }
 
        new->area = OspfRI.area; /* Area must be null if the Opaque type is AS
@@ -631,7 +619,6 @@ static struct ospf_lsa *ospf_router_info_lsa_new()
        memcpy(new->data, lsah, length);
        stream_free(s);
 
-out:
        return new;
 }
 
@@ -648,7 +635,7 @@ static int ospf_router_info_lsa_originate1(void *arg)
                if (area->area_id.s_addr != OspfRI.area_id.s_addr) {
                        zlog_debug(
                                "RI -> This is not the Router Information Area. Stop processing");
-                       goto out;
+                       return rc;
                }
                OspfRI.area = area;
        }
@@ -657,7 +644,7 @@ static int ospf_router_info_lsa_originate1(void *arg)
        if ((new = ospf_router_info_lsa_new()) == NULL) {
                zlog_warn(
                        "ospf_router_info_lsa_originate1: ospf_router_info_lsa_new() ?");
-               goto out;
+               return rc;
        }
 
        /* Get ospf info */
@@ -668,7 +655,7 @@ static int ospf_router_info_lsa_originate1(void *arg)
                zlog_warn(
                        "ospf_router_info_lsa_originate1: ospf_lsa_install() ?");
                ospf_lsa_unlock(&new);
-               goto out;
+               return rc;
        }
 
        /* Now this Router Info parameter entry has associated LSA. */
@@ -691,7 +678,6 @@ static int ospf_router_info_lsa_originate1(void *arg)
        }
 
        rc = 0;
-out:
        return rc;
 }
 
@@ -700,17 +686,17 @@ static int ospf_router_info_lsa_originate(void *arg)
 
        int rc = -1;
 
-       if (OspfRI.status == disabled) {
+       if (!OspfRI.enabled) {
                zlog_info(
                        "ospf_router_info_lsa_originate: ROUTER INFORMATION is disabled now.");
                rc = 0; /* This is not an error case. */
-               goto out;
+               return rc;
        }
 
        /* Check if Router Information LSA is already engaged */
-       if (OspfRI.flags & RIFLG_LSA_ENGAGED) {
-               if (OspfRI.flags & RIFLG_LSA_FORCED_REFRESH) {
-                       OspfRI.flags &= ~RIFLG_LSA_FORCED_REFRESH;
+       if (CHECK_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED)) {
+               if (CHECK_FLAG(OspfRI.flags, RIFLG_LSA_FORCED_REFRESH)) {
+                       UNSET_FLAG(OspfRI.flags, RIFLG_LSA_FORCED_REFRESH);
                        ospf_router_info_lsa_schedule(REFRESH_THIS_LSA);
                }
        } else {
@@ -720,11 +706,10 @@ static int ospf_router_info_lsa_originate(void *arg)
 
                /* Ok, let's try to originate an LSA */
                if (ospf_router_info_lsa_originate1(arg) != 0)
-                       goto out;
+                       return rc;
        }
 
        rc = 0;
-out:
        return rc;
 }
 
@@ -733,7 +718,7 @@ static struct ospf_lsa *ospf_router_info_lsa_refresh(struct ospf_lsa *lsa)
        struct ospf_lsa *new = NULL;
        struct ospf *top;
 
-       if (OspfRI.status == disabled) {
+       if (!OspfRI.enabled) {
                /*
                 * This LSA must have flushed before due to ROUTER INFORMATION
                 * status change.
@@ -749,21 +734,21 @@ static struct ospf_lsa *ospf_router_info_lsa_refresh(struct ospf_lsa *lsa)
        if (GET_OPAQUE_ID(ntohl(lsa->data->id.s_addr)) != 0) {
                zlog_warn(
                        "ospf_router_info_lsa_refresh: Unsupported Router Information ID");
-               goto out;
+               return NULL;
        }
 
        /* If the lsa's age reached to MaxAge, start flushing procedure. */
        if (IS_LSA_MAXAGE(lsa)) {
-               OspfRI.flags &= ~RIFLG_LSA_ENGAGED;
+               UNSET_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED);
                ospf_opaque_lsa_flush_schedule(lsa);
-               goto out;
+               return NULL;
        }
 
        /* Create new Opaque-LSA/ROUTER INFORMATION instance. */
        if ((new = ospf_router_info_lsa_new()) == NULL) {
                zlog_warn(
                        "ospf_router_info_lsa_refresh: ospf_router_info_lsa_new() ?");
-               goto out;
+               return NULL;
        }
        new->data->ls_seqnum = lsa_seqnum_increment(lsa);
 
@@ -773,7 +758,7 @@ static struct ospf_lsa *ospf_router_info_lsa_refresh(struct ospf_lsa *lsa)
        if (ospf_lsa_install(top, NULL /*oi */, new) == NULL) {
                zlog_warn("ospf_router_info_lsa_refresh: ospf_lsa_install() ?");
                ospf_lsa_unlock(&new);
-               goto out;
+               return new;
        }
 
        /* Flood updated LSA through AS or AREA depending of OspfRI.scope. */
@@ -790,11 +775,10 @@ static struct ospf_lsa *ospf_router_info_lsa_refresh(struct ospf_lsa *lsa)
                ospf_lsa_header_dump(new->data);
        }
 
-out:
        return new;
 }
 
-static void ospf_router_info_lsa_schedule(opcode_t opcode)
+static void ospf_router_info_lsa_schedule(enum lsa_opcode opcode)
 {
        struct ospf_lsa lsa;
        struct lsa_header lsah;
@@ -809,6 +793,13 @@ static void ospf_router_info_lsa_schedule(opcode_t opcode)
                   opcode == REFRESH_THIS_LSA ? "Refresh" : "",
                   opcode == FLUSH_THIS_LSA ? "Flush" : "");
 
+       /* Check LSA flags state coherence */
+       if (!CHECK_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED) && (opcode != REORIGINATE_THIS_LSA))
+               return;
+
+       if (CHECK_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED) && (opcode == REORIGINATE_THIS_LSA))
+               opcode = REFRESH_THIS_LSA;
+
        top = ospf_lookup();
        if ((OspfRI.scope == OSPF_OPAQUE_AREA_LSA) && (OspfRI.area == NULL)) {
                zlog_warn(
@@ -838,7 +829,7 @@ static void ospf_router_info_lsa_schedule(opcode_t opcode)
                ospf_opaque_lsa_refresh_schedule(&lsa);
                break;
        case FLUSH_THIS_LSA:
-               OspfRI.flags &= ~RIFLG_LSA_ENGAGED;
+               UNSET_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED);
                ospf_opaque_lsa_flush_schedule(&lsa);
                break;
        default:
@@ -855,7 +846,7 @@ static void ospf_router_info_lsa_schedule(opcode_t opcode)
  *------------------------------------------------------------------------*/
 
 static u_int16_t show_vty_router_cap(struct vty *vty,
-                                    struct ri_tlv_header *tlvh)
+                                    struct tlv_header *tlvh)
 {
        struct ri_tlv_router_cap *top = (struct ri_tlv_router_cap *)tlvh;
 
@@ -865,11 +856,11 @@ static u_int16_t show_vty_router_cap(struct vty *vty,
        else
                zlog_debug("    Router Capabilities: 0x%x", ntohl(top->value));
 
-       return RI_TLV_SIZE(tlvh);
+       return TLV_SIZE(tlvh);
 }
 
 static u_int16_t show_vty_pce_subtlv_address(struct vty *vty,
-                                            struct ri_tlv_header *tlvh)
+                                            struct tlv_header *tlvh)
 {
        struct ri_pce_subtlv_address *top =
                (struct ri_pce_subtlv_address *)tlvh;
@@ -891,11 +882,11 @@ static u_int16_t show_vty_pce_subtlv_address(struct vty *vty,
                                   ntohl(top->address.value.s_addr));
        }
 
-       return RI_TLV_SIZE(tlvh);
+       return TLV_SIZE(tlvh);
 }
 
 static u_int16_t show_vty_pce_subtlv_path_scope(struct vty *vty,
-                                               struct ri_tlv_header *tlvh)
+                                               struct tlv_header *tlvh)
 {
        struct ri_pce_subtlv_path_scope *top =
                (struct ri_pce_subtlv_path_scope *)tlvh;
@@ -905,11 +896,11 @@ static u_int16_t show_vty_pce_subtlv_path_scope(struct vty *vty,
        else
                zlog_debug("    PCE Path Scope: 0x%x", ntohl(top->value));
 
-       return RI_TLV_SIZE(tlvh);
+       return TLV_SIZE(tlvh);
 }
 
 static u_int16_t show_vty_pce_subtlv_domain(struct vty *vty,
-                                           struct ri_tlv_header *tlvh)
+                                           struct tlv_header *tlvh)
 {
        struct ri_pce_subtlv_domain *top = (struct ri_pce_subtlv_domain *)tlvh;
        struct in_addr tmp;
@@ -927,11 +918,11 @@ static u_int16_t show_vty_pce_subtlv_domain(struct vty *vty,
                else
                        zlog_debug("    PCE domain AS: %d", ntohl(top->value));
        }
-       return RI_TLV_SIZE(tlvh);
+       return TLV_SIZE(tlvh);
 }
 
 static u_int16_t show_vty_pce_subtlv_neighbor(struct vty *vty,
-                                             struct ri_tlv_header *tlvh)
+                                             struct tlv_header *tlvh)
 {
 
        struct ri_pce_subtlv_neighbor *top =
@@ -953,11 +944,11 @@ static u_int16_t show_vty_pce_subtlv_neighbor(struct vty *vty,
                        zlog_debug("    PCE neighbor AS: %d",
                                   ntohl(top->value));
        }
-       return RI_TLV_SIZE(tlvh);
+       return TLV_SIZE(tlvh);
 }
 
 static u_int16_t show_vty_pce_subtlv_cap_flag(struct vty *vty,
-                                             struct ri_tlv_header *tlvh)
+                                             struct tlv_header *tlvh)
 {
        struct ri_pce_subtlv_cap_flag *top =
                (struct ri_pce_subtlv_cap_flag *)tlvh;
@@ -969,11 +960,11 @@ static u_int16_t show_vty_pce_subtlv_cap_flag(struct vty *vty,
                zlog_debug("    PCE Capabilities Flag: 0x%x",
                           ntohl(top->value));
 
-       return RI_TLV_SIZE(tlvh);
+       return TLV_SIZE(tlvh);
 }
 
 static u_int16_t show_vty_unknown_tlv(struct vty *vty,
-                                     struct ri_tlv_header *tlvh)
+                                     struct tlv_header *tlvh)
 {
        if (vty != NULL)
                vty_out(vty, "  Unknown TLV: [type(0x%x), length(0x%x)]\n",
@@ -982,16 +973,16 @@ static u_int16_t show_vty_unknown_tlv(struct vty *vty,
                zlog_debug("    Unknown TLV: [type(0x%x), length(0x%x)]",
                           ntohs(tlvh->type), ntohs(tlvh->length));
 
-       return RI_TLV_SIZE(tlvh);
+       return TLV_SIZE(tlvh);
 }
 
-static u_int16_t show_vty_pce_info(struct vty *vty, struct ri_tlv_header *ri,
+static u_int16_t show_vty_pce_info(struct vty *vty, struct tlv_header *ri,
                                   uint32_t total)
 {
-       struct ri_tlv_header *tlvh;
+       struct tlv_header *tlvh;
        u_int16_t sum = 0;
 
-       for (tlvh = ri; sum < total; tlvh = RI_TLV_HDR_NEXT(tlvh)) {
+       for (tlvh = ri; sum < total; tlvh = TLV_HDR_NEXT(tlvh)) {
                switch (ntohs(tlvh->type)) {
                case RI_PCE_SUBTLV_ADDRESS:
                        sum += show_vty_pce_subtlv_address(vty, tlvh);
@@ -1019,21 +1010,21 @@ static u_int16_t show_vty_pce_info(struct vty *vty, struct ri_tlv_header *ri,
 static void ospf_router_info_show_info(struct vty *vty, struct ospf_lsa *lsa)
 {
        struct lsa_header *lsah = (struct lsa_header *)lsa->data;
-       struct ri_tlv_header *tlvh;
+       struct tlv_header *tlvh;
        u_int16_t length = 0, sum = 0;
 
        /* Initialize TLV browsing */
        length = ntohs(lsah->length) - OSPF_LSA_HEADER_SIZE;
 
-       for (tlvh = RI_TLV_HDR_TOP(lsah); sum < length;
-            tlvh = RI_TLV_HDR_NEXT(tlvh)) {
+       for (tlvh = TLV_HDR_TOP(lsah); sum < length;
+            tlvh = TLV_HDR_NEXT(tlvh)) {
                switch (ntohs(tlvh->type)) {
                case RI_TLV_CAPABILITIES:
                        sum += show_vty_router_cap(vty, tlvh);
                        break;
                case RI_TLV_PCE:
                        tlvh++;
-                       sum += RI_TLV_HDR_SIZE;
+                       sum += TLV_HDR_SIZE;
                        sum += show_vty_pce_info(vty, tlvh, length - sum);
                        break;
                default:
@@ -1053,50 +1044,53 @@ static void ospf_router_info_config_write_router(struct vty *vty)
        struct ri_pce_subtlv_neighbor *neighbor;
        struct in_addr tmp;
 
-       if (OspfRI.status == enabled) {
+       if (OspfRI.enabled) {
                if (OspfRI.scope == OSPF_OPAQUE_AS_LSA)
                        vty_out(vty, " router-info as\n");
                else
                        vty_out(vty, " router-info area %s\n",
                                inet_ntoa(OspfRI.area_id));
 
-               if (pce->pce_address.header.type != 0)
-                       vty_out(vty, "  pce address %s\n",
-                               inet_ntoa(pce->pce_address.address.value));
-
-               if (pce->pce_cap_flag.header.type != 0)
-                       vty_out(vty, "  pce flag 0x%x\n",
-                               ntohl(pce->pce_cap_flag.value));
-
-               for (ALL_LIST_ELEMENTS_RO(pce->pce_domain, node, domain)) {
-                       if (domain->header.type != 0) {
-                               if (domain->type == PCE_DOMAIN_TYPE_AREA) {
-                                       tmp.s_addr = domain->value;
-                                       vty_out(vty, "  pce domain area %s\n",
-                                               inet_ntoa(tmp));
-                               } else {
-                                       vty_out(vty, "  pce domain as %d\n",
-                                               ntohl(domain->value));
+               if (OspfRI.pce_info.enabled) {
+
+                       if (pce->pce_address.header.type != 0)
+                               vty_out(vty, "  pce address %s\n",
+                                       inet_ntoa(pce->pce_address.address.value));
+
+                       if (pce->pce_cap_flag.header.type != 0)
+                               vty_out(vty, "  pce flag 0x%x\n",
+                                       ntohl(pce->pce_cap_flag.value));
+
+                       for (ALL_LIST_ELEMENTS_RO(pce->pce_domain, node, domain)) {
+                               if (domain->header.type != 0) {
+                                       if (domain->type == PCE_DOMAIN_TYPE_AREA) {
+                                               tmp.s_addr = domain->value;
+                                               vty_out(vty, "  pce domain area %s\n",
+                                                       inet_ntoa(tmp));
+                                       } else {
+                                               vty_out(vty, "  pce domain as %d\n",
+                                                       ntohl(domain->value));
+                                       }
                                }
                        }
-               }
 
-               for (ALL_LIST_ELEMENTS_RO(pce->pce_neighbor, node, neighbor)) {
-                       if (neighbor->header.type != 0) {
-                               if (neighbor->type == PCE_DOMAIN_TYPE_AREA) {
-                                       tmp.s_addr = neighbor->value;
-                                       vty_out(vty, "  pce neighbor area %s\n",
-                                               inet_ntoa(tmp));
-                               } else {
-                                       vty_out(vty, "  pce neighbor as %d\n",
-                                               ntohl(neighbor->value));
+                       for (ALL_LIST_ELEMENTS_RO(pce->pce_neighbor, node, neighbor)) {
+                               if (neighbor->header.type != 0) {
+                                       if (neighbor->type == PCE_DOMAIN_TYPE_AREA) {
+                                               tmp.s_addr = neighbor->value;
+                                               vty_out(vty, "  pce neighbor area %s\n",
+                                                       inet_ntoa(tmp));
+                                       } else {
+                                               vty_out(vty, "  pce neighbor as %d\n",
+                                                       ntohl(neighbor->value));
+                                       }
                                }
                        }
-               }
 
-               if (pce->pce_scope.header.type != 0)
-                       vty_out(vty, "  pce scope 0x%x\n",
-                               ntohl(OspfRI.pce_info.pce_scope.value));
+                       if (pce->pce_scope.header.type != 0)
+                               vty_out(vty, "  pce scope 0x%x\n",
+                                       ntohl(OspfRI.pce_info.pce_scope.value));
+               }
        }
        return;
 }
@@ -1118,7 +1112,7 @@ DEFUN (router_info,
 
        u_int8_t scope;
 
-       if (OspfRI.status == enabled)
+       if (OspfRI.enabled)
                return CMD_SUCCESS;
 
        /* Check and get Area value if present */
@@ -1137,11 +1131,11 @@ DEFUN (router_info,
        /* First start to register Router Information callbacks */
        if ((ospf_router_info_register(scope)) != 0) {
                zlog_warn(
-                       "Enable to register Router Information callbacks. Abort!");
+                       "Unable to register Router Information callbacks. Abort!");
                return CMD_WARNING_CONFIG_FAILED;
        }
 
-       OspfRI.status = enabled;
+       OspfRI.enabled = true;
 
        if (IS_DEBUG_OSPF_EVENT)
                zlog_debug("RI-> Router Information (%s flooding): OFF -> ON",
@@ -1160,7 +1154,10 @@ DEFUN (router_info,
        initialize_params(&OspfRI);
 
        /* Refresh RI LSA if already engaged */
-       if (OspfRI.flags & RIFLG_LSA_ENGAGED) {
+       if (CHECK_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED)) {
+               zlog_debug ("RI-> Refresh LSA following configuration");
+               ospf_router_info_lsa_schedule (REFRESH_THIS_LSA);
+       } else {
                zlog_debug("RI-> Initial origination following configuration");
                ospf_router_info_lsa_schedule(REORIGINATE_THIS_LSA);
        }
@@ -1175,26 +1172,26 @@ DEFUN (no_router_info,
        "Disable the Router Information functionality\n")
 {
 
-       if (OspfRI.status == disabled)
+       if (!OspfRI.enabled)
                return CMD_SUCCESS;
 
        if (IS_DEBUG_OSPF_EVENT)
                zlog_debug("RI-> Router Information: ON -> OFF");
 
-       if (OspfRI.flags & RIFLG_LSA_ENGAGED)
+       if (CHECK_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED))
                ospf_router_info_lsa_schedule(FLUSH_THIS_LSA);
 
        /* Unregister the callbacks */
        ospf_router_info_unregister();
 
-       OspfRI.status = disabled;
+       OspfRI.enabled = false;
 
        return CMD_SUCCESS;
 }
 
 static int ospf_ri_enabled(struct vty *vty)
 {
-       if (OspfRI.status == enabled)
+       if (OspfRI.enabled)
                return 1;
 
        if (vty)
@@ -1229,7 +1226,7 @@ DEFUN (pce_address,
                set_pce_address(value, pi);
 
                /* Refresh RI LSA if already engaged */
-               if (OspfRI.flags & RIFLG_LSA_ENGAGED)
+               if (CHECK_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED))
                        ospf_router_info_lsa_schedule(REFRESH_THIS_LSA);
        }
 
@@ -1248,7 +1245,7 @@ DEFUN (no_pce_address,
        unset_param(&OspfRI.pce_info.pce_address.header);
 
        /* Refresh RI LSA if already engaged */
-       if ((OspfRI.status == enabled) && (OspfRI.flags & RIFLG_LSA_ENGAGED))
+       if (CHECK_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED))
                ospf_router_info_lsa_schedule(REFRESH_THIS_LSA);
 
        return CMD_SUCCESS;
@@ -1279,7 +1276,7 @@ DEFUN (pce_path_scope,
                set_pce_path_scope(scope, pi);
 
                /* Refresh RI LSA if already engaged */
-               if (OspfRI.flags & RIFLG_LSA_ENGAGED)
+               if (CHECK_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED))
                        ospf_router_info_lsa_schedule(REFRESH_THIS_LSA);
        }
 
@@ -1298,7 +1295,7 @@ DEFUN (no_pce_path_scope,
        unset_param(&OspfRI.pce_info.pce_address.header);
 
        /* Refresh RI LSA if already engaged */
-       if ((OspfRI.status == enabled) && (OspfRI.flags & RIFLG_LSA_ENGAGED))
+       if (CHECK_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED))
                ospf_router_info_lsa_schedule(REFRESH_THIS_LSA);
 
        return CMD_SUCCESS;
@@ -1337,7 +1334,7 @@ DEFUN (pce_domain,
        set_pce_domain(PCE_DOMAIN_TYPE_AS, as, pce);
 
        /* Refresh RI LSA if already engaged */
-       if (OspfRI.flags & RIFLG_LSA_ENGAGED)
+       if (CHECK_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED))
                ospf_router_info_lsa_schedule(REFRESH_THIS_LSA);
 
        return CMD_SUCCESS;
@@ -1367,7 +1364,7 @@ DEFUN (no_pce_domain,
        unset_pce_domain(PCE_DOMAIN_TYPE_AS, as, pce);
 
        /* Refresh RI LSA if already engaged */
-       if ((OspfRI.status == enabled) && (OspfRI.flags & RIFLG_LSA_ENGAGED))
+       if (CHECK_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED))
                ospf_router_info_lsa_schedule(REFRESH_THIS_LSA);
 
        return CMD_SUCCESS;
@@ -1407,7 +1404,7 @@ DEFUN (pce_neigbhor,
        set_pce_neighbor(PCE_DOMAIN_TYPE_AS, as, pce);
 
        /* Refresh RI LSA if already engaged */
-       if (OspfRI.flags & RIFLG_LSA_ENGAGED)
+       if (CHECK_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED))
                ospf_router_info_lsa_schedule(REFRESH_THIS_LSA);
 
        return CMD_SUCCESS;
@@ -1437,7 +1434,7 @@ DEFUN (no_pce_neighbor,
        unset_pce_neighbor(PCE_DOMAIN_TYPE_AS, as, pce);
 
        /* Refresh RI LSA if already engaged */
-       if ((OspfRI.status == enabled) && (OspfRI.flags & RIFLG_LSA_ENGAGED))
+       if (CHECK_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED))
                ospf_router_info_lsa_schedule(REFRESH_THIS_LSA);
 
        return CMD_SUCCESS;
@@ -1469,7 +1466,7 @@ DEFUN (pce_cap_flag,
                set_pce_cap_flag(cap, pce);
 
                /* Refresh RI LSA if already engaged */
-               if (OspfRI.flags & RIFLG_LSA_ENGAGED)
+               if (CHECK_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED))
                        ospf_router_info_lsa_schedule(REFRESH_THIS_LSA);
        }
 
@@ -1487,7 +1484,7 @@ DEFUN (no_pce_cap_flag,
        unset_param(&OspfRI.pce_info.pce_cap_flag.header);
 
        /* Refresh RI LSA if already engaged */
-       if ((OspfRI.status == enabled) && (OspfRI.flags & RIFLG_LSA_ENGAGED))
+       if (CHECK_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED))
                ospf_router_info_lsa_schedule(REFRESH_THIS_LSA);
 
        return CMD_SUCCESS;
@@ -1502,7 +1499,7 @@ DEFUN (show_ip_ospf_router_info,
        "Router Information\n")
 {
 
-       if (OspfRI.status == enabled) {
+       if (OspfRI.enabled) {
                vty_out(vty, "--- Router Information parameters ---\n");
                show_vty_router_cap(vty, &OspfRI.router_cap.header);
        } else {
@@ -1528,7 +1525,7 @@ DEFUN (show_ip_opsf_router_info_pce,
        struct ri_pce_subtlv_domain *domain;
        struct ri_pce_subtlv_neighbor *neighbor;
 
-       if (OspfRI.status == enabled) {
+       if (OspfRI.enabled) {
                vty_out(vty, "--- PCE parameters ---\n");
 
                if (pce->pce_address.header.type != 0)
index 50221b25c59c17b7a2e14db612fe7ed1119f6585..2d90730d93ecfde5411de5c5283ddca990932a95 100644 (file)
  * +--------+--------+--------+--------+ ---
  */
 
-/*
- * Following section defines TLV (tag, length, value) structures,
- * used for Router Information.
- */
-struct ri_tlv_header {
-       u_int16_t type;   /* RI_TLV_XXX (see below) */
-       u_int16_t length; /* Value portion only, in byte */
-};
-
-#define RI_TLV_HDR_SIZE (sizeof (struct ri_tlv_header))
-#define RI_TLV_BODY_SIZE(tlvh) (ROUNDUP (ntohs ((tlvh)->length), sizeof (u_int32_t)))
-#define RI_TLV_SIZE(tlvh) (RI_TLV_HDR_SIZE + RI_TLV_BODY_SIZE(tlvh))
-#define RI_TLV_HDR_TOP(lsah) (struct ri_tlv_header *)((char *)(lsah) + OSPF_LSA_HEADER_SIZE)
-#define RI_TLV_HDR_NEXT(tlvh) (struct ri_tlv_header *)((char *)(tlvh) + RI_TLV_SIZE(tlvh))
-
 /*
  * Following section defines TLV body parts.
  */
@@ -91,7 +76,7 @@ struct ri_tlv_header {
 #define RI_TLV_CAPABILITIES            1
 
 struct ri_tlv_router_cap {
-       struct ri_tlv_header header; /* Value length is 4 bytes. */
+       struct tlv_header header; /* Value length is 4 bytes. */
        u_int32_t value;
 };
 
@@ -109,23 +94,19 @@ struct ri_tlv_router_cap {
 #define RI_TLV_PCE                     6
 
 struct ri_tlv_pce {
-       struct ri_tlv_header header;
+       struct tlv_header header;
        /* A set of PCE-sub-TLVs will follow. */
 };
 
 /* PCE Address Sub-TLV */ /* Mandatory */
 #define        RI_PCE_SUBTLV_ADDRESS           1
 struct ri_pce_subtlv_address {
-       struct ri_tlv_header
-               header; /* Type = 1; Length is 8 (IPv4) or 20 (IPv6) bytes. */
-                       /* $FRR indent$ */
-                       /* clang-format off */
+       /* Type = 1; Length is 8 (IPv4) or 20 (IPv6) bytes. */
+       struct tlv_header header;
 #define        PCE_ADDRESS_LENGTH_IPV4         8
 #define        PCE_ADDRESS_LENGTH_IPV6         20
        struct {
                u_int16_t type; /* Address type: 1 = IPv4, 2 = IPv6 */
-                               /* $FRR indent$ */
-                               /* clang-format off */
 #define        PCE_ADDRESS_TYPE_IPV4           1
 #define        PCE_ADDRESS_TYPE_IPV6           2
                u_int16_t reserved;
@@ -136,9 +117,12 @@ struct ri_pce_subtlv_address {
 /* PCE Path-Scope Sub-TLV */ /* Mandatory */
 #define        RI_PCE_SUBTLV_PATH_SCOPE        2
 struct ri_pce_subtlv_path_scope {
-       struct ri_tlv_header header; /* Type = 2; Length = 4 bytes. */
-       u_int32_t value; /* L, R, Rd, S, Sd, Y, PrefL, PrefR, PrefS and PrefY
-                           bits see RFC5088 page 9 */
+       struct tlv_header header; /* Type = 2; Length = 4 bytes. */
+       /*
+        * L, R, Rd, S, Sd, Y, PrefL, PrefR, PrefS and PrefY bits:
+        * see RFC5088 page 9
+        */
+       u_int32_t value;
 };
 
 /* PCE Domain Sub-TLV */ /* Optional */
@@ -148,7 +132,7 @@ struct ri_pce_subtlv_path_scope {
 #define        PCE_DOMAIN_TYPE_AS                      2
 
 struct ri_pce_subtlv_domain {
-       struct ri_tlv_header header; /* Type = 3; Length = 8 bytes. */
+       struct tlv_header header; /* Type = 3; Length = 8 bytes. */
        u_int16_t type; /* Domain type: 1 = OSPF Area ID, 2 = AS Number */
        u_int16_t reserved;
        u_int32_t value;
@@ -157,7 +141,7 @@ struct ri_pce_subtlv_domain {
 /* PCE Neighbor Sub-TLV */ /* Mandatory if R or S bit is set */
 #define RI_PCE_SUBTLV_NEIGHBOR         4
 struct ri_pce_subtlv_neighbor {
-       struct ri_tlv_header header; /* Type = 4; Length = 8 bytes. */
+       struct tlv_header header; /* Type = 4; Length = 8 bytes. */
        u_int16_t type; /* Domain type: 1 = OSPF Area ID, 2 = AS Number */
        u_int16_t reserved;
        u_int32_t value;
@@ -177,7 +161,7 @@ struct ri_pce_subtlv_neighbor {
 #define PCE_CAP_MULTIPLE_REQ   0x0100
 
 struct ri_pce_subtlv_cap_flag {
-       struct ri_tlv_header header; /* Type = 5; Length = n x 4 bytes. */
+       struct tlv_header header; /* Type = 5; Length = n x 4 bytes. */
        u_int32_t value;
 };
 
index 4ca6578eaec2f21c7395c2e15190548440259abc..1c1c76c1afdda52e4d35bf1c6259ba1da3ece51f 100644 (file)
@@ -68,9 +68,7 @@
  */
 struct ospf_mpls_te OspfMplsTE;
 
-const char *mode2text[] = {"Disable", "AS", "Area", "Emulate"};
-
-enum oifstate { OI_ANY, OI_DOWN, OI_UP };
+const char *mode2text[] = {"Off", "AS", "Area"};
 
 /*------------------------------------------------------------------------*
  * Followings are initialize/terminate functions for MPLS-TE handling.
@@ -106,29 +104,28 @@ int ospf_mpls_te_init(void)
        if (rc != 0) {
                zlog_warn(
                        "ospf_mpls_te_init: Failed to register Traffic Engineering functions");
-               goto out;
+               return rc;
        }
 
        memset(&OspfMplsTE, 0, sizeof(struct ospf_mpls_te));
-       OspfMplsTE.status = disabled;
-       OspfMplsTE.inter_as = Disable;
+       OspfMplsTE.enabled = false;
+       OspfMplsTE.inter_as = Off;
        OspfMplsTE.iflist = list_new();
        OspfMplsTE.iflist->del = del_mpls_te_link;
 
        ospf_mpls_te_register_vty();
 
-out:
        return rc;
 }
 
 /* Additional register for RFC5392 support */
 static int ospf_mpls_te_register(enum inter_as_mode mode)
 {
-       int rc;
+       int rc = 0;
        u_int8_t scope;
 
-       if (OspfMplsTE.inter_as != Disable)
-               return 0;
+       if (OspfMplsTE.inter_as != Off)
+               return rc;
 
        if (mode == AS)
                scope = OSPF_OPAQUE_AS_LSA;
@@ -147,14 +144,14 @@ static int ospf_mpls_te_register(enum inter_as_mode mode)
                return rc;
        }
 
-       return 0;
+       return rc;
 }
 
 static int ospf_mpls_te_unregister()
 {
        u_int8_t scope;
 
-       if (OspfMplsTE.inter_as == Disable)
+       if (OspfMplsTE.inter_as == Off)
                return 0;
 
        if (OspfMplsTE.inter_as == AS)
@@ -174,10 +171,10 @@ void ospf_mpls_te_term(void)
 
        ospf_delete_opaque_functab(OSPF_OPAQUE_AREA_LSA,
                                   OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA);
-       OspfMplsTE.status = disabled;
+       OspfMplsTE.enabled = false;
 
        ospf_mpls_te_unregister();
-       OspfMplsTE.inter_as = Disable;
+       OspfMplsTE.inter_as = Off;
 
        return;
 }
@@ -192,7 +189,7 @@ static void del_mpls_te_link(void *val)
        return;
 }
 
-u_int32_t get_mpls_te_instance_value(void)
+static u_int32_t get_mpls_te_instance_value(void)
 {
        static u_int32_t seqno = 0;
 
@@ -204,41 +201,6 @@ u_int32_t get_mpls_te_instance_value(void)
        return seqno;
 }
 
-static struct ospf_interface *lookup_oi_by_ifp(struct interface *ifp,
-                                              struct ospf_area *area,
-                                              enum oifstate oifstate)
-{
-       struct ospf_interface *oi = NULL;
-       struct route_node *rn;
-
-       for (rn = route_top(IF_OIFS(ifp)); rn; rn = route_next(rn)) {
-               if ((oi = rn->info) == NULL)
-                       continue;
-
-               switch (oifstate) {
-               case OI_ANY:
-                       break;
-               case OI_DOWN:
-                       if (ospf_if_is_enable(oi))
-                               continue;
-                       break;
-               case OI_UP:
-                       if (!ospf_if_is_enable(oi))
-                               continue;
-                       break;
-               default:
-                       zlog_warn("lookup_oi_by_ifp: Unknown oifstate: %x",
-                                 oifstate);
-                       goto out;
-               }
-
-               if (area == NULL || oi->area == area)
-                       return oi;
-       }
-out:
-       return NULL;
-}
-
 static struct mpls_te_link *lookup_linkparams_by_ifp(struct interface *ifp)
 {
        struct listnode *node, *nnode;
@@ -267,8 +229,8 @@ static struct mpls_te_link *lookup_linkparams_by_instance(struct ospf_lsa *lsa)
 }
 
 static void ospf_mpls_te_foreach_area(void (*func)(struct mpls_te_link *lp,
-                                                  opcode_t sched_opcode),
-                                     opcode_t sched_opcode)
+                                       enum lsa_opcode sched_opcode),
+                                     enum lsa_opcode sched_opcode)
 {
        struct listnode *node, *nnode;
        struct listnode *node2;
@@ -281,8 +243,8 @@ static void ospf_mpls_te_foreach_area(void (*func)(struct mpls_te_link *lp,
                        continue;
                if ((area = lp->area) == NULL)
                        continue;
-               if
-                       CHECK_FLAG(lp->flags, LPFLG_LOOKUP_DONE) continue;
+               if (CHECK_FLAG(lp->flags, LPFLG_LOOKUP_DONE))
+                       continue;
 
                if (func != NULL)
                        (*func)(lp, sched_opcode);
@@ -793,14 +755,25 @@ static void update_linkparams(struct mpls_te_link *lp)
 static void initialize_linkparams(struct mpls_te_link *lp)
 {
        struct interface *ifp = lp->ifp;
-       struct ospf_interface *oi;
+       struct ospf_interface *oi = NULL;
+       struct route_node *rn;
 
        if (IS_DEBUG_OSPF_TE)
                zlog_debug(
                        "MPLS-TE(initialize_linkparams) Initialize Link Parameters for interface %s",
                        ifp->name);
 
-       if ((oi = lookup_oi_by_ifp(ifp, NULL, OI_ANY)) == NULL) {
+       /* Search OSPF Interface parameters for this interface */
+       for (rn = route_top (IF_OIFS (ifp)); rn; rn = route_next (rn)) {
+
+               if ((oi = rn->info) == NULL)
+                       continue;
+
+               if (oi->ifp == ifp)
+                       break;
+       }
+
+       if ((oi == NULL) || (oi->ifp != ifp)) {
                if (IS_DEBUG_OSPF_TE)
                        zlog_warn(
                                "MPLS-TE(initialize_linkparams) Could not find corresponding OSPF Interface for %s",
@@ -818,7 +791,7 @@ static void initialize_linkparams(struct mpls_te_link *lp)
        set_linkparams_lclif_ipaddr(lp, oi->address->u.prefix4);
 
        /* Set Remote IP addr if Point to Point Interface */
-       if (oi->type == LINK_TYPE_SUBTLV_VALUE_PTP) {
+       if (oi->type == OSPF_IFTYPE_POINTOPOINT) {
                struct prefix *pref = CONNECTED_PREFIX(oi->connected);
                if (pref != NULL)
                        set_linkparams_rmtif_ipaddr(lp, pref->u.prefix4);
@@ -837,21 +810,20 @@ static int is_mandated_params_set(struct mpls_te_link *lp)
        if (ntohs(OspfMplsTE.router_addr.header.type) == 0) {
                zlog_warn(
                        "MPLS-TE(is_mandated_params_set) Missing Router Address");
-               goto out;
+               return rc;
        }
 
        if (ntohs(lp->link_type.header.type) == 0) {
                zlog_warn("MPLS-TE(is_mandated_params_set) Missing Link Type");
-               goto out;
+               return rc;
        }
 
        if (!IS_INTER_AS(lp->type) && (ntohs(lp->link_id.header.type) == 0)) {
                zlog_warn("MPLS-TE(is_mandated_params_set) Missing Link ID");
-               goto out;
+               return rc;
        }
 
        rc = 1;
-out:
        return rc;
 }
 
@@ -873,14 +845,14 @@ static int ospf_mpls_te_new_if(struct interface *ifp)
                zlog_warn("ospf_mpls_te_new_if: ifp(%p) already in use?",
                          (void *)ifp);
                rc = 0; /* Do nothing here. */
-               goto out;
+               return rc;
        }
 
        new = XCALLOC(MTYPE_OSPF_MPLS_TE, sizeof(struct mpls_te_link));
        if (new == NULL) {
                zlog_warn("ospf_mpls_te_new_if: XMALLOC: %s",
                          safe_strerror(errno));
-               goto out;
+               return rc;
        }
 
        new->instance = get_mpls_te_instance_value();
@@ -909,7 +881,6 @@ static int ospf_mpls_te_new_if(struct interface *ifp)
        /* Schedule Opaque-LSA refresh. */ /* XXX */
 
        rc = 0;
-out:
        return rc;
 }
 
@@ -934,7 +905,6 @@ static int ospf_mpls_te_del_if(struct interface *ifp)
        /* Schedule Opaque-LSA refresh. */ /* XXX */
 
        rc = 0;
-       /*out:*/
        return rc;
 }
 
@@ -952,10 +922,9 @@ void ospf_mpls_te_update_if(struct interface *ifp)
 
        /* Get Link context from interface */
        if ((lp = lookup_linkparams_by_ifp(ifp)) == NULL) {
-               if (IS_DEBUG_OSPF_TE)
-                       zlog_warn(
-                               "OSPF MPLS-TE Update: Did not find Link Parameters context for interface %s",
-                               ifp->name);
+               zlog_warn(
+                       "OSPF MPLS-TE Update: Did not find Link Parameters context for interface %s",
+                       ifp->name);
                return;
        }
 
@@ -968,20 +937,18 @@ void ospf_mpls_te_update_if(struct interface *ifp)
 
                /* Finally Re-Originate or Refresh Opaque LSA if MPLS_TE is
                 * enabled */
-               if (OspfMplsTE.status == enabled)
+               if (OspfMplsTE.enabled)
                        if (lp->area != NULL) {
-                               if
-                                       CHECK_FLAG(lp->flags, LPFLG_LSA_ENGAGED)
-                               ospf_mpls_te_lsa_schedule(lp, REFRESH_THIS_LSA);
-                               else ospf_mpls_te_lsa_schedule(
-                                       lp, REORIGINATE_THIS_LSA);
+                               if (CHECK_FLAG(lp->flags, LPFLG_LSA_ENGAGED))
+                                       ospf_mpls_te_lsa_schedule(lp, REFRESH_THIS_LSA);
+                               else
+                                       ospf_mpls_te_lsa_schedule(lp, REORIGINATE_THIS_LSA);
                        }
        } else {
                /* If MPLS TE is disable on this interface, flush LSA if it is
                 * already engaged */
-               if
-                       CHECK_FLAG(lp->flags, LPFLG_LSA_ENGAGED)
-               ospf_mpls_te_lsa_schedule(lp, FLUSH_THIS_LSA);
+               if (CHECK_FLAG(lp->flags, LPFLG_LSA_ENGAGED))
+                       ospf_mpls_te_lsa_schedule(lp, FLUSH_THIS_LSA);
                else
                        /* Reset Activity flag */
                        lp->flags = LPFLG_LSA_INACTIVE;
@@ -1000,14 +967,14 @@ static void ospf_mpls_te_ism_change(struct ospf_interface *oi, int old_state)
                zlog_warn(
                        "ospf_mpls_te_ism_change: Cannot get linkparams from OI(%s)?",
                        IF_NAME(oi));
-               goto out;
+               return;
        }
 
        if (oi->area == NULL || oi->area->ospf == NULL) {
                zlog_warn(
                        "ospf_mpls_te_ism_change: Cannot refer to OSPF from OI(%s)?",
                        IF_NAME(oi));
-               goto out;
+               return;
        }
 #ifdef notyet
        if ((lp->area != NULL
@@ -1059,24 +1026,21 @@ static void ospf_mpls_te_ism_change(struct ospf_interface *oi, int old_state)
                                != ntohs(lp->link_id.header.type)
                        || ntohl(old_id.value.s_addr)
                                   != ntohl(lp->link_id.value.s_addr))) {
-                       if
-                               CHECK_FLAG(lp->flags, LPFLG_LSA_ENGAGED)
-                       ospf_mpls_te_lsa_schedule(lp, REFRESH_THIS_LSA);
-                       else ospf_mpls_te_lsa_schedule(lp,
-                                                      REORIGINATE_THIS_LSA);
+                       if (CHECK_FLAG(lp->flags, LPFLG_LSA_ENGAGED))
+                               ospf_mpls_te_lsa_schedule(lp, REFRESH_THIS_LSA);
+                       else
+                               ospf_mpls_te_lsa_schedule(lp, REORIGINATE_THIS_LSA);
                }
                break;
        default:
                lp->link_type.header.type = htons(0);
                lp->link_id.header.type = htons(0);
 
-               if
-                       CHECK_FLAG(lp->flags, LPFLG_LSA_ENGAGED)
-               ospf_mpls_te_lsa_schedule(lp, FLUSH_THIS_LSA);
+               if (CHECK_FLAG(lp->flags, LPFLG_LSA_ENGAGED))
+                       ospf_mpls_te_lsa_schedule(lp, FLUSH_THIS_LSA);
                break;
        }
 
-out:
        return;
 }
 
@@ -1090,28 +1054,28 @@ static void ospf_mpls_te_nsm_change(struct ospf_neighbor *nbr, int old_state)
  * Followings are OSPF protocol processing functions for MPLS-TE.
  *------------------------------------------------------------------------*/
 
-static void build_tlv_header(struct stream *s, struct te_tlv_header *tlvh)
+static void build_tlv_header(struct stream *s, struct tlv_header *tlvh)
 {
-       stream_put(s, tlvh, sizeof(struct te_tlv_header));
+       stream_put(s, tlvh, sizeof(struct tlv_header));
        return;
 }
 
 static void build_router_tlv(struct stream *s)
 {
-       struct te_tlv_header *tlvh = &OspfMplsTE.router_addr.header;
+       struct tlv_header *tlvh = &OspfMplsTE.router_addr.header;
        if (ntohs(tlvh->type) != 0) {
                build_tlv_header(s, tlvh);
-               stream_put(s, tlvh + 1, TLV_BODY_SIZE(tlvh));
+               stream_put(s, TLV_DATA(tlvh), TLV_BODY_SIZE(tlvh));
        }
        return;
 }
 
-static void build_link_subtlv(struct stream *s, struct te_tlv_header *tlvh)
+static void build_link_subtlv(struct stream *s, struct tlv_header *tlvh)
 {
 
        if ((tlvh != NULL) && (ntohs(tlvh->type) != 0)) {
                build_tlv_header(s, tlvh);
-               stream_put(s, tlvh + 1, TLV_BODY_SIZE(tlvh));
+               stream_put(s, TLV_DATA(tlvh), TLV_BODY_SIZE(tlvh));
        }
        return;
 }
@@ -1177,7 +1141,7 @@ static struct ospf_lsa *ospf_mpls_te_lsa_new(struct ospf_area *area,
        /* Create a stream for LSA. */
        if ((s = stream_new(OSPF_MAX_LSA_SIZE)) == NULL) {
                zlog_warn("ospf_mpls_te_lsa_new: stream_new() ?");
-               goto out;
+               return NULL;
        }
        lsah = (struct lsa_header *)STREAM_DATA(s);
 
@@ -1233,14 +1197,14 @@ static struct ospf_lsa *ospf_mpls_te_lsa_new(struct ospf_area *area,
        if ((new = ospf_lsa_new()) == NULL) {
                zlog_warn("ospf_mpls_te_lsa_new: ospf_lsa_new() ?");
                stream_free(s);
-               goto out;
+               return NULL;
        }
        if ((new->data = ospf_lsa_data_new(length)) == NULL) {
                zlog_warn("ospf_mpls_te_lsa_new: ospf_lsa_data_new() ?");
                ospf_lsa_unlock(&new);
                new = NULL;
                stream_free(s);
-               goto out;
+               return new;
        }
 
        new->area = area;
@@ -1248,7 +1212,6 @@ static struct ospf_lsa *ospf_mpls_te_lsa_new(struct ospf_area *area,
        memcpy(new->data, lsah, length);
        stream_free(s);
 
-out:
        return new;
 }
 
@@ -1262,14 +1225,14 @@ static int ospf_mpls_te_lsa_originate1(struct ospf_area *area,
        if ((new = ospf_mpls_te_lsa_new(area, lp)) == NULL) {
                zlog_warn(
                        "ospf_mpls_te_lsa_originate1: ospf_mpls_te_lsa_new() ?");
-               goto out;
+               return rc;
        }
 
        /* Install this LSA into LSDB. */
        if (ospf_lsa_install(area->ospf, NULL /*oi*/, new) == NULL) {
                zlog_warn("ospf_mpls_te_lsa_originate1: ospf_lsa_install() ?");
                ospf_lsa_unlock(&new);
-               goto out;
+               return rc;
        }
 
        /* Now this link-parameter entry has associated LSA. */
@@ -1291,7 +1254,6 @@ static int ospf_mpls_te_lsa_originate1(struct ospf_area *area,
        }
 
        rc = 0;
-out:
        return rc;
 }
 
@@ -1302,11 +1264,11 @@ static int ospf_mpls_te_lsa_originate_area(void *arg)
        struct mpls_te_link *lp;
        int rc = -1;
 
-       if (OspfMplsTE.status == disabled) {
+       if (!OspfMplsTE.enabled) {
                zlog_info(
                        "ospf_mpls_te_lsa_originate_area: MPLS-TE is disabled now.");
                rc = 0; /* This is not an error case. */
-               goto out;
+               return rc;
        }
 
        for (ALL_LIST_ELEMENTS(OspfMplsTE.iflist, node, nnode, lp)) {
@@ -1321,23 +1283,16 @@ static int ospf_mpls_te_lsa_originate_area(void *arg)
                if (!IPV4_ADDR_SAME(&lp->area->area_id, &area->area_id))
                        continue;
 
-               if
-                       CHECK_FLAG(lp->flags, LPFLG_LSA_ENGAGED)
-                       {
-                               if
-                                       CHECK_FLAG(lp->flags,
-                                                  LPFLG_LSA_FORCED_REFRESH)
-                                       {
-                                               UNSET_FLAG(
-                                                       lp->flags,
-                                                       LPFLG_LSA_FORCED_REFRESH);
-                                               zlog_warn(
-                                                       "OSPF MPLS-TE (ospf_mpls_te_lsa_originate_area): Refresh instead of Originate");
-                                               ospf_mpls_te_lsa_schedule(
-                                                       lp, REFRESH_THIS_LSA);
-                                       }
-                               continue;
+               if (CHECK_FLAG(lp->flags, LPFLG_LSA_ENGAGED)) {
+                       if (CHECK_FLAG(lp->flags, LPFLG_LSA_FORCED_REFRESH)) {
+                               UNSET_FLAG(lp->flags, LPFLG_LSA_FORCED_REFRESH);
+                               zlog_warn(
+                                       "OSPF MPLS-TE (ospf_mpls_te_lsa_originate_area): Refresh instead of Originate");
+                               ospf_mpls_te_lsa_schedule(lp, REFRESH_THIS_LSA);
                        }
+                       continue;
+               }
+
                if (!is_mandated_params_set(lp)) {
                        zlog_warn(
                                "ospf_mpls_te_lsa_originate_area: Link(%s) lacks some mandated MPLS-TE parameters.",
@@ -1352,11 +1307,10 @@ static int ospf_mpls_te_lsa_originate_area(void *arg)
                                lp->instance, inet_ntoa(area->area_id),
                                lp->ifp ? lp->ifp->name : "?");
                if (ospf_mpls_te_lsa_originate1(area, lp) != 0)
-                       goto out;
+                       return rc;
        }
 
        rc = 0;
-out:
        return rc;
 }
 
@@ -1370,14 +1324,14 @@ static int ospf_mpls_te_lsa_originate2(struct ospf *top,
        if ((new = ospf_mpls_te_lsa_new(NULL, lp)) == NULL) {
                zlog_warn(
                        "ospf_mpls_te_lsa_originate2: ospf_router_info_lsa_new() ?");
-               goto out;
+               return rc;
        }
 
        /* Install this LSA into LSDB. */
        if (ospf_lsa_install(top, NULL /*oi */, new) == NULL) {
                zlog_warn("ospf_mpls_te_lsa_originate2: ospf_lsa_install() ?");
                ospf_lsa_unlock(&new);
-               goto out;
+               return rc;
        }
 
        /* Now this Router Info parameter entry has associated LSA. */
@@ -1396,7 +1350,6 @@ static int ospf_mpls_te_lsa_originate2(struct ospf *top,
        }
 
        rc = 0;
-out:
        return rc;
 }
 
@@ -1408,12 +1361,12 @@ static int ospf_mpls_te_lsa_originate_as(void *arg)
        struct mpls_te_link *lp;
        int rc = -1;
 
-       if ((OspfMplsTE.status == disabled)
-           || (OspfMplsTE.inter_as == Disable)) {
+       if ((!OspfMplsTE.enabled)
+           || (OspfMplsTE.inter_as == Off)) {
                zlog_info(
                        "ospf_mpls_te_lsa_originate_as: MPLS-TE Inter-AS is disabled for now.");
                rc = 0; /* This is not an error case. */
-               goto out;
+               return rc;
        }
 
        for (ALL_LIST_ELEMENTS(OspfMplsTE.iflist, node, nnode, lp)) {
@@ -1422,21 +1375,14 @@ static int ospf_mpls_te_lsa_originate_as(void *arg)
                    || !IS_INTER_AS(lp->type))
                        continue;
 
-               if
-                       CHECK_FLAG(lp->flags, LPFLG_LSA_ENGAGED)
-                       {
-                               if
-                                       CHECK_FLAG(lp->flags,
-                                                  LPFLG_LSA_FORCED_REFRESH)
-                                       {
-                                               UNSET_FLAG(
-                                                       lp->flags,
-                                                       LPFLG_LSA_FORCED_REFRESH);
-                                               ospf_mpls_te_lsa_schedule(
-                                                       lp, REFRESH_THIS_LSA);
-                                       }
-                               continue;
+               if (CHECK_FLAG(lp->flags, LPFLG_LSA_ENGAGED)) {
+                       if (CHECK_FLAG(lp->flags, LPFLG_LSA_FORCED_REFRESH)) {
+                               UNSET_FLAG(lp->flags,LPFLG_LSA_FORCED_REFRESH);
+                               ospf_mpls_te_lsa_schedule(lp, REFRESH_THIS_LSA);
                        }
+                       continue;
+               }
+
                if (!is_mandated_params_set(lp)) {
                        zlog_warn(
                                "ospf_mpls_te_lsa_originate_as: Link(%s) lacks some mandated MPLS-TE parameters.",
@@ -1462,7 +1408,6 @@ static int ospf_mpls_te_lsa_originate_as(void *arg)
        }
 
        rc = 0;
-out:
        return rc;
 }
 
@@ -1473,7 +1418,7 @@ static struct ospf_lsa *ospf_mpls_te_lsa_refresh(struct ospf_lsa *lsa)
        struct ospf *top;
        struct ospf_lsa *new = NULL;
 
-       if (OspfMplsTE.status == disabled) {
+       if (!OspfMplsTE.enabled) {
                /*
                 * This LSA must have flushed before due to MPLS-TE status
                 * change.
@@ -1504,13 +1449,13 @@ static struct ospf_lsa *ospf_mpls_te_lsa_refresh(struct ospf_lsa *lsa)
                if (lp)
                        UNSET_FLAG(lp->flags, LPFLG_LSA_ENGAGED);
                ospf_opaque_lsa_flush_schedule(lsa);
-               goto out;
+               return NULL;
        }
 
        /* Create new Opaque-LSA/MPLS-TE instance. */
        if ((new = ospf_mpls_te_lsa_new(area, lp)) == NULL) {
                zlog_warn("ospf_mpls_te_lsa_refresh: ospf_mpls_te_lsa_new() ?");
-               goto out;
+               return NULL;
        }
        new->data->ls_seqnum = lsa_seqnum_increment(lsa);
 
@@ -1526,7 +1471,7 @@ static struct ospf_lsa *ospf_mpls_te_lsa_refresh(struct ospf_lsa *lsa)
        if (ospf_lsa_install(top, NULL /*oi */, new) == NULL) {
                zlog_warn("ospf_mpls_te_lsa_refresh: ospf_lsa_install() ?");
                ospf_lsa_unlock(&new);
-               goto out;
+               return NULL;
        }
 
        /* Flood updated LSA through AS or Area depending of the RFC of the link
@@ -1543,11 +1488,10 @@ static struct ospf_lsa *ospf_mpls_te_lsa_refresh(struct ospf_lsa *lsa)
                ospf_lsa_header_dump(new->data);
        }
 
-out:
        return new;
 }
 
-void ospf_mpls_te_lsa_schedule(struct mpls_te_link *lp, opcode_t opcode)
+void ospf_mpls_te_lsa_schedule(struct mpls_te_link *lp, enum lsa_opcode opcode)
 {
        struct ospf_lsa lsa;
        struct lsa_header lsah;
@@ -1636,7 +1580,7 @@ void ospf_mpls_te_lsa_schedule(struct mpls_te_link *lp, opcode_t opcode)
  *------------------------------------------------------------------------*/
 
 static u_int16_t show_vty_router_addr(struct vty *vty,
-                                     struct te_tlv_header *tlvh)
+                                     struct tlv_header *tlvh)
 {
        struct te_tlv_router_addr *top = (struct te_tlv_router_addr *)tlvh;
 
@@ -1649,7 +1593,7 @@ static u_int16_t show_vty_router_addr(struct vty *vty,
 }
 
 static u_int16_t show_vty_link_header(struct vty *vty,
-                                     struct te_tlv_header *tlvh)
+                                     struct tlv_header *tlvh)
 {
        struct te_tlv_link *top = (struct te_tlv_link *)tlvh;
 
@@ -1664,7 +1608,7 @@ static u_int16_t show_vty_link_header(struct vty *vty,
 }
 
 static u_int16_t show_vty_link_subtlv_link_type(struct vty *vty,
-                                               struct te_tlv_header *tlvh)
+                                               struct tlv_header *tlvh)
 {
        struct te_link_subtlv_link_type *top;
        const char *cp = "Unknown";
@@ -1691,7 +1635,7 @@ static u_int16_t show_vty_link_subtlv_link_type(struct vty *vty,
 }
 
 static u_int16_t show_vty_link_subtlv_link_id(struct vty *vty,
-                                             struct te_tlv_header *tlvh)
+                                             struct tlv_header *tlvh)
 {
        struct te_link_subtlv_link_id *top;
 
@@ -1705,7 +1649,7 @@ static u_int16_t show_vty_link_subtlv_link_id(struct vty *vty,
 }
 
 static u_int16_t show_vty_link_subtlv_lclif_ipaddr(struct vty *vty,
-                                                  struct te_tlv_header *tlvh)
+                                                  struct tlv_header *tlvh)
 {
        struct te_link_subtlv_lclif_ipaddr *top;
        int i, n;
@@ -1730,7 +1674,7 @@ static u_int16_t show_vty_link_subtlv_lclif_ipaddr(struct vty *vty,
 }
 
 static u_int16_t show_vty_link_subtlv_rmtif_ipaddr(struct vty *vty,
-                                                  struct te_tlv_header *tlvh)
+                                                  struct tlv_header *tlvh)
 {
        struct te_link_subtlv_rmtif_ipaddr *top;
        int i, n;
@@ -1754,7 +1698,7 @@ static u_int16_t show_vty_link_subtlv_rmtif_ipaddr(struct vty *vty,
 }
 
 static u_int16_t show_vty_link_subtlv_te_metric(struct vty *vty,
-                                               struct te_tlv_header *tlvh)
+                                               struct tlv_header *tlvh)
 {
        struct te_link_subtlv_te_metric *top;
 
@@ -1770,7 +1714,7 @@ static u_int16_t show_vty_link_subtlv_te_metric(struct vty *vty,
 }
 
 static u_int16_t show_vty_link_subtlv_max_bw(struct vty *vty,
-                                            struct te_tlv_header *tlvh)
+                                            struct tlv_header *tlvh)
 {
        struct te_link_subtlv_max_bw *top;
        float fval;
@@ -1787,7 +1731,7 @@ static u_int16_t show_vty_link_subtlv_max_bw(struct vty *vty,
 }
 
 static u_int16_t show_vty_link_subtlv_max_rsv_bw(struct vty *vty,
-                                                struct te_tlv_header *tlvh)
+                                                struct tlv_header *tlvh)
 {
        struct te_link_subtlv_max_rsv_bw *top;
        float fval;
@@ -1806,7 +1750,7 @@ static u_int16_t show_vty_link_subtlv_max_rsv_bw(struct vty *vty,
 }
 
 static u_int16_t show_vty_link_subtlv_unrsv_bw(struct vty *vty,
-                                              struct te_tlv_header *tlvh)
+                                              struct tlv_header *tlvh)
 {
        struct te_link_subtlv_unrsv_bw *top;
        float fval1, fval2;
@@ -1837,7 +1781,7 @@ static u_int16_t show_vty_link_subtlv_unrsv_bw(struct vty *vty,
 }
 
 static u_int16_t show_vty_link_subtlv_rsc_clsclr(struct vty *vty,
-                                                struct te_tlv_header *tlvh)
+                                                struct tlv_header *tlvh)
 {
        struct te_link_subtlv_rsc_clsclr *top;
 
@@ -1853,7 +1797,7 @@ static u_int16_t show_vty_link_subtlv_rsc_clsclr(struct vty *vty,
 }
 
 static u_int16_t show_vty_link_subtlv_lrrid(struct vty *vty,
-                                           struct te_tlv_header *tlvh)
+                                           struct tlv_header *tlvh)
 {
        struct te_link_subtlv_lrrid *top;
 
@@ -1875,7 +1819,7 @@ static u_int16_t show_vty_link_subtlv_lrrid(struct vty *vty,
 }
 
 static u_int16_t show_vty_link_subtlv_llri(struct vty *vty,
-                                          struct te_tlv_header *tlvh)
+                                          struct tlv_header *tlvh)
 {
        struct te_link_subtlv_llri *top;
 
@@ -1897,7 +1841,7 @@ static u_int16_t show_vty_link_subtlv_llri(struct vty *vty,
 }
 
 static u_int16_t show_vty_link_subtlv_rip(struct vty *vty,
-                                         struct te_tlv_header *tlvh)
+                                         struct tlv_header *tlvh)
 {
        struct te_link_subtlv_rip *top;
 
@@ -1914,7 +1858,7 @@ static u_int16_t show_vty_link_subtlv_rip(struct vty *vty,
 }
 
 static u_int16_t show_vty_link_subtlv_ras(struct vty *vty,
-                                         struct te_tlv_header *tlvh)
+                                         struct tlv_header *tlvh)
 {
        struct te_link_subtlv_ras *top;
 
@@ -1931,7 +1875,7 @@ static u_int16_t show_vty_link_subtlv_ras(struct vty *vty,
 }
 
 static u_int16_t show_vty_link_subtlv_av_delay(struct vty *vty,
-                                              struct te_tlv_header *tlvh)
+                                              struct tlv_header *tlvh)
 {
        struct te_link_subtlv_av_delay *top;
        u_int32_t delay;
@@ -1952,7 +1896,7 @@ static u_int16_t show_vty_link_subtlv_av_delay(struct vty *vty,
 }
 
 static u_int16_t show_vty_link_subtlv_mm_delay(struct vty *vty,
-                                              struct te_tlv_header *tlvh)
+                                              struct tlv_header *tlvh)
 {
        struct te_link_subtlv_mm_delay *top;
        u_int32_t low, high;
@@ -1974,7 +1918,7 @@ static u_int16_t show_vty_link_subtlv_mm_delay(struct vty *vty,
 }
 
 static u_int16_t show_vty_link_subtlv_delay_var(struct vty *vty,
-                                               struct te_tlv_header *tlvh)
+                                               struct tlv_header *tlvh)
 {
        struct te_link_subtlv_delay_var *top;
        u_int32_t jitter;
@@ -1991,7 +1935,7 @@ static u_int16_t show_vty_link_subtlv_delay_var(struct vty *vty,
 }
 
 static u_int16_t show_vty_link_subtlv_pkt_loss(struct vty *vty,
-                                              struct te_tlv_header *tlvh)
+                                              struct tlv_header *tlvh)
 {
        struct te_link_subtlv_pkt_loss *top;
        u_int32_t loss;
@@ -2014,7 +1958,7 @@ static u_int16_t show_vty_link_subtlv_pkt_loss(struct vty *vty,
 }
 
 static u_int16_t show_vty_link_subtlv_res_bw(struct vty *vty,
-                                            struct te_tlv_header *tlvh)
+                                            struct tlv_header *tlvh)
 {
        struct te_link_subtlv_res_bw *top;
        float fval;
@@ -2035,7 +1979,7 @@ static u_int16_t show_vty_link_subtlv_res_bw(struct vty *vty,
 }
 
 static u_int16_t show_vty_link_subtlv_ava_bw(struct vty *vty,
-                                            struct te_tlv_header *tlvh)
+                                            struct tlv_header *tlvh)
 {
        struct te_link_subtlv_ava_bw *top;
        float fval;
@@ -2056,7 +2000,7 @@ static u_int16_t show_vty_link_subtlv_ava_bw(struct vty *vty,
 }
 
 static u_int16_t show_vty_link_subtlv_use_bw(struct vty *vty,
-                                            struct te_tlv_header *tlvh)
+                                            struct tlv_header *tlvh)
 {
        struct te_link_subtlv_use_bw *top;
        float fval;
@@ -2077,7 +2021,7 @@ static u_int16_t show_vty_link_subtlv_use_bw(struct vty *vty,
 }
 
 static u_int16_t show_vty_unknown_tlv(struct vty *vty,
-                                     struct te_tlv_header *tlvh)
+                                     struct tlv_header *tlvh)
 {
        if (vty != NULL)
                vty_out(vty, "  Unknown TLV: [type(0x%x), length(0x%x)]\n",
@@ -2090,11 +2034,11 @@ static u_int16_t show_vty_unknown_tlv(struct vty *vty,
 }
 
 static u_int16_t ospf_mpls_te_show_link_subtlv(struct vty *vty,
-                                              struct te_tlv_header *tlvh0,
+                                              struct tlv_header *tlvh0,
                                               u_int16_t subtotal,
                                               u_int16_t total)
 {
-       struct te_tlv_header *tlvh, *next;
+       struct tlv_header *tlvh, *next;
        u_int16_t sum = subtotal;
 
        for (tlvh = tlvh0; sum < total;
@@ -2172,9 +2116,9 @@ static u_int16_t ospf_mpls_te_show_link_subtlv(struct vty *vty,
 static void ospf_mpls_te_show_info(struct vty *vty, struct ospf_lsa *lsa)
 {
        struct lsa_header *lsah = (struct lsa_header *)lsa->data;
-       struct te_tlv_header *tlvh, *next;
+       struct tlv_header *tlvh, *next;
        u_int16_t sum, total;
-       u_int16_t (*subfunc)(struct vty * vty, struct te_tlv_header * tlvh,
+       u_int16_t (*subfunc)(struct vty * vty, struct tlv_header * tlvh,
                             u_int16_t subtotal, u_int16_t total) = NULL;
 
        sum = 0;
@@ -2184,7 +2128,7 @@ static void ospf_mpls_te_show_info(struct vty *vty, struct ospf_lsa *lsa)
             tlvh = (next ? next : TLV_HDR_NEXT(tlvh))) {
                if (subfunc != NULL) {
                        sum = (*subfunc)(vty, tlvh, sum, total);
-                       next = (struct te_tlv_header *)((char *)tlvh + sum);
+                       next = (struct tlv_header *)((char *)tlvh + sum);
                        subfunc = NULL;
                        continue;
                }
@@ -2197,7 +2141,7 @@ static void ospf_mpls_te_show_info(struct vty *vty, struct ospf_lsa *lsa)
                case TE_TLV_LINK:
                        sum += show_vty_link_header(vty, tlvh);
                        subfunc = ospf_mpls_te_show_link_subtlv;
-                       next = tlvh + 1;
+                       next = TLV_DATA(tlvh);
                        break;
                default:
                        sum += show_vty_unknown_tlv(vty, tlvh);
@@ -2210,7 +2154,7 @@ static void ospf_mpls_te_show_info(struct vty *vty, struct ospf_lsa *lsa)
 static void ospf_mpls_te_config_write_router(struct vty *vty)
 {
 
-       if (OspfMplsTE.status == enabled) {
+       if (OspfMplsTE.enabled) {
                vty_out(vty, " mpls-te on\n");
                vty_out(vty, " mpls-te router-address %s\n",
                        inet_ntoa(OspfMplsTE.router_addr.value));
@@ -2235,24 +2179,24 @@ DEFUN (ospf_mpls_te_on,
        MPLS_TE_STR
        "Enable the MPLS-TE functionality\n")
 {
-       VTY_DECLVAR_CONTEXT(ospf, ospf);
+       VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
        struct listnode *node;
        struct mpls_te_link *lp;
 
-       if (OspfMplsTE.status == enabled)
+       if (OspfMplsTE.enabled)
                return CMD_SUCCESS;
 
        if (IS_DEBUG_OSPF_EVENT)
                zlog_debug("MPLS-TE: OFF -> ON");
 
-       OspfMplsTE.status = enabled;
+       OspfMplsTE.enabled = true;
 
        /* Reoriginate RFC3630 & RFC6827 Links */
        ospf_mpls_te_foreach_area(ospf_mpls_te_lsa_schedule,
                                  REORIGINATE_THIS_LSA);
 
        /* Reoriginate LSA if INTER-AS is always on */
-       if (OspfMplsTE.inter_as != Disable) {
+       if (OspfMplsTE.inter_as != Off) {
                for (ALL_LIST_ELEMENTS_RO(OspfMplsTE.iflist, node, lp)) {
                        if (IS_INTER_AS(lp->type)) {
                                ospf_mpls_te_lsa_schedule(lp,
@@ -2271,22 +2215,21 @@ DEFUN (no_ospf_mpls_te,
        MPLS_TE_STR
        "Disable the MPLS-TE functionality\n")
 {
-       VTY_DECLVAR_CONTEXT(ospf, ospf);
+       VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
        struct listnode *node, *nnode;
        struct mpls_te_link *lp;
 
-       if (OspfMplsTE.status == disabled)
+       if (!OspfMplsTE.enabled)
                return CMD_SUCCESS;
 
        if (IS_DEBUG_OSPF_EVENT)
                zlog_debug("MPLS-TE: ON -> OFF");
 
-       OspfMplsTE.status = disabled;
+       OspfMplsTE.enabled = false;
 
        for (ALL_LIST_ELEMENTS(OspfMplsTE.iflist, node, nnode, lp))
-               if
-                       CHECK_FLAG(lp->flags, LPFLG_LSA_ENGAGED)
-       ospf_mpls_te_lsa_schedule(lp, FLUSH_THIS_LSA);
+               if (CHECK_FLAG(lp->flags, LPFLG_LSA_ENGAGED))
+                       ospf_mpls_te_lsa_schedule(lp, FLUSH_THIS_LSA);
 
        return CMD_SUCCESS;
 }
@@ -2299,7 +2242,7 @@ DEFUN (ospf_mpls_te_router_addr,
        "Stable IP address of the advertising router\n"
        "MPLS-TE router address in IPv4 address format\n")
 {
-       VTY_DECLVAR_CONTEXT(ospf, ospf);
+       VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
        int idx_ipv4 = 2;
        struct te_tlv_router_addr *ra = &OspfMplsTE.router_addr;
        struct in_addr value;
@@ -2317,8 +2260,8 @@ DEFUN (ospf_mpls_te_router_addr,
 
                set_mpls_te_router_addr(value);
 
-               if (OspfMplsTE.status == disabled)
-                       goto out;
+               if (!OspfMplsTE.enabled)
+                       return CMD_SUCCESS;
 
                for (ALL_LIST_ELEMENTS(OspfMplsTE.iflist, node, nnode, lp)) {
                        if ((lp->area == NULL) || IS_FLOOD_AS(lp->type))
@@ -2344,7 +2287,7 @@ DEFUN (ospf_mpls_te_router_addr,
                        ospf_mpls_te_foreach_area(ospf_mpls_te_lsa_schedule,
                                                  REORIGINATE_THIS_LSA);
        }
-out:
+
        return CMD_SUCCESS;
 }
 
@@ -2356,7 +2299,7 @@ static int set_inter_as_mode(struct vty *vty, const char *mode_name,
        struct mpls_te_link *lp;
        int format;
 
-       if (OspfMplsTE.status == enabled) {
+       if (OspfMplsTE.enabled) {
 
                /* Read and Check inter_as mode */
                if (strcmp(mode_name, "as") == 0)
@@ -2385,7 +2328,7 @@ static int set_inter_as_mode(struct vty *vty, const char *mode_name,
                }
 
                /* Enable mode and re-originate LSA if needed */
-               if ((OspfMplsTE.inter_as == Disable)
+               if ((OspfMplsTE.inter_as == Off)
                    && (mode != OspfMplsTE.inter_as)) {
                        OspfMplsTE.inter_as = mode;
                        /* Re-originate all InterAS-TEv2 LSA */
@@ -2451,9 +2394,9 @@ DEFUN (no_ospf_mpls_te_inter_as,
        if (IS_DEBUG_OSPF_EVENT)
                zlog_debug("MPLS-TE: Inter-AS support OFF");
 
-       if ((OspfMplsTE.status == enabled)
-           && (OspfMplsTE.inter_as != Disable)) {
-               OspfMplsTE.inter_as = Disable;
+       if ((OspfMplsTE.enabled)
+           && (OspfMplsTE.inter_as != Off)) {
+               OspfMplsTE.inter_as = Off;
                /* Flush all Inter-AS LSA */
                for (ALL_LIST_ELEMENTS(OspfMplsTE.iflist, node, nnode, lp))
                        if (IS_INTER_AS(lp->type)
@@ -2476,7 +2419,7 @@ DEFUN (show_ip_ospf_mpls_te_router,
        "MPLS-TE information\n"
        "MPLS-TE Router parameters\n")
 {
-       if (OspfMplsTE.status == enabled) {
+       if (OspfMplsTE.enabled) {
                vty_out(vty, "--- MPLS-TE router parameters ---\n");
 
                if (ntohs(OspfMplsTE.router_addr.header.type) != 0)
@@ -2492,7 +2435,7 @@ static void show_mpls_te_link_sub(struct vty *vty, struct interface *ifp)
 {
        struct mpls_te_link *lp;
 
-       if ((OspfMplsTE.status == enabled) && HAS_LINK_PARAMS(ifp)
+       if ((OspfMplsTE.enabled) && HAS_LINK_PARAMS(ifp)
            && !if_is_loopback(ifp) && if_is_up(ifp)
            && ((lp = lookup_linkparams_by_ifp(ifp)) != NULL)) {
                /* Continue only if interface is not passive or support Inter-AS
index 4ee9139a3c5f31d99e4835581c79dd0354cabbd6..013421451057691235b2a25887b8ce44500ae19d 100644 (file)
@@ -78,7 +78,7 @@
 #define FLOOD_AS       0x20
 #define EMULATED       0x80
 
-#define IS_STD_TE(x)           (x & STD_TE)
+#define IS_STD_TE(x)       (x & STD_TE)
 #define IS_PSEUDO_TE(x)                (x & PSEUDO_TE)
 #define IS_INTER_AS(x)                 (x & INTER_AS)
 #define IS_EMULATED(x)         (x & EMULATED)
 #define LPFLG_LOOKUP_DONE              0x4
 #define LPFLG_LSA_FORCED_REFRESH       0x8
 
-/*
- * Following section defines TLV (tag, length, value) structures,
- * used for Traffic Engineering.
- */
-struct te_tlv_header {
-       u_int16_t type;   /* TE_TLV_XXX (see below) */
-       u_int16_t length; /* Value portion only, in octets */
-};
-
-#define TLV_HDR_SIZE (sizeof(struct te_tlv_header))
-
-#define TLV_BODY_SIZE(tlvh) (ROUNDUP(ntohs((tlvh)->length), sizeof(u_int32_t)))
-
-#define TLV_SIZE(tlvh) (TLV_HDR_SIZE + TLV_BODY_SIZE(tlvh))
-
-#define TLV_HDR_TOP(lsah)                                                      \
-       (struct te_tlv_header *)((char *)(lsah) + OSPF_LSA_HEADER_SIZE)
-
-#define TLV_HDR_NEXT(tlvh)                                                     \
-       (struct te_tlv_header *)((char *)(tlvh) + TLV_SIZE(tlvh))
-
-#define TLV_HDR_SUBTLV(tlvh)                                                   \
-       (struct te_tlv_header *)((char *)(tlvh) + TLV_HDR_SIZE)
-
-#define TLV_TYPE(tlvh)     tlvh.header.type
-#define TLV_LEN(tlvh)      tlvh.header.length
-#define TLV_HDR(tlvh)      tlvh.header
-
 /*
  * Following section defines TLV body parts.
  */
+
 /* Router Address TLV */ /* Mandatory */
 #define        TE_TLV_ROUTER_ADDR              1
 struct te_tlv_router_addr {
-       struct te_tlv_header header; /* Value length is 4 octets. */
+       struct tlv_header header; /* Value length is 4 octets. */
        struct in_addr value;
 };
 
 /* Link TLV */
 #define        TE_TLV_LINK                     2
 struct te_tlv_link {
-       struct te_tlv_header header;
+       struct tlv_header header;
        /* A set of link-sub-TLVs will follow. */
 };
 
+/* Default TE TLV size */
 #define TE_LINK_SUBTLV_DEF_SIZE                4
 
 /* Link Type Sub-TLV */ /* Mandatory */
 #define        TE_LINK_SUBTLV_LINK_TYPE        1
 #define TE_LINK_SUBTLV_TYPE_SIZE       1
 struct te_link_subtlv_link_type {
-       struct te_tlv_header header; /* Value length is 1 octet. */
+       struct tlv_header header; /* Value length is 1 octet. */
        struct {
 #define        LINK_TYPE_SUBTLV_VALUE_PTP      1
 #define        LINK_TYPE_SUBTLV_VALUE_MA       2
@@ -157,42 +131,42 @@ struct te_link_subtlv_link_type {
 /* Link Sub-TLV: Link ID */ /* Mandatory */
 #define        TE_LINK_SUBTLV_LINK_ID          2
 struct te_link_subtlv_link_id {
-       struct te_tlv_header header; /* Value length is 4 octets. */
+       struct tlv_header header; /* Value length is 4 octets. */
        struct in_addr value;   /* Same as router-lsa's link-id. */
 };
 
 /* Link Sub-TLV: Local Interface IP Address */ /* Optional */
 #define        TE_LINK_SUBTLV_LCLIF_IPADDR     3
 struct te_link_subtlv_lclif_ipaddr {
-       struct te_tlv_header header; /* Value length is 4 x N octets. */
+       struct tlv_header header; /* Value length is 4 x N octets. */
        struct in_addr value[1];     /* Local IP address(es). */
 };
 
 /* Link Sub-TLV: Remote Interface IP Address */ /* Optional */
 #define        TE_LINK_SUBTLV_RMTIF_IPADDR     4
 struct te_link_subtlv_rmtif_ipaddr {
-       struct te_tlv_header header; /* Value length is 4 x N octets. */
+       struct tlv_header header; /* Value length is 4 x N octets. */
        struct in_addr value[1];     /* Neighbor's IP address(es). */
 };
 
 /* Link Sub-TLV: Traffic Engineering Metric */ /* Optional */
 #define        TE_LINK_SUBTLV_TE_METRIC        5
 struct te_link_subtlv_te_metric {
-       struct te_tlv_header header; /* Value length is 4 octets. */
+       struct tlv_header header; /* Value length is 4 octets. */
        u_int32_t value;             /* Link metric for TE purpose. */
 };
 
 /* Link Sub-TLV: Maximum Bandwidth */ /* Optional */
 #define        TE_LINK_SUBTLV_MAX_BW           6
 struct te_link_subtlv_max_bw {
-       struct te_tlv_header header; /* Value length is 4 octets. */
+       struct tlv_header header; /* Value length is 4 octets. */
        float value;                 /* bytes/sec */
 };
 
 /* Link Sub-TLV: Maximum Reservable Bandwidth */ /* Optional */
 #define        TE_LINK_SUBTLV_MAX_RSV_BW       7
 struct te_link_subtlv_max_rsv_bw {
-       struct te_tlv_header header; /* Value length is 4 octets. */
+       struct tlv_header header; /* Value length is 4 octets. */
        float value;                 /* bytes/sec */
 };
 
@@ -200,14 +174,14 @@ struct te_link_subtlv_max_rsv_bw {
 #define        TE_LINK_SUBTLV_UNRSV_BW         8
 #define TE_LINK_SUBTLV_UNRSV_SIZE      32
 struct te_link_subtlv_unrsv_bw {
-       struct te_tlv_header header; /* Value length is 32 octets. */
+       struct tlv_header header; /* Value length is 32 octets. */
        float value[MAX_CLASS_TYPE]; /* One for each priority level. */
 };
 
 /* Link Sub-TLV: Resource Class/Color */ /* Optional */
 #define        TE_LINK_SUBTLV_RSC_CLSCLR       9
 struct te_link_subtlv_rsc_clsclr {
-       struct te_tlv_header header; /* Value length is 4 octets. */
+       struct tlv_header header; /* Value length is 4 octets. */
        u_int32_t value;             /* Admin. group membership. */
 };
 
@@ -216,7 +190,7 @@ struct te_link_subtlv_rsc_clsclr {
 #define TE_LINK_SUBTLV_LRRID           10
 #define TE_LINK_SUBTLV_LRRID_SIZE      8
 struct te_link_subtlv_lrrid {
-       struct te_tlv_header header; /* Value length is 8 octets. */
+       struct tlv_header header; /* Value length is 8 octets. */
        struct in_addr local;   /* Local TE Router Identifier */
        struct in_addr remote;       /* Remote TE Router Identifier */
 };
@@ -225,7 +199,7 @@ struct te_link_subtlv_lrrid {
 #define TE_LINK_SUBTLV_LLRI            11
 #define TE_LINK_SUBTLV_LLRI_SIZE       8
 struct te_link_subtlv_llri {
-       struct te_tlv_header header; /* Value length is 8 octets. */
+       struct tlv_header header; /* Value length is 8 octets. */
        u_int32_t local;             /* Link Local Identifier */
        u_int32_t remote;           /* Link Remote Identifier */
 };
@@ -240,14 +214,14 @@ struct te_link_subtlv_llri {
 /* Remote AS Number sub-TLV */
 #define TE_LINK_SUBTLV_RAS             21
 struct te_link_subtlv_ras {
-       struct te_tlv_header header; /* Value length is 4 octets. */
+       struct tlv_header header; /* Value length is 4 octets. */
        u_int32_t value;             /* Remote AS number */
 };
 
 /* IPv4 Remote ASBR ID Sub-TLV */
 #define TE_LINK_SUBTLV_RIP             22
 struct te_link_subtlv_rip {
-       struct te_tlv_header header; /* Value length is 4 octets. */
+       struct tlv_header header; /* Value length is 4 octets. */
        struct in_addr value;   /* Remote ASBR IP address */
 };
 
@@ -261,63 +235,69 @@ struct te_link_subtlv_rip {
 /* Link Sub-TLV: Average Link Delay */ /* Optional */
 #define TE_LINK_SUBTLV_AV_DELAY                27
 struct te_link_subtlv_av_delay {
-       struct te_tlv_header header; /* Value length is 4 bytes. */
-       u_int32_t
-               value; /* delay in micro-seconds only 24 bits => 0 ... 16777215
-                         with Anomalous Bit as Upper most bit */
+       struct tlv_header header; /* Value length is 4 bytes. */
+       /*
+        * delay in micro-seconds only 24 bits => 0 ... 16777215
+        * with Anomalous Bit as Upper most bit
+        */
+       u_int32_t value;
 };
 
 /* Link Sub-TLV: Low/High Link Delay */
 #define TE_LINK_SUBTLV_MM_DELAY         28
 #define TE_LINK_SUBTLV_MM_DELAY_SIZE    8
 struct te_link_subtlv_mm_delay {
-       struct te_tlv_header header; /* Value length is 8 bytes. */
-       u_int32_t low;  /* low delay in micro-seconds only 24 bits => 0 ...
-                          16777215
-                          with Anomalous Bit (A) as Upper most bit */
-       u_int32_t high; /* high delay in micro-seconds only 24 bits => 0 ...
-                          16777215 */
+       struct tlv_header header; /* Value length is 8 bytes. */
+       /*
+        * low delay in micro-seconds only 24 bits => 0 ... 16777215
+        * with Anomalous Bit (A) as Upper most bit
+        */
+       u_int32_t low;
+       /* high delay in micro-seconds only 24 bits => 0 ... 16777215 */
+       u_int32_t high;
 };
 
 /* Link Sub-TLV: Link Delay Variation i.e. Jitter */
 #define TE_LINK_SUBTLV_DELAY_VAR       29
 struct te_link_subtlv_delay_var {
-       struct te_tlv_header header; /* Value length is 4 bytes. */
-       u_int32_t value; /* interval in micro-seconds only 24 bits => 0 ...
-                           16777215 */
+       struct tlv_header header; /* Value length is 4 bytes. */
+       /* interval in micro-seconds only 24 bits => 0 ... 16777215 */
+       u_int32_t value;
 };
 
 /* Link Sub-TLV: Routine Unidirectional Link Packet Loss */
 #define TE_LINK_SUBTLV_PKT_LOSS                30
 struct te_link_subtlv_pkt_loss {
-       struct te_tlv_header header; /* Value length is 4 bytes. */
-       u_int32_t
-               value; /* in percentage of total traffic only 24 bits (2^24 - 2)
-                         with Anomalous Bit as Upper most bit */
+       struct tlv_header header; /* Value length is 4 bytes. */
+       /*
+        * in percentage of total traffic only 24 bits (2^24 - 2)
+        * with Anomalous Bit as Upper most bit
+        */
+       u_int32_t value;
 };
 
 /* Link Sub-TLV: Unidirectional Residual Bandwidth */ /* Optional */
 #define TE_LINK_SUBTLV_RES_BW          31
 struct te_link_subtlv_res_bw {
-       struct te_tlv_header header; /* Value length is 4 bytes. */
-       float value; /* bandwidth in IEEE floating point format with units in
-                       bytes per second */
+       struct tlv_header header; /* Value length is 4 bytes. */
+       /* bandwidth in IEEE floating point format with units in bytes/second */
+       float value;
 };
 
 /* Link Sub-TLV: Unidirectional Available Bandwidth */ /* Optional */
 #define TE_LINK_SUBTLV_AVA_BW          32
 struct te_link_subtlv_ava_bw {
-       struct te_tlv_header header; /* Value length is 4 octets. */
-       float value; /* bandwidth in IEEE floating point format with units in
-                       bytes per second */
+       struct tlv_header header; /* Value length is 4 octets. */
+       /* bandwidth in IEEE floating point format with units in bytes/second */
+       float value;
 };
 
 /* Link Sub-TLV: Unidirectional Utilized Bandwidth */ /* Optional */
 #define TE_LINK_SUBTLV_USE_BW           33
 struct te_link_subtlv_use_bw {
-       struct te_tlv_header header; /* Value length is 4 octets. */
-       float value; /* bandwidth in IEEE floating point format with units in
-                       bytes per second */
+       struct tlv_header header; /* Value length is 4 octets. */
+       /* bandwidth in IEEE floating point format with units in bytes/second */
+       float value;
 };
 
 #define TE_LINK_SUBTLV_MAX             34      /* Last SUBTLV + 1 */
@@ -325,20 +305,11 @@ struct te_link_subtlv_use_bw {
 /* Here are "non-official" architectural constants. */
 #define MPLS_TE_MINIMUM_BANDWIDTH      1.0     /* Reasonable? *//* XXX */
 
-/* Following declaration concerns the MPLS-TE and LINk-TE management */
-typedef enum _opcode_t {
-       REORIGINATE_THIS_LSA,
-       REFRESH_THIS_LSA,
-       FLUSH_THIS_LSA
-} opcode_t;
-
-typedef enum _status_t { disabled, enabled } status_t;
-
 /* Mode for Inter-AS Opaque-LSA */
-enum inter_as_mode { Disable, AS, Area };
+enum inter_as_mode { Off, AS, Area };
 
 struct te_link_subtlv {
-       struct te_tlv_header header;
+       struct tlv_header header;
        union {
                u_int32_t link_type;
                struct in_addr link_id;
@@ -366,7 +337,7 @@ struct te_link_subtlv {
 /* Following structure are internal use only. */
 struct ospf_mpls_te {
        /* Status of MPLS-TE: enable or disbale */
-       status_t status;
+       bool enabled;
 
        /* RFC5392 */
        enum inter_as_mode inter_as;
@@ -437,8 +408,7 @@ extern int ospf_mpls_te_init(void);
 extern void ospf_mpls_te_term(void);
 extern struct ospf_mpls_te *get_ospf_mpls_te(void);
 extern void ospf_mpls_te_update_if(struct interface *);
-extern void ospf_mpls_te_lsa_schedule(struct mpls_te_link *, opcode_t);
-extern u_int32_t get_mpls_te_instance_value(void);
+extern void ospf_mpls_te_lsa_schedule(struct mpls_te_link *, enum lsa_opcode);
 extern void set_linkparams_llri(struct mpls_te_link *, u_int32_t, u_int32_t);
 extern void set_linkparams_lrrid(struct mpls_te_link *, struct in_addr,
                                 struct in_addr);
index a8bfb669af423e3a4a4da2d912fd018fb456375a..13d4780db3b7ec4e205d4f9cc2e5ce4283637bf9 100644 (file)
@@ -135,6 +135,7 @@ DEFUN_NOSH (router_ospf,
 {
        struct ospf *ospf;
        u_short instance = 0;
+       int ret = CMD_SUCCESS;
 
        ospf = ospf_lookup();
        if (!ospf) {
@@ -147,9 +148,10 @@ DEFUN_NOSH (router_ospf,
 
        /* The following logic to set the vty qobj index is in place to be able
           to ignore the commands which dont belong to this instance. */
-       if (ospf->instance != instance)
+       if (ospf->instance != instance) {
                VTY_PUSH_CONTEXT_NULL(OSPF_NODE);
-       else {
+               ret = CMD_NOT_MY_INSTANCE;
+       } else {
                if (IS_DEBUG_OSPF_EVENT)
                        zlog_debug("Config command 'router ospf %d' received",
                                   instance);
@@ -158,7 +160,7 @@ DEFUN_NOSH (router_ospf,
                ospf_router_id_update(ospf);
        }
 
-       return CMD_SUCCESS;
+       return ret;
 }
 
 DEFUN (no_router_ospf,
@@ -175,8 +177,9 @@ DEFUN (no_router_ospf,
        if (argc > 3)
                instance = strtoul(argv[3]->arg, NULL, 10);
 
-       if ((ospf = ospf_lookup_instance(instance)) == NULL)
-               return CMD_SUCCESS;
+       ospf = ospf_lookup_instance(instance);
+       if (ospf == NULL)
+               return CMD_NOT_MY_INSTANCE;
 
        ospf_finish(ospf);
 
@@ -191,7 +194,7 @@ DEFUN (ospf_router_id,
        "router-id for the OSPF process\n"
        "OSPF router-id in IP address format\n")
 {
-       VTY_DECLVAR_CONTEXT(ospf, ospf);
+       VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
        int idx_ipv4 = 2;
        struct listnode *node;
        struct ospf_area *area;
@@ -225,7 +228,7 @@ DEFUN_HIDDEN (ospf_router_id_old,
               "router-id for the OSPF process\n"
               "OSPF router-id in IP address format\n")
 {
-       VTY_DECLVAR_CONTEXT(ospf, ospf);
+       VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
        int idx_ipv4 = 1;
        struct listnode *node;
        struct ospf_area *area;
@@ -261,7 +264,7 @@ DEFUN (no_ospf_router_id,
        "router-id for the OSPF process\n"
        "OSPF router-id in IP address format\n")
 {
-       VTY_DECLVAR_CONTEXT(ospf, ospf);
+       VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
        struct listnode *node;
        struct ospf_area *area;
 
@@ -350,7 +353,7 @@ DEFUN (ospf_passive_interface,
        "IPv4 address\n"
        "Suppress routing updates on interfaces by default\n")
 {
-       VTY_DECLVAR_CONTEXT(ospf, ospf);
+       VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
        int idx_ipv4 = 2;
        struct interface *ifp;
        struct in_addr addr = {.s_addr = INADDR_ANY};
@@ -417,7 +420,7 @@ DEFUN (no_ospf_passive_interface,
        "IPv4 address\n"
        "Allow routing updates on interfaces by default\n")
 {
-       VTY_DECLVAR_CONTEXT(ospf, ospf);
+       VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
        int idx_ipv4 = 3;
        struct interface *ifp;
        struct in_addr addr = {.s_addr = INADDR_ANY};
@@ -478,7 +481,7 @@ DEFUN (ospf_network_area,
        "OSPF area ID in IP address format\n"
        "OSPF area ID as a decimal value\n")
 {
-       VTY_DECLVAR_CONTEXT(ospf, ospf);
+       VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
        int idx_ipv4_prefixlen = 1;
        int idx_ipv4_number = 3;
        struct prefix_ipv4 p;
@@ -520,7 +523,7 @@ DEFUN (no_ospf_network_area,
        "OSPF area ID in IP address format\n"
        "OSPF area ID as a decimal value\n")
 {
-       VTY_DECLVAR_CONTEXT(ospf, ospf);
+       VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
        int idx_ipv4_prefixlen = 2;
        int idx_ipv4_number = 4;
        struct prefix_ipv4 p;
@@ -559,7 +562,7 @@ DEFUN (ospf_area_range,
        "User specified metric for this range\n"
        "Advertised metric for this range\n")
 {
-       VTY_DECLVAR_CONTEXT(ospf, ospf);
+       VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
        int idx_ipv4_number = 1;
        int idx_ipv4_prefixlen = 3;
        int idx_cost = 6;
@@ -591,7 +594,7 @@ DEFUN (ospf_area_range_cost,
        "User specified metric for this range\n"
        "Advertised metric for this range\n")
 {
-       VTY_DECLVAR_CONTEXT(ospf, ospf);
+       VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
        int idx_ipv4_number = 1;
        int idx_ipv4_prefixlen = 3;
        int idx_cost = 5;
@@ -623,7 +626,7 @@ DEFUN (ospf_area_range_not_advertise,
        "Area range prefix\n"
        "DoNotAdvertise this range\n")
 {
-       VTY_DECLVAR_CONTEXT(ospf, ospf);
+       VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
        int idx_ipv4_number = 1;
        int idx_ipv4_prefixlen = 3;
        struct prefix_ipv4 p;
@@ -656,7 +659,7 @@ DEFUN (no_ospf_area_range,
        "Advertised metric for this range\n"
        "DoNotAdvertise this range\n")
 {
-       VTY_DECLVAR_CONTEXT(ospf, ospf);
+       VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
        int idx_ipv4_number = 2;
        int idx_ipv4_prefixlen = 4;
        struct prefix_ipv4 p;
@@ -682,7 +685,7 @@ DEFUN (ospf_area_range_substitute,
        "Announce area range as another prefix\n"
        "Network prefix to be announced instead of range\n")
 {
-       VTY_DECLVAR_CONTEXT(ospf, ospf);
+       VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
        int idx_ipv4_number = 1;
        int idx_ipv4_prefixlen = 3;
        int idx_ipv4_prefixlen_2 = 5;
@@ -713,7 +716,7 @@ DEFUN (no_ospf_area_range_substitute,
        "Announce area range as another prefix\n"
        "Network prefix to be announced instead of range\n")
 {
-       VTY_DECLVAR_CONTEXT(ospf, ospf);
+       VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
        int idx_ipv4_number = 2;
        int idx_ipv4_prefixlen = 4;
        int idx_ipv4_prefixlen_2 = 6;
@@ -981,7 +984,7 @@ DEFUN (ospf_area_vlink,
        "Use MD5 algorithm\n" \
        "The OSPF password (key)")
 {
-       VTY_DECLVAR_CONTEXT(ospf, ospf);
+       VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
        int idx_ipv4_number = 1;
        int idx_ipv4 = 3;
        struct ospf_vl_config_data vl_config;
@@ -1105,7 +1108,7 @@ DEFUN (no_ospf_area_vlink,
        "Use MD5 algorithm\n" \
        "The OSPF password (key)")
 {
-       VTY_DECLVAR_CONTEXT(ospf, ospf);
+       VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
        int idx_ipv4_number = 2;
        int idx_ipv4 = 4;
        struct ospf_area *area;
@@ -1204,7 +1207,7 @@ DEFUN (ospf_area_vlink_intervals,
        VLINK_HELPSTR_IPADDR
        VLINK_HELPSTR_TIME_PARAM)
 {
-       VTY_DECLVAR_CONTEXT(ospf, ospf);
+       VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
        struct ospf_vl_config_data vl_config;
        int ret = 0;
 
@@ -1251,7 +1254,7 @@ DEFUN (no_ospf_area_vlink_intervals,
        VLINK_HELPSTR_IPADDR
        VLINK_HELPSTR_TIME_PARAM)
 {
-       VTY_DECLVAR_CONTEXT(ospf, ospf);
+       VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
        struct ospf_vl_config_data vl_config;
        int ret = 0;
 
@@ -1300,7 +1303,7 @@ DEFUN (ospf_area_shortcut,
        "Enable shortcutting through the area\n"
        "Disable shortcutting through the area\n")
 {
-       VTY_DECLVAR_CONTEXT(ospf, ospf);
+       VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
        int idx_ipv4_number = 1;
        int idx_enable_disable = 3;
        struct ospf_area *area;
@@ -1344,7 +1347,7 @@ DEFUN (no_ospf_area_shortcut,
        "Deconfigure enabled shortcutting through the area\n"
        "Deconfigure disabled shortcutting through the area\n")
 {
-       VTY_DECLVAR_CONTEXT(ospf, ospf);
+       VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
        int idx_ipv4_number = 2;
        struct ospf_area *area;
        struct in_addr area_id;
@@ -1371,7 +1374,7 @@ DEFUN (ospf_area_stub,
        "OSPF area ID as a decimal value\n"
        "Configure OSPF area as stub\n")
 {
-       VTY_DECLVAR_CONTEXT(ospf, ospf);
+       VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
        int idx_ipv4_number = 1;
        struct in_addr area_id;
        int ret, format;
@@ -1402,7 +1405,7 @@ DEFUN (ospf_area_stub_no_summary,
        "Configure OSPF area as stub\n"
        "Do not inject inter-area routes into stub\n")
 {
-       VTY_DECLVAR_CONTEXT(ospf, ospf);
+       VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
        int idx_ipv4_number = 1;
        struct in_addr area_id;
        int ret, format;
@@ -1433,7 +1436,7 @@ DEFUN (no_ospf_area_stub,
        "OSPF area ID as a decimal value\n"
        "Configure OSPF area as stub\n")
 {
-       VTY_DECLVAR_CONTEXT(ospf, ospf);
+       VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
        int idx_ipv4_number = 2;
        struct in_addr area_id;
        int format;
@@ -1457,7 +1460,7 @@ DEFUN (no_ospf_area_stub_no_summary,
        "Configure OSPF area as stub\n"
        "Do not inject inter-area routes into area\n")
 {
-       VTY_DECLVAR_CONTEXT(ospf, ospf);
+       VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
        int idx_ipv4_number = 2;
        struct in_addr area_id;
        int format;
@@ -1472,7 +1475,7 @@ DEFUN (no_ospf_area_stub_no_summary,
 static int ospf_area_nssa_cmd_handler(struct vty *vty, int argc,
                                      struct cmd_token **argv, int nosum)
 {
-       VTY_DECLVAR_CONTEXT(ospf, ospf);
+       VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
        struct in_addr area_id;
        int ret, format;
 
@@ -1577,7 +1580,7 @@ DEFUN (no_ospf_area_nssa,
        "Configure NSSA-ABR to always translate\n"
        "Do not inject inter-area routes into nssa\n")
 {
-       VTY_DECLVAR_CONTEXT(ospf, ospf);
+       VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
        int idx_ipv4_number = 2;
        struct in_addr area_id;
        int format;
@@ -1603,7 +1606,7 @@ DEFUN (ospf_area_default_cost,
        "Set the summary-default cost of a NSSA or stub area\n"
        "Stub's advertised default summary cost\n")
 {
-       VTY_DECLVAR_CONTEXT(ospf, ospf);
+       VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
        int idx_ipv4_number = 1;
        int idx_number = 3;
        struct ospf_area *area;
@@ -1649,7 +1652,7 @@ DEFUN (no_ospf_area_default_cost,
        "Set the summary-default cost of a NSSA or stub area\n"
        "Stub's advertised default summary cost\n")
 {
-       VTY_DECLVAR_CONTEXT(ospf, ospf);
+       VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
        int idx_ipv4_number = 2;
        struct ospf_area *area;
        struct in_addr area_id;
@@ -1695,7 +1698,7 @@ DEFUN (ospf_area_export_list,
        "Set the filter for networks announced to other areas\n"
        "Name of the access-list\n")
 {
-       VTY_DECLVAR_CONTEXT(ospf, ospf);
+       VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
        int idx_ipv4_number = 1;
        struct ospf_area *area;
        struct in_addr area_id;
@@ -1720,7 +1723,7 @@ DEFUN (no_ospf_area_export_list,
        "Unset the filter for networks announced to other areas\n"
        "Name of the access-list\n")
 {
-       VTY_DECLVAR_CONTEXT(ospf, ospf);
+       VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
        int idx_ipv4_number = 2;
        struct ospf_area *area;
        struct in_addr area_id;
@@ -1747,7 +1750,7 @@ DEFUN (ospf_area_import_list,
        "Set the filter for networks from other areas announced to the specified one\n"
        "Name of the access-list\n")
 {
-       VTY_DECLVAR_CONTEXT(ospf, ospf);
+       VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
        int idx_ipv4_number = 1;
        struct ospf_area *area;
        struct in_addr area_id;
@@ -1772,7 +1775,7 @@ DEFUN (no_ospf_area_import_list,
        "Unset the filter for networks announced to other areas\n"
        "Name of the access-list\n")
 {
-       VTY_DECLVAR_CONTEXT(ospf, ospf);
+       VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
        int idx_ipv4_number = 2;
        struct ospf_area *area;
        struct in_addr area_id;
@@ -1801,7 +1804,7 @@ DEFUN (ospf_area_filter_list,
        "Filter networks sent to this area\n"
        "Filter networks sent from this area\n")
 {
-       VTY_DECLVAR_CONTEXT(ospf, ospf);
+       VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
        int idx_ipv4_number = 1;
        int idx_word = 4;
        int idx_in_out = 5;
@@ -1847,7 +1850,7 @@ DEFUN (no_ospf_area_filter_list,
        "Filter networks sent to this area\n"
        "Filter networks sent from this area\n")
 {
-       VTY_DECLVAR_CONTEXT(ospf, ospf);
+       VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
        int idx_ipv4_number = 2;
        int idx_word = 5;
        int idx_in_out = 6;
@@ -1901,7 +1904,7 @@ DEFUN (ospf_area_authentication_message_digest,
        "Enable authentication\n"
        "Use message-digest authentication\n")
 {
-       VTY_DECLVAR_CONTEXT(ospf, ospf);
+       VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
        int idx_ipv4_number = 1;
        struct ospf_area *area;
        struct in_addr area_id;
@@ -1924,7 +1927,7 @@ DEFUN (ospf_area_authentication,
        "OSPF area ID as a decimal value\n"
        "Enable authentication\n")
 {
-       VTY_DECLVAR_CONTEXT(ospf, ospf);
+       VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
        int idx_ipv4_number = 1;
        struct ospf_area *area;
        struct in_addr area_id;
@@ -1948,7 +1951,7 @@ DEFUN (no_ospf_area_authentication,
        "OSPF area ID as a decimal value\n"
        "Enable authentication\n")
 {
-       VTY_DECLVAR_CONTEXT(ospf, ospf);
+       VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
        int idx_ipv4_number = 2;
        struct ospf_area *area;
        struct in_addr area_id;
@@ -1978,7 +1981,7 @@ DEFUN (ospf_abr_type,
        "Shortcut ABR\n"
        "Standard behavior (RFC2328)\n")
 {
-       VTY_DECLVAR_CONTEXT(ospf, ospf);
+       VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
        int idx_vendor = 2;
        u_char abr_type = OSPF_ABR_UNKNOWN;
 
@@ -2013,7 +2016,7 @@ DEFUN (no_ospf_abr_type,
        "Shortcut ABR\n"
        "Standard ABR\n")
 {
-       VTY_DECLVAR_CONTEXT(ospf, ospf);
+       VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
        int idx_vendor = 3;
        u_char abr_type = OSPF_ABR_UNKNOWN;
 
@@ -2042,7 +2045,7 @@ DEFUN (ospf_log_adjacency_changes,
        "log-adjacency-changes",
        "Log changes in adjacency state\n")
 {
-       VTY_DECLVAR_CONTEXT(ospf, ospf);
+       VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
 
        SET_FLAG(ospf->config, OSPF_LOG_ADJACENCY_CHANGES);
        UNSET_FLAG(ospf->config, OSPF_LOG_ADJACENCY_DETAIL);
@@ -2055,7 +2058,7 @@ DEFUN (ospf_log_adjacency_changes_detail,
        "Log changes in adjacency state\n"
        "Log all state changes\n")
 {
-       VTY_DECLVAR_CONTEXT(ospf, ospf);
+       VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
 
        SET_FLAG(ospf->config, OSPF_LOG_ADJACENCY_CHANGES);
        SET_FLAG(ospf->config, OSPF_LOG_ADJACENCY_DETAIL);
@@ -2068,7 +2071,7 @@ DEFUN (no_ospf_log_adjacency_changes,
        NO_STR
        "Log changes in adjacency state\n")
 {
-       VTY_DECLVAR_CONTEXT(ospf, ospf);
+       VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
 
        UNSET_FLAG(ospf->config, OSPF_LOG_ADJACENCY_DETAIL);
        UNSET_FLAG(ospf->config, OSPF_LOG_ADJACENCY_CHANGES);
@@ -2082,7 +2085,7 @@ DEFUN (no_ospf_log_adjacency_changes_detail,
        "Log changes in adjacency state\n"
        "Log all state changes\n")
 {
-       VTY_DECLVAR_CONTEXT(ospf, ospf);
+       VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
 
        UNSET_FLAG(ospf->config, OSPF_LOG_ADJACENCY_DETAIL);
        return CMD_SUCCESS;
@@ -2094,7 +2097,7 @@ DEFUN (ospf_compatible_rfc1583,
        "OSPF compatibility list\n"
        "compatible with RFC 1583\n")
 {
-       VTY_DECLVAR_CONTEXT(ospf, ospf);
+       VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
 
        if (!CHECK_FLAG(ospf->config, OSPF_RFC1583_COMPATIBLE)) {
                SET_FLAG(ospf->config, OSPF_RFC1583_COMPATIBLE);
@@ -2110,7 +2113,7 @@ DEFUN (no_ospf_compatible_rfc1583,
        "OSPF compatibility list\n"
        "compatible with RFC 1583\n")
 {
-       VTY_DECLVAR_CONTEXT(ospf, ospf);
+       VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
 
        if (CHECK_FLAG(ospf->config, OSPF_RFC1583_COMPATIBLE)) {
                UNSET_FLAG(ospf->config, OSPF_RFC1583_COMPATIBLE);
@@ -2132,7 +2135,7 @@ ALIAS(no_ospf_compatible_rfc1583, no_ospf_rfc1583_flag_cmd,
 static int ospf_timers_spf_set(struct vty *vty, unsigned int delay,
                               unsigned int hold, unsigned int max)
 {
-       VTY_DECLVAR_CONTEXT(ospf, ospf);
+       VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
 
        ospf->spf_delay = delay;
        ospf->spf_holdtime = hold;
@@ -2150,7 +2153,7 @@ DEFUN (ospf_timers_min_ls_interval,
        "All LSA types\n"
        "Delay (msec) between sending LSAs\n")
 {
-       VTY_DECLVAR_CONTEXT(ospf, ospf);
+       VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
        int idx_number = 4;
        unsigned int interval;
 
@@ -2176,54 +2179,12 @@ DEFUN (no_ospf_timers_min_ls_interval,
        "All LSA types\n"
        "Delay (msec) between sending LSAs\n")
 {
-       VTY_DECLVAR_CONTEXT(ospf, ospf);
+       VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
        ospf->min_ls_interval = OSPF_MIN_LS_INTERVAL;
 
        return CMD_SUCCESS;
 }
 
-
-DEFUN (ospf_timers_min_ls_arrival,
-       ospf_timers_min_ls_arrival_cmd,
-       "timers lsa arrival (0-1000)",
-       "Adjust routing timers\n"
-       "Throttling link state advertisement delays\n"
-       "OSPF minimum arrival interval delay\n"
-       "Delay (msec) between accepted LSAs\n")
-{
-       VTY_DECLVAR_CONTEXT(ospf, ospf);
-       int idx_number = 3;
-       unsigned int arrival;
-
-       if (argc < 4) {
-               vty_out(vty, "Insufficient arguments\n");
-               return CMD_WARNING_CONFIG_FAILED;
-       }
-
-       arrival = strtoul(argv[idx_number]->arg, NULL, 10);
-
-       ospf->min_ls_arrival = arrival;
-
-       return CMD_SUCCESS;
-}
-
-DEFUN (no_ospf_timers_min_ls_arrival,
-       no_ospf_timers_min_ls_arrival_cmd,
-       "no timers lsa arrival [(0-1000)]",
-       NO_STR
-       "Adjust routing timers\n"
-       "Throttling link state advertisement delays\n"
-       "OSPF minimum arrival interval delay\n"
-       "Delay (msec) between accepted LSAs\n")
-{
-       VTY_DECLVAR_CONTEXT(ospf, ospf);
-
-       ospf->min_ls_arrival = OSPF_MIN_LS_ARRIVAL;
-
-       return CMD_SUCCESS;
-}
-
-
 DEFUN (ospf_timers_throttle_spf,
        ospf_timers_throttle_spf_cmd,
        "timers throttle spf (0-600000) (0-600000) (0-600000)",
@@ -2268,32 +2229,21 @@ DEFUN (no_ospf_timers_throttle_spf,
 }
 
 
-DEFUN (ospf_timers_lsa,
-       ospf_timers_lsa_cmd,
+DEFUN (ospf_timers_lsa_min_arrival,
+       ospf_timers_lsa_min_arrival_cmd,
        "timers lsa min-arrival (0-600000)",
        "Adjust routing timers\n"
        "OSPF LSA timers\n"
        "Minimum delay in receiving new version of a LSA\n"
        "Delay in milliseconds\n")
 {
-       VTY_DECLVAR_CONTEXT(ospf, ospf);
-       int idx_number = 3;
-       unsigned int minarrival;
-
-       if (argc < 4) {
-               vty_out(vty, "Insufficient number of arguments\n");
-               return CMD_WARNING_CONFIG_FAILED;
-       }
-
-       minarrival = strtoul(argv[idx_number]->arg, NULL, 10);
-
-       ospf->min_ls_arrival = minarrival;
-
+       VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
+       ospf->min_ls_arrival = strtoul(argv[argc - 1]->arg, NULL, 10);
        return CMD_SUCCESS;
 }
 
-DEFUN (no_ospf_timers_lsa,
-       no_ospf_timers_lsa_cmd,
+DEFUN (no_ospf_timers_lsa_min_arrival,
+       no_ospf_timers_lsa_min_arrival_cmd,
        "no timers lsa min-arrival [(0-600000)]",
        NO_STR
        "Adjust routing timers\n"
@@ -2301,11 +2251,11 @@ DEFUN (no_ospf_timers_lsa,
        "Minimum delay in receiving new version of a LSA\n"
        "Delay in milliseconds\n")
 {
-       VTY_DECLVAR_CONTEXT(ospf, ospf);
+       VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
        unsigned int minarrival;
 
        if (argc > 4) {
-               minarrival = strtoul(argv[4]->arg, NULL, 10);
+               minarrival = strtoul(argv[argc - 1]->arg, NULL, 10);
 
                if (ospf->min_ls_arrival != minarrival
                    || minarrival == OSPF_MIN_LS_ARRIVAL)
@@ -2317,6 +2267,26 @@ DEFUN (no_ospf_timers_lsa,
        return CMD_SUCCESS;
 }
 
+/* Deprecated: 08/07/2017 */
+ALIAS_HIDDEN (ospf_timers_lsa_min_arrival,
+              ospf_timers_lsa_arrival_cmd,
+              "timers lsa arrival (0-1000)",
+              "adjust routing timers\n"
+              "throttling link state advertisement delays\n"
+              "ospf minimum arrival interval delay\n"
+              "delay (msec) between accepted lsas\n");
+
+/* Deprecated: 08/07/2017 */
+ALIAS_HIDDEN (no_ospf_timers_lsa_min_arrival,
+              no_ospf_timers_lsa_arrival_cmd,
+              "no timers lsa arrival (0-1000)",
+              NO_STR
+              "adjust routing timers\n"
+              "throttling link state advertisement delays\n"
+              "ospf minimum arrival interval delay\n"
+              "delay (msec) between accepted lsas\n");
+
+
 DEFUN (ospf_neighbor,
        ospf_neighbor_cmd,
        "neighbor A.B.C.D [priority (0-255) [poll-interval (1-65535)]]",
@@ -2327,7 +2297,7 @@ DEFUN (ospf_neighbor,
        "Dead Neighbor Polling interval\n"
        "Seconds\n")
 {
-       VTY_DECLVAR_CONTEXT(ospf, ospf);
+       VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
        int idx_ipv4 = 1;
        int idx_pri = 3;
        int idx_poll = 5;
@@ -2364,7 +2334,7 @@ DEFUN (ospf_neighbor_poll_interval,
        "OSPF priority of non-broadcast neighbor\n"
        "Priority\n")
 {
-       VTY_DECLVAR_CONTEXT(ospf, ospf);
+       VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
        int idx_ipv4 = 1;
        int idx_poll = 3;
        int idx_pri = 5;
@@ -2399,7 +2369,7 @@ DEFUN (no_ospf_neighbor,
        "Dead Neighbor Polling interval\n"
        "Seconds\n")
 {
-       VTY_DECLVAR_CONTEXT(ospf, ospf);
+       VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
        int idx_ipv4 = 2;
        struct in_addr nbr_addr;
 
@@ -2421,7 +2391,7 @@ DEFUN (no_ospf_neighbor_poll,
        "Neighbor Priority\n"
        "Priority\n")
 {
-       VTY_DECLVAR_CONTEXT(ospf, ospf);
+       VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
        int idx_ipv4 = 2;
        struct in_addr nbr_addr;
 
@@ -2439,7 +2409,7 @@ DEFUN (ospf_refresh_timer,
        "Set refresh timer\n"
        "Timer value in seconds\n")
 {
-       VTY_DECLVAR_CONTEXT(ospf, ospf);
+       VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
        int idx_number = 2;
        unsigned int interval;
 
@@ -2460,7 +2430,7 @@ DEFUN (no_ospf_refresh_timer,
        "Unset refresh timer\n"
        "Timer value in seconds\n")
 {
-       VTY_DECLVAR_CONTEXT(ospf, ospf);
+       VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
        int idx_number = 3;
        unsigned int interval;
 
@@ -2485,7 +2455,7 @@ DEFUN (ospf_auto_cost_reference_bandwidth,
        "Use reference bandwidth method to assign OSPF cost\n"
        "The reference bandwidth in terms of Mbits per second\n")
 {
-       VTY_DECLVAR_CONTEXT(ospf, ospf);
+       VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
        int idx_number = 2;
        u_int32_t refbw;
        struct listnode *node;
@@ -2516,7 +2486,7 @@ DEFUN (no_ospf_auto_cost_reference_bandwidth,
        "Use reference bandwidth method to assign OSPF cost\n"
        "The reference bandwidth in terms of Mbits per second\n")
 {
-       VTY_DECLVAR_CONTEXT(ospf, ospf);
+       VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
        struct listnode *node, *nnode;
        struct interface *ifp;
 
@@ -2541,7 +2511,7 @@ DEFUN (ospf_write_multiplier,
        "Write multiplier\n"
        "Maximum number of interface serviced per write\n")
 {
-       VTY_DECLVAR_CONTEXT(ospf, ospf);
+       VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
        int idx_number;
        u_int32_t write_oi_count;
 
@@ -2572,7 +2542,7 @@ DEFUN (no_ospf_write_multiplier,
        "Write multiplier\n"
        "Maximum number of interface serviced per write\n")
 {
-       VTY_DECLVAR_CONTEXT(ospf, ospf);
+       VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
 
        ospf->write_oi_count = OSPF_WRITE_INTERFACE_COUNT_DEFAULT;
        return CMD_SUCCESS;
@@ -3218,8 +3188,11 @@ DEFUN (show_ip_ospf_instance,
        u_char uj = use_json(argc, argv);
 
        instance = strtoul(argv[idx_number]->arg, NULL, 10);
-       if ((ospf = ospf_lookup_instance(instance)) == NULL
-           || !ospf->oi_running)
+       ospf = ospf_lookup_instance(instance);
+       if (ospf == NULL)
+               return CMD_NOT_MY_INSTANCE;
+
+       if (!ospf->oi_running)
                return CMD_SUCCESS;
 
        return (show_ip_ospf_common(vty, ospf, uj));
@@ -3654,8 +3627,11 @@ DEFUN (show_ip_ospf_instance_interface,
        u_char uj = use_json(argc, argv);
 
        instance = strtoul(argv[idx_number]->arg, NULL, 10);
-       if ((ospf = ospf_lookup_instance(instance)) == NULL
-           || !ospf->oi_running)
+       ospf = ospf_lookup_instance(instance);
+       if (ospf == NULL)
+               return CMD_NOT_MY_INSTANCE;
+
+       if (!ospf->oi_running)
                return CMD_SUCCESS;
 
        if (uj)
@@ -3861,8 +3837,11 @@ DEFUN (show_ip_ospf_instance_neighbor,
        u_char uj = use_json(argc, argv);
 
        instance = strtoul(argv[idx_number]->arg, NULL, 10);
-       if ((ospf = ospf_lookup_instance(instance)) == NULL
-           || !ospf->oi_running)
+       ospf = ospf_lookup_instance(instance);
+       if (ospf == NULL)
+               return CMD_NOT_MY_INSTANCE;
+
+       if (!ospf->oi_running)
                return CMD_SUCCESS;
 
        return show_ip_ospf_neighbor_common(vty, ospf, uj);
@@ -3982,8 +3961,11 @@ DEFUN (show_ip_ospf_instance_neighbor_all,
        u_char uj = use_json(argc, argv);
 
        instance = strtoul(argv[idx_number]->arg, NULL, 10);
-       if ((ospf = ospf_lookup_instance(instance)) == NULL
-           || !ospf->oi_running)
+       ospf = ospf_lookup_instance(instance);
+       if (ospf == NULL)
+               return CMD_NOT_MY_INSTANCE;
+
+       if (!ospf->oi_running)
                return CMD_SUCCESS;
 
        return show_ip_ospf_neighbor_all_common(vty, ospf, uj);
@@ -4075,8 +4057,11 @@ DEFUN (show_ip_ospf_instance_neighbor_int,
        u_char uj = use_json(argc, argv);
 
        instance = strtoul(argv[idx_number]->arg, NULL, 10);
-       if ((ospf = ospf_lookup_instance(instance)) == NULL
-           || !ospf->oi_running)
+       ospf = ospf_lookup_instance(instance);
+       if (ospf == NULL)
+               return CMD_NOT_MY_INSTANCE;
+
+       if (!ospf->oi_running)
                return CMD_SUCCESS;
 
        return show_ip_ospf_neighbor_int_common(vty, ospf, 1, argv, uj);
@@ -4462,8 +4447,11 @@ DEFUN (show_ip_ospf_instance_neighbor_id,
        u_char uj = use_json(argc, argv);
 
        instance = strtoul(argv[idx_number]->arg, NULL, 10);
-       if ((ospf = ospf_lookup_instance(instance)) == NULL
-           || !ospf->oi_running)
+       ospf = ospf_lookup_instance(instance);
+       if (ospf == NULL)
+               return CMD_NOT_MY_INSTANCE;
+
+       if (!ospf->oi_running)
                return CMD_SUCCESS;
 
        return show_ip_ospf_neighbor_id_common(vty, ospf, 1, argv, uj);
@@ -4551,8 +4539,11 @@ DEFUN (show_ip_ospf_instance_neighbor_detail,
        u_char uj = use_json(argc, argv);
 
        instance = strtoul(argv[idx_number]->arg, NULL, 10);
-       if ((ospf = ospf_lookup_instance(instance)) == NULL
-           || !ospf->oi_running)
+       ospf = ospf_lookup_instance(instance);
+       if (ospf == NULL)
+               return CMD_NOT_MY_INSTANCE;
+
+       if (!ospf->oi_running)
                return CMD_SUCCESS;
 
        return show_ip_ospf_neighbor_detail_common(vty, ospf, uj);
@@ -4652,8 +4643,11 @@ DEFUN (show_ip_ospf_instance_neighbor_detail_all,
        u_char uj = use_json(argc, argv);
 
        instance = strtoul(argv[idx_number]->arg, NULL, 10);
-       if ((ospf = ospf_lookup_instance(instance)) == NULL
-           || !ospf->oi_running)
+       ospf = ospf_lookup_instance(instance);
+       if (ospf == NULL)
+               return CMD_NOT_MY_INSTANCE;
+
+       if (!ospf->oi_running)
                return CMD_SUCCESS;
 
        return show_ip_ospf_neighbor_detail_all_common(vty, ospf, uj);
@@ -4757,8 +4751,11 @@ DEFUN (show_ip_ospf_instance_neighbor_int_detail,
        u_char uj = use_json(argc, argv);
 
        instance = strtoul(argv[idx_number]->arg, NULL, 10);
-       if ((ospf = ospf_lookup_instance(instance)) == NULL
-           || !ospf->oi_running)
+       ospf = ospf_lookup_instance(instance);
+       if (ospf == NULL)
+               return CMD_NOT_MY_INSTANCE;
+
+       if (!ospf->oi_running)
                return CMD_SUCCESS;
 
        return show_ip_ospf_neighbor_int_detail_common(vty, ospf, 1, argv, uj);
@@ -5446,6 +5443,8 @@ DEFUN (show_ip_ospf_instance_database,
        if (argv_find(argv, argc, "(1-65535)", &idx)) {
                instance = strtoul(argv[idx]->arg, NULL, 10);
                ospf = ospf_lookup_instance(instance);
+               if (ospf == NULL)
+                       return CMD_NOT_MY_INSTANCE;
        } else {
                ospf = ospf_lookup();
        }
@@ -5474,8 +5473,11 @@ DEFUN (show_ip_ospf_instance_database_max,
 
        instance = strtoul(argv[idx_number]->arg, NULL, 10);
 
-       if ((ospf = ospf_lookup_instance(instance)) == NULL
-           || !ospf->oi_running)
+       ospf = ospf_lookup_instance(instance);
+       if (ospf == NULL)
+               return CMD_NOT_MY_INSTANCE;
+
+       if (!ospf->oi_running)
                return CMD_SUCCESS;
 
        return (show_ip_ospf_database_common(vty, ospf, 1, argc, argv));
@@ -5553,6 +5555,8 @@ DEFUN (show_ip_ospf_instance_database_type_adv_router,
        if (argv_find(argv, argc, "(1-65535)", &idx)) {
                instance = strtoul(argv[idx]->arg, NULL, 10);
                ospf = ospf_lookup_instance(instance);
+               if (ospf == NULL)
+                       return CMD_NOT_MY_INSTANCE;
        } else
                ospf = ospf_lookup();
 
@@ -6922,7 +6926,7 @@ DEFUN (ip_ospf_area,
                        ospf = ospf_lookup();
                        ospf->if_ospf_cli_count--;
                }
-               return CMD_SUCCESS;
+               return CMD_NOT_MY_INSTANCE;
        }
 
        ret = str2area_id(areaid, &area_id, &format);
@@ -6995,8 +6999,9 @@ DEFUN (no_ip_ospf_area,
        if (argv_find(argv, argc, "(1-65535)", &idx))
                instance = strtol(argv[idx]->arg, NULL, 10);
 
-       if ((ospf = ospf_lookup_instance(instance)) == NULL)
-               return CMD_SUCCESS;
+       ospf = ospf_lookup_instance(instance);
+       if (ospf == NULL)
+               return CMD_NOT_MY_INSTANCE;
 
        argv_find(argv, argc, "area", &idx);
 
@@ -7038,7 +7043,7 @@ DEFUN (ospf_redistribute_source,
        "Route map reference\n"
        "Pointer to route-map entries\n")
 {
-       VTY_DECLVAR_CONTEXT(ospf, ospf);
+       VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
        int idx_protocol = 1;
        int source;
        int type = -1;
@@ -7088,7 +7093,7 @@ DEFUN (no_ospf_redistribute_source,
        "Route map reference\n"
        "Pointer to route-map entries\n")
 {
-       VTY_DECLVAR_CONTEXT(ospf, ospf);
+       VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
        int idx_protocol = 2;
        int source;
        struct ospf_redist *red;
@@ -7119,7 +7124,7 @@ DEFUN (ospf_redistribute_instance_source,
        "Route map reference\n"
        "Pointer to route-map entries\n")
 {
-       VTY_DECLVAR_CONTEXT(ospf, ospf);
+       VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
        int idx_ospf_table = 1;
        int idx_number = 2;
        int idx = 3;
@@ -7187,7 +7192,7 @@ DEFUN (no_ospf_redistribute_instance_source,
        "Route map reference\n"
        "Pointer to route-map entries\n")
 {
-       VTY_DECLVAR_CONTEXT(ospf, ospf);
+       VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
        int idx_ospf_table = 2;
        int idx_number = 3;
        u_int instance;
@@ -7228,7 +7233,7 @@ DEFUN (ospf_distribute_list_out,
        OUT_STR
        FRR_REDIST_HELP_STR_OSPFD)
 {
-       VTY_DECLVAR_CONTEXT(ospf, ospf);
+       VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
        int idx_word = 1;
        int source;
 
@@ -7251,7 +7256,7 @@ DEFUN (no_ospf_distribute_list_out,
        OUT_STR
        FRR_REDIST_HELP_STR_OSPFD)
 {
-       VTY_DECLVAR_CONTEXT(ospf, ospf);
+       VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
        int idx_word = 2;
        int source;
 
@@ -7278,7 +7283,7 @@ DEFUN (ospf_default_information_originate,
        "Route map reference\n"
        "Pointer to route-map entries\n")
 {
-       VTY_DECLVAR_CONTEXT(ospf, ospf);
+       VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
        int default_originate = DEFAULT_ORIGINATE_ZEBRA;
        int type = -1;
        int metric = -1;
@@ -7324,7 +7329,7 @@ DEFUN (no_ospf_default_information_originate,
        "Route map reference\n"
        "Pointer to route-map entries\n")
 {
-       VTY_DECLVAR_CONTEXT(ospf, ospf);
+       VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
        struct prefix_ipv4 p;
        struct ospf_external *ext;
        struct ospf_redist *red;
@@ -7355,7 +7360,7 @@ DEFUN (ospf_default_metric,
        "Set metric of redistributed routes\n"
        "Default metric\n")
 {
-       VTY_DECLVAR_CONTEXT(ospf, ospf);
+       VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
        int idx_number = 1;
        int metric = -1;
 
@@ -7374,7 +7379,7 @@ DEFUN (no_ospf_default_metric,
        "Set metric of redistributed routes\n"
        "Default metric\n")
 {
-       VTY_DECLVAR_CONTEXT(ospf, ospf);
+       VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
 
        ospf->default_metric = -1;
 
@@ -7388,7 +7393,7 @@ DEFUN (ospf_distance,
        "Administrative distance\n"
        "OSPF Administrative distance\n")
 {
-       VTY_DECLVAR_CONTEXT(ospf, ospf);
+       VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
        int idx_number = 1;
 
        ospf->distance_all = atoi(argv[idx_number]->arg);
@@ -7403,7 +7408,7 @@ DEFUN (no_ospf_distance,
        "Administrative distance\n"
        "OSPF Administrative distance\n")
 {
-       VTY_DECLVAR_CONTEXT(ospf, ospf);
+       VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
 
        ospf->distance_all = 0;
 
@@ -7423,7 +7428,7 @@ DEFUN (no_ospf_distance_ospf,
        "External routes\n"
        "Distance for external routes\n")
 {
-       VTY_DECLVAR_CONTEXT(ospf, ospf);
+       VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
        int idx = 0;
 
        if (!ospf)
@@ -7451,7 +7456,7 @@ DEFUN (ospf_distance_ospf,
        "External routes\n"
        "Distance for external routes\n")
 {
-       VTY_DECLVAR_CONTEXT(ospf, ospf);
+       VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
        int idx = 0;
 
        if (argv_find(argv, argc, "intra-area", &idx))
@@ -7636,7 +7641,7 @@ DEFUN (ospf_max_metric_router_lsa_admin,
        "Advertise own Router-LSA with infinite distance (stub router)\n"
        "Administratively applied, for an indefinite period\n")
 {
-       VTY_DECLVAR_CONTEXT(ospf, ospf);
+       VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
        struct listnode *ln;
        struct ospf_area *area;
 
@@ -7662,7 +7667,7 @@ DEFUN (no_ospf_max_metric_router_lsa_admin,
        "Advertise own Router-LSA with infinite distance (stub router)\n"
        "Administratively applied, for an indefinite period\n")
 {
-       VTY_DECLVAR_CONTEXT(ospf, ospf);
+       VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
        struct listnode *ln;
        struct ospf_area *area;
 
@@ -7691,7 +7696,7 @@ DEFUN (ospf_max_metric_router_lsa_startup,
        "Automatically advertise stub Router-LSA on startup of OSPF\n"
        "Time (seconds) to advertise self as stub-router\n")
 {
-       VTY_DECLVAR_CONTEXT(ospf, ospf);
+       VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
        int idx_number = 3;
        unsigned int seconds;
 
@@ -7716,7 +7721,7 @@ DEFUN (no_ospf_max_metric_router_lsa_startup,
        "Automatically advertise stub Router-LSA on startup of OSPF\n"
        "Time (seconds) to advertise self as stub-router\n")
 {
-       VTY_DECLVAR_CONTEXT(ospf, ospf);
+       VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
        struct listnode *ln;
        struct ospf_area *area;
 
@@ -7747,7 +7752,7 @@ DEFUN (ospf_max_metric_router_lsa_shutdown,
        "Advertise stub-router prior to full shutdown of OSPF\n"
        "Time (seconds) to wait till full shutdown\n")
 {
-       VTY_DECLVAR_CONTEXT(ospf, ospf);
+       VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
        int idx_number = 3;
        unsigned int seconds;
 
@@ -7772,7 +7777,7 @@ DEFUN (no_ospf_max_metric_router_lsa_shutdown,
        "Advertise stub-router prior to full shutdown of OSPF\n"
        "Time (seconds) to wait till full shutdown\n")
 {
-       VTY_DECLVAR_CONTEXT(ospf, ospf);
+       VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
 
        ospf->stub_router_shutdown_time = OSPF_STUB_ROUTER_UNCONFIGURED;
 
@@ -8034,8 +8039,11 @@ DEFUN (show_ip_ospf_instance_border_routers,
        u_short instance = 0;
 
        instance = strtoul(argv[idx_number]->arg, NULL, 10);
-       if ((ospf = ospf_lookup_instance(instance)) == NULL
-           || !ospf->oi_running)
+       ospf = ospf_lookup_instance(instance);
+       if (ospf == NULL)
+               return CMD_NOT_MY_INSTANCE;
+
+       if (!ospf->oi_running)
                return CMD_SUCCESS;
 
        return show_ip_ospf_border_routers_common(vty, ospf);
@@ -8095,8 +8103,11 @@ DEFUN (show_ip_ospf_instance_route,
        u_short instance = 0;
 
        instance = strtoul(argv[idx_number]->arg, NULL, 10);
-       if ((ospf = ospf_lookup_instance(instance)) == NULL
-           || !ospf->oi_running)
+       ospf = ospf_lookup_instance(instance);
+       if (ospf == NULL)
+               return CMD_NOT_MY_INSTANCE;
+
+       if (!ospf->oi_running)
                return CMD_SUCCESS;
 
        return show_ip_ospf_route_common(vty, ospf);
@@ -9141,10 +9152,10 @@ void ospf_vty_init(void)
        /* LSA timers commands */
        install_element(OSPF_NODE, &ospf_timers_min_ls_interval_cmd);
        install_element(OSPF_NODE, &no_ospf_timers_min_ls_interval_cmd);
-       install_element(OSPF_NODE, &ospf_timers_min_ls_arrival_cmd);
-       install_element(OSPF_NODE, &no_ospf_timers_min_ls_arrival_cmd);
-       install_element(OSPF_NODE, &ospf_timers_lsa_cmd);
-       install_element(OSPF_NODE, &no_ospf_timers_lsa_cmd);
+       install_element(OSPF_NODE, &ospf_timers_lsa_min_arrival_cmd);
+       install_element(OSPF_NODE, &no_ospf_timers_lsa_min_arrival_cmd);
+       install_element(OSPF_NODE, &ospf_timers_lsa_arrival_cmd);
+       install_element(OSPF_NODE, &no_ospf_timers_lsa_arrival_cmd);
 
        /* refresh timer commands */
        install_element(OSPF_NODE, &ospf_refresh_timer_cmd);
index c6b0955dab0003c63a05f840b3e1346de848832f..ec8f1ee8524e6057511bf3c3e36c05daa77ecdac 100644 (file)
@@ -51,6 +51,9 @@
 #include "ospfd/ospf_zebra.h"
 #include "ospfd/ospf_te.h"
 
+DEFINE_MTYPE_STATIC(OSPFD, OSPF_EXTERNAL, "OSPF External route table")
+DEFINE_MTYPE_STATIC(OSPFD, OSPF_REDISTRIBUTE, "OSPF Redistriute")
+
 DEFINE_HOOK(ospf_if_update, (struct interface * ifp), (ifp))
 DEFINE_HOOK(ospf_if_delete, (struct interface * ifp), (ifp))
 
@@ -628,7 +631,8 @@ struct ospf_external *ospf_external_add(u_char type, u_short instance)
                om->external[type] = list_new();
 
        ext_list = om->external[type];
-       ext = (struct ospf_external *)calloc(1, sizeof(struct ospf_external));
+       ext = (struct ospf_external *)XCALLOC(MTYPE_OSPF_EXTERNAL,
+                                             sizeof(struct ospf_external));
        ext->instance = instance;
        EXTERNAL_INFO(ext) = route_table_init();
 
@@ -652,6 +656,7 @@ void ospf_external_del(u_char type, u_short instance)
                        list_free(om->external[type]);
                        om->external[type] = NULL;
                }
+               XFREE(MTYPE_OSPF_EXTERNAL, ext);
        }
 }
 
@@ -687,7 +692,8 @@ struct ospf_redist *ospf_redist_add(struct ospf *ospf, u_char type,
                ospf->redist[type] = list_new();
 
        red_list = ospf->redist[type];
-       red = (struct ospf_redist *)calloc(1, sizeof(struct ospf_redist));
+       red = (struct ospf_redist *)XCALLOC(MTYPE_OSPF_REDISTRIBUTE,
+                                           sizeof(struct ospf_redist));
        red->instance = instance;
        red->dmetric.type = -1;
        red->dmetric.value = -1;
@@ -709,6 +715,7 @@ void ospf_redist_del(struct ospf *ospf, u_char type, u_short instance)
                        list_free(ospf->redist[type]);
                        ospf->redist[type] = NULL;
                }
+               XFREE(MTYPE_OSPF_REDISTRIBUTE, red);
        }
 }
 
index cee2244dd99f2c0579c4d78c1bbda5196352f7c6..b3553238efddda71881e56f2c333d06f6043de7a 100644 (file)
@@ -590,6 +590,7 @@ static void ospf_finish_final(struct ospf *ospf)
                        route_unlock_node(rn);
                }
        }
+       route_table_finish(ospf->networks);
 
        for (ALL_LIST_ELEMENTS(ospf->areas, node, nnode, area)) {
                listnode_delete(ospf->areas, area);
@@ -655,6 +656,8 @@ static void ospf_finish_final(struct ospf *ospf)
        }
 
        list_delete(ospf->areas);
+       list_delete(ospf->oi_write_q);
+       list_delete(ospf->oiflist);
 
        for (i = ZEBRA_ROUTE_SYSTEM; i <= ZEBRA_ROUTE_MAX; i++) {
                struct list *ext_list;
@@ -752,6 +755,7 @@ static void ospf_area_free(struct ospf_area *area)
        LSDB_LOOP(OPAQUE_LINK_LSDB(area), rn, lsa)
        ospf_discard_from_db(area->ospf, area->lsdb, lsa);
 
+       ospf_opaque_type10_lsa_term(area);
        ospf_lsdb_delete_all(area->lsdb);
        ospf_lsdb_free(area->lsdb);
 
@@ -976,9 +980,13 @@ int ospf_network_unset(struct ospf *ospf, struct prefix_ipv4 *p,
        rn->info = NULL;
        route_unlock_node(rn); /* initial reference */
 
-       /* Find interfaces that not configured already.  */
+       /* Find interfaces that are not configured already.  */
        for (ALL_LIST_ELEMENTS(ospf->oiflist, node, nnode, oi)) {
-               ospf_network_run_subnet(ospf, oi->connected, NULL, NULL);
+
+         if (oi->type == OSPF_IFTYPE_VIRTUALLINK)
+           continue;
+
+         ospf_network_run_subnet(ospf, oi->connected, NULL, NULL);
        }
 
        /* Update connected redistribute. */
index 4142f1a3e94cbbc5dd6b933543b84dd2b699cf27..b49bbdc17dfd33ae1a09acafa19c4953c0eb7ce6 100644 (file)
@@ -101,7 +101,7 @@ struct ospf_master {
 
        /* Various OSPF global configuration. */
        u_char options;
-#define OSPF_MASTER_SHUTDOWN (1 << 0) /* deferred-shutdown */  
+#define OSPF_MASTER_SHUTDOWN (1 << 0) /* deferred-shutdown */
 };
 
 struct ospf_redist {
index 0dd6c569dcb9d75098a6523a21a05db459572dc4..f440221d4274b6a44aba03168e68ebd6579f5162 100644 (file)
@@ -53,7 +53,8 @@ libpim_a_SOURCES = \
        pim_ssmpingd.c pim_int.c pim_rp.c \
        pim_static.c pim_br.c pim_register.c pim_routemap.c \
        pim_msdp.c pim_msdp_socket.c pim_msdp_packet.c \
-       pim_jp_agg.c pim_nht.c pim_ssm.c pim_bfd.c
+       pim_jp_agg.c pim_nht.c pim_ssm.c pim_bfd.c \
+       pim_instance.c
 
 noinst_HEADERS = \
        pim_memory.h \
@@ -66,7 +67,7 @@ noinst_HEADERS = \
        pim_igmp_join.h pim_ssmpingd.h pim_int.h pim_rp.h \
        pim_static.h pim_br.h pim_register.h \
        pim_msdp.h pim_msdp_socket.h pim_msdp_packet.h pim_nht.h \
-       pim_jp_agg.h pim_ssm.h pim_bfd.h
+       pim_jp_agg.h pim_ssm.h pim_bfd.h pim_instance.h
 
 pimd_SOURCES = \
        pim_main.c $(libpim_a_SOURCES)
diff --git a/pimd/WHY_SSM b/pimd/WHY_SSM
deleted file mode 100644 (file)
index 2e8c966..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-WHY SSM
-
-Benefis of PIM SSM over PIM SM
-------------------------------
-
-- SSM consumes minimum link bandwidth
-- SSM simplifies multicast address management (specially important for
-  inter-domain multicast)
-  - SSM (S,G) channels easily provide unique per-application addressing
-  - SSM does not require MSDP between PIM domains
-- SSM does not suffer instabilities from traffic-driven SPT switchover
-- SSM is not suscetible to DoS attack from unwanted sources
-- SSM does not use RP. Some RP issues:
-  - RP is possible point of failure
-  - RP demands redundancy management
-  - RP may require PIM dense mode support for RP election
-  - RP is possible performance bottleneck
-  - RP may demand lots of extra management
-- SSM can be deployed in an existing PIM SM network (only the last hop
-  routers need to support IGMPv3)
-- SSM is easier to deploy and maintain
-
-PIM-SSM drawbacks
------------------
-
-- SSM requires IGMPv3 support on both receivers and last-hop routers
-- SSM may be memory intensive when managing (S,G) states for
-  many-to-many multicast distribution
-- SSM will keep (S,G) state as long as there are subscriptions from
-  receivers, even if the source is not actually sending traffic
-
---EOF--
index f68c252a3563120ab00461f20ee847b4fcb46f9f..934fea5a9e1a9a038aae4f3ce5e2c3d453e5088e 100644 (file)
@@ -47,6 +47,7 @@ void pim_ifassert_winner_set(struct pim_ifchannel *ch,
                             struct in_addr winner,
                             struct pim_assert_metric winner_metric)
 {
+       struct pim_interface *pim_ifp = ch->interface->info;
        int winner_changed = (ch->ifassert_winner.s_addr != winner.s_addr);
        int metric_changed = !pim_assert_metric_match(
                &ch->ifassert_winner_metric, &winner_metric);
@@ -81,7 +82,7 @@ void pim_ifassert_winner_set(struct pim_ifchannel *ch,
        ch->ifassert_creation = pim_time_monotonic_sec();
 
        if (winner_changed || metric_changed) {
-               pim_upstream_update_join_desired(ch->upstream);
+               pim_upstream_update_join_desired(pim_ifp->pim, ch->upstream);
                pim_ifchannel_update_could_assert(ch);
                pim_ifchannel_update_assert_tracking_desired(ch);
        }
@@ -146,7 +147,7 @@ static int dispatch_assert(struct interface *ifp, struct in_addr source_addr,
        memset(&sg, 0, sizeof(struct prefix_sg));
        sg.src = source_addr;
        sg.grp = group_addr;
-       ch = pim_ifchannel_add(ifp, &sg, 0);
+       ch = pim_ifchannel_add(ifp, &sg, 0, 0);
        if (!ch) {
                zlog_warn(
                        "%s: (S,G)=%s failure creating channel on interface %s",
@@ -404,9 +405,9 @@ int pim_assert_build_msg(uint8_t *pim_msg, int buf_size, struct interface *ifp,
        }
 
        /* Metric preference */
-       pim_write_uint32(pim_msg_curr,
-                        rpt_bit_flag ? metric_preference | 0x80000000
-                                     : metric_preference);
+       pim_write_uint32(pim_msg_curr, rpt_bit_flag
+                                              ? metric_preference | 0x80000000
+                                              : metric_preference);
        pim_msg_curr += 4;
 
        /* Route metric */
index e4c50a18be386c86f56228dfc096801275792426..1dfb558f46de2bd27835dc0b64bc28834a002e99 100644 (file)
@@ -27,6 +27,7 @@
 #include "vty.h"
 #include "zclient.h"
 
+#include "pim_instance.h"
 #include "pim_cmd.h"
 #include "pim_vty.h"
 #include "pim_iface.h"
index 1c9fe40c299f7d76612342362cf7049c685bbc54..d7e94d11dd33447476dc3f07ff3e7f1058fa06c2 100644 (file)
@@ -27,6 +27,7 @@
 #include "plist.h"
 #include "hash.h"
 #include "nexthop.h"
+#include "vrf.h"
 
 #include "pimd.h"
 #include "pim_mroute.h"
@@ -70,6 +71,23 @@ static struct cmd_node interface_node = {
 
 static struct cmd_node debug_node = {DEBUG_NODE, "", 1};
 
+static struct vrf *pim_cmd_lookup_vrf(struct vty *vty, struct cmd_token *argv[],
+                                     const int argc, int *idx)
+{
+       struct vrf *vrf;
+
+       if (argv_find(argv, argc, "NAME", idx))
+               vrf = vrf_lookup_by_name(argv[*idx]->arg);
+       else
+               vrf = vrf_lookup_by_id(VRF_DEFAULT);
+
+       if (!vrf)
+               vty_out(vty, "Specified VRF: %s does not exist\n",
+                       argv[*idx]->arg);
+
+       return vrf;
+}
+
 static void pim_if_membership_clear(struct interface *ifp)
 {
        struct pim_interface *pim_ifp;
@@ -158,12 +176,45 @@ static void pim_if_membership_refresh(struct interface *ifp)
        pim_ifchannel_delete_on_noinfo(ifp);
 }
 
-static void pim_show_assert(struct vty *vty)
+static void pim_show_assert_helper(struct vty *vty,
+                                  struct pim_interface *pim_ifp,
+                                  struct pim_ifchannel *ch,
+                                  time_t now)
+{
+       char ch_src_str[INET_ADDRSTRLEN];
+       char ch_grp_str[INET_ADDRSTRLEN];
+       char winner_str[INET_ADDRSTRLEN];
+       struct in_addr ifaddr;
+       char uptime[10];
+       char timer[10];
+
+       ifaddr = pim_ifp->primary_address;
+
+       pim_inet4_dump("<ch_src?>", ch->sg.src, ch_src_str,
+                      sizeof(ch_src_str));
+       pim_inet4_dump("<ch_grp?>", ch->sg.grp, ch_grp_str,
+                      sizeof(ch_grp_str));
+       pim_inet4_dump("<assrt_win?>", ch->ifassert_winner, winner_str,
+                      sizeof(winner_str));
+
+       pim_time_uptime(uptime, sizeof(uptime),
+                       now - ch->ifassert_creation);
+       pim_time_timer_to_mmss(timer, sizeof(timer),
+                              ch->t_ifassert_timer);
+
+       vty_out(vty, "%-9s %-15s %-15s %-15s %-6s %-15s %-8s %-5s\n",
+               ch->interface->name, inet_ntoa(ifaddr), ch_src_str,
+               ch_grp_str,
+               pim_ifchannel_ifassert_name(ch->ifassert_state),
+               winner_str, uptime, timer);
+}
+
+static void pim_show_assert(struct pim_instance *pim, struct vty *vty)
 {
        struct pim_interface *pim_ifp;
        struct pim_ifchannel *ch;
-       struct listnode *ch_node;
-       struct in_addr ifaddr;
+       struct listnode *if_node;
+       struct interface *ifp;
        time_t now;
 
        now = pim_time_monotonic_sec();
@@ -171,46 +222,49 @@ static void pim_show_assert(struct vty *vty)
        vty_out(vty,
                "Interface Address         Source          Group           State  Winner          Uptime   Timer\n");
 
-       for (ALL_LIST_ELEMENTS_RO(pim_ifchannel_list, ch_node, ch)) {
-               char ch_src_str[INET_ADDRSTRLEN];
-               char ch_grp_str[INET_ADDRSTRLEN];
-               char winner_str[INET_ADDRSTRLEN];
-               char uptime[10];
-               char timer[10];
-
-               pim_ifp = ch->interface->info;
-
+       for (ALL_LIST_ELEMENTS_RO(vrf_iflist(pim->vrf_id), if_node, ifp)) {
+               pim_ifp = ifp->info;
                if (!pim_ifp)
                        continue;
 
-               ifaddr = pim_ifp->primary_address;
+               RB_FOREACH(ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb) {
+                       pim_show_assert_helper(vty, pim_ifp, ch, now);
+               } /* scan interface channels */
+       }
+}
 
-               pim_inet4_dump("<ch_src?>", ch->sg.src, ch_src_str,
-                              sizeof(ch_src_str));
-               pim_inet4_dump("<ch_grp?>", ch->sg.grp, ch_grp_str,
-                              sizeof(ch_grp_str));
-               pim_inet4_dump("<assrt_win?>", ch->ifassert_winner, winner_str,
-                              sizeof(winner_str));
+static void pim_show_assert_internal_helper(struct vty *vty,
+                                           struct pim_interface *pim_ifp,
+                                           struct pim_ifchannel *ch)
+{
+       char ch_src_str[INET_ADDRSTRLEN];
+       char ch_grp_str[INET_ADDRSTRLEN];
+       struct in_addr ifaddr;
 
-               pim_time_uptime(uptime, sizeof(uptime),
-                               now - ch->ifassert_creation);
-               pim_time_timer_to_mmss(timer, sizeof(timer),
-                                      ch->t_ifassert_timer);
+       ifaddr = pim_ifp->primary_address;
 
-               vty_out(vty, "%-9s %-15s %-15s %-15s %-6s %-15s %-8s %-5s\n",
-                       ch->interface->name, inet_ntoa(ifaddr), ch_src_str,
-                       ch_grp_str,
-                       pim_ifchannel_ifassert_name(ch->ifassert_state),
-                       winner_str, uptime, timer);
-       } /* scan interface channels */
+       pim_inet4_dump("<ch_src?>", ch->sg.src, ch_src_str,
+                      sizeof(ch_src_str));
+       pim_inet4_dump("<ch_grp?>", ch->sg.grp, ch_grp_str,
+                      sizeof(ch_grp_str));
+       vty_out(vty, "%-9s %-15s %-15s %-15s %-3s %-3s %-3s %-4s\n",
+               ch->interface->name, inet_ntoa(ifaddr), ch_src_str,
+               ch_grp_str,
+               PIM_IF_FLAG_TEST_COULD_ASSERT(ch->flags) ? "yes" : "no",
+               pim_macro_ch_could_assert_eval(ch) ? "yes" : "no",
+               PIM_IF_FLAG_TEST_ASSERT_TRACKING_DESIRED(ch->flags)
+               ? "yes"
+               : "no",
+               pim_macro_assert_tracking_desired_eval(ch) ? "yes"
+               : "no");
 }
 
-static void pim_show_assert_internal(struct vty *vty)
+static void pim_show_assert_internal(struct pim_instance *pim, struct vty *vty)
 {
        struct pim_interface *pim_ifp;
-       struct listnode *ch_node;
+       struct listnode *if_node;
        struct pim_ifchannel *ch;
-       struct in_addr ifaddr;
+       struct interface *ifp;
 
        vty_out(vty,
                "CA:   CouldAssert\n"
@@ -220,126 +274,127 @@ static void pim_show_assert_internal(struct vty *vty)
 
        vty_out(vty,
                "Interface Address         Source          Group           CA  eCA ATD eATD\n");
-
-       for (ALL_LIST_ELEMENTS_RO(pim_ifchannel_list, ch_node, ch)) {
-               pim_ifp = ch->interface->info;
-
+       for (ALL_LIST_ELEMENTS_RO(vrf_iflist(pim->vrf_id), if_node, ifp)) {
+               pim_ifp = ifp->info;
                if (!pim_ifp)
                        continue;
 
-               ifaddr = pim_ifp->primary_address;
+               RB_FOREACH(ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb) {
+                       pim_show_assert_internal_helper(vty, pim_ifp, ch);
+               } /* scan interface channels */
+       }
+}
+
+static void pim_show_assert_metric_helper(struct vty *vty,
+                                         struct pim_interface *pim_ifp,
+                                         struct pim_ifchannel *ch)
+{
+       char ch_src_str[INET_ADDRSTRLEN];
+       char ch_grp_str[INET_ADDRSTRLEN];
+       char addr_str[INET_ADDRSTRLEN];
+       struct pim_assert_metric am;
+       struct in_addr ifaddr;
 
-               char ch_src_str[INET_ADDRSTRLEN];
-               char ch_grp_str[INET_ADDRSTRLEN];
+       ifaddr = pim_ifp->primary_address;
 
-               pim_inet4_dump("<ch_src?>", ch->sg.src, ch_src_str,
-                              sizeof(ch_src_str));
-               pim_inet4_dump("<ch_grp?>", ch->sg.grp, ch_grp_str,
-                              sizeof(ch_grp_str));
-               vty_out(vty, "%-9s %-15s %-15s %-15s %-3s %-3s %-3s %-4s\n",
-                       ch->interface->name, inet_ntoa(ifaddr), ch_src_str,
-                       ch_grp_str,
-                       PIM_IF_FLAG_TEST_COULD_ASSERT(ch->flags) ? "yes" : "no",
-                       pim_macro_ch_could_assert_eval(ch) ? "yes" : "no",
-                       PIM_IF_FLAG_TEST_ASSERT_TRACKING_DESIRED(ch->flags)
-                               ? "yes"
-                               : "no",
-                       pim_macro_assert_tracking_desired_eval(ch) ? "yes"
-                                                                  : "no");
-       } /* scan interface channels */
+       am = pim_macro_spt_assert_metric(&ch->upstream->rpf,
+                                        pim_ifp->primary_address);
+
+       pim_inet4_dump("<ch_src?>", ch->sg.src, ch_src_str,
+                      sizeof(ch_src_str));
+       pim_inet4_dump("<ch_grp?>", ch->sg.grp, ch_grp_str,
+                      sizeof(ch_grp_str));
+       pim_inet4_dump("<addr?>", am.ip_address, addr_str,
+                      sizeof(addr_str));
+
+       vty_out(vty, "%-9s %-15s %-15s %-15s %-3s %4u %6u %-15s\n",
+               ch->interface->name, inet_ntoa(ifaddr), ch_src_str,
+               ch_grp_str, am.rpt_bit_flag ? "yes" : "no",
+               am.metric_preference, am.route_metric, addr_str);
 }
 
-static void pim_show_assert_metric(struct vty *vty)
+static void pim_show_assert_metric(struct pim_instance *pim, struct vty *vty)
 {
        struct pim_interface *pim_ifp;
-       struct listnode *ch_node;
+       struct listnode *if_node;
        struct pim_ifchannel *ch;
-       struct in_addr ifaddr;
+       struct interface *ifp;
 
        vty_out(vty,
                "Interface Address         Source          Group           RPT Pref Metric Address        \n");
 
-       for (ALL_LIST_ELEMENTS_RO(pim_ifchannel_list, ch_node, ch)) {
-               pim_ifp = ch->interface->info;
-
+       for (ALL_LIST_ELEMENTS_RO(vrf_iflist(pim->vrf_id), if_node, ifp)) {
+               pim_ifp = ifp->info;
                if (!pim_ifp)
                        continue;
 
-               ifaddr = pim_ifp->primary_address;
+               RB_FOREACH(ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb) {
+                       pim_show_assert_metric_helper(vty, pim_ifp, ch);
+               } /* scan interface channels */
+       }
+}
+
+static void pim_show_assert_winner_metric_helper(struct vty *vty,
+                                                struct pim_interface *pim_ifp,
+                                                struct pim_ifchannel *ch)
+{
+       char ch_src_str[INET_ADDRSTRLEN];
+       char ch_grp_str[INET_ADDRSTRLEN];
+       char addr_str[INET_ADDRSTRLEN];
+       struct pim_assert_metric *am;
+       struct in_addr ifaddr;
+       char pref_str[5];
+       char metr_str[7];
 
-               char ch_src_str[INET_ADDRSTRLEN];
-               char ch_grp_str[INET_ADDRSTRLEN];
-               char addr_str[INET_ADDRSTRLEN];
-               struct pim_assert_metric am;
+       ifaddr = pim_ifp->primary_address;
 
-               am = pim_macro_spt_assert_metric(&ch->upstream->rpf,
-                                                pim_ifp->primary_address);
+       am = &ch->ifassert_winner_metric;
 
-               pim_inet4_dump("<ch_src?>", ch->sg.src, ch_src_str,
-                              sizeof(ch_src_str));
-               pim_inet4_dump("<ch_grp?>", ch->sg.grp, ch_grp_str,
-                              sizeof(ch_grp_str));
-               pim_inet4_dump("<addr?>", am.ip_address, addr_str,
-                              sizeof(addr_str));
+       pim_inet4_dump("<ch_src?>", ch->sg.src, ch_src_str,
+                      sizeof(ch_src_str));
+       pim_inet4_dump("<ch_grp?>", ch->sg.grp, ch_grp_str,
+                      sizeof(ch_grp_str));
+       pim_inet4_dump("<addr?>", am->ip_address, addr_str,
+                      sizeof(addr_str));
+
+       if (am->metric_preference == PIM_ASSERT_METRIC_PREFERENCE_MAX)
+               snprintf(pref_str, sizeof(pref_str), "INFI");
+       else
+               snprintf(pref_str, sizeof(pref_str), "%4u",
+                        am->metric_preference);
+
+       if (am->route_metric == PIM_ASSERT_ROUTE_METRIC_MAX)
+               snprintf(metr_str, sizeof(metr_str), "INFI");
+       else
+               snprintf(metr_str, sizeof(metr_str), "%6u",
+                        am->route_metric);
 
-               vty_out(vty, "%-9s %-15s %-15s %-15s %-3s %4u %6u %-15s\n",
-                       ch->interface->name, inet_ntoa(ifaddr), ch_src_str,
-                       ch_grp_str, am.rpt_bit_flag ? "yes" : "no",
-                       am.metric_preference, am.route_metric, addr_str);
-       } /* scan interface channels */
+       vty_out(vty, "%-9s %-15s %-15s %-15s %-3s %-4s %-6s %-15s\n",
+               ch->interface->name, inet_ntoa(ifaddr), ch_src_str,
+               ch_grp_str, am->rpt_bit_flag ? "yes" : "no", pref_str,
+               metr_str, addr_str);
 }
 
-static void pim_show_assert_winner_metric(struct vty *vty)
+static void pim_show_assert_winner_metric(struct pim_instance *pim,
+                                         struct vty *vty)
 {
+       struct listnode *if_node;
        struct pim_interface *pim_ifp;
-       struct listnode *ch_node;
        struct pim_ifchannel *ch;
-       struct in_addr ifaddr;
+       struct interface *ifp;
 
        vty_out(vty,
                "Interface Address         Source          Group           RPT Pref Metric Address        \n");
 
-       for (ALL_LIST_ELEMENTS_RO(pim_ifchannel_list, ch_node, ch)) {
-               pim_ifp = ch->interface->info;
-
+       for (ALL_LIST_ELEMENTS_RO(vrf_iflist(pim->vrf_id), if_node, ifp)) {
+               pim_ifp = ifp->info;
                if (!pim_ifp)
                        continue;
 
-               ifaddr = pim_ifp->primary_address;
-
-               char ch_src_str[INET_ADDRSTRLEN];
-               char ch_grp_str[INET_ADDRSTRLEN];
-               char addr_str[INET_ADDRSTRLEN];
-               struct pim_assert_metric *am;
-               char pref_str[5];
-               char metr_str[7];
-
-               am = &ch->ifassert_winner_metric;
-
-               pim_inet4_dump("<ch_src?>", ch->sg.src, ch_src_str,
-                              sizeof(ch_src_str));
-               pim_inet4_dump("<ch_grp?>", ch->sg.grp, ch_grp_str,
-                              sizeof(ch_grp_str));
-               pim_inet4_dump("<addr?>", am->ip_address, addr_str,
-                              sizeof(addr_str));
-
-               if (am->metric_preference == PIM_ASSERT_METRIC_PREFERENCE_MAX)
-                       snprintf(pref_str, sizeof(pref_str), "INFI");
-               else
-                       snprintf(pref_str, sizeof(pref_str), "%4u",
-                                am->metric_preference);
-
-               if (am->route_metric == PIM_ASSERT_ROUTE_METRIC_MAX)
-                       snprintf(metr_str, sizeof(metr_str), "INFI");
-               else
-                       snprintf(metr_str, sizeof(metr_str), "%6u",
-                                am->route_metric);
-
-               vty_out(vty, "%-9s %-15s %-15s %-15s %-3s %-4s %-6s %-15s\n",
-                       ch->interface->name, inet_ntoa(ifaddr), ch_src_str,
-                       ch_grp_str, am->rpt_bit_flag ? "yes" : "no", pref_str,
-                       metr_str, addr_str);
-       } /* scan interface channels */
+               RB_FOREACH(ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb) {
+                       pim_show_assert_winner_metric_helper(vty, pim_ifp, ch);
+               } /* scan interface channels */
+       }
 }
 
 static void json_object_pim_ifp_add(struct json_object *json,
@@ -373,54 +428,63 @@ static void json_object_pim_ifp_add(struct json_object *json,
                json_object_boolean_true_add(json, "lanDelayEnabled");
 }
 
-static void pim_show_membership(struct vty *vty, u_char uj)
+static void pim_show_membership_helper(struct vty *vty,
+                                      struct pim_interface *pim_ifp,
+                                      struct pim_ifchannel *ch,
+                                      struct json_object *json)
+{
+       char ch_src_str[INET_ADDRSTRLEN];
+       char ch_grp_str[INET_ADDRSTRLEN];
+       json_object *json_iface = NULL;
+       json_object *json_row = NULL;
+
+       pim_inet4_dump("<ch_src?>", ch->sg.src, ch_src_str,
+                      sizeof(ch_src_str));
+       pim_inet4_dump("<ch_grp?>", ch->sg.grp, ch_grp_str,
+                      sizeof(ch_grp_str));
+
+       json_object_object_get_ex(json, ch->interface->name,
+                                 &json_iface);
+       if (!json_iface) {
+               json_iface = json_object_new_object();
+               json_object_pim_ifp_add(json_iface, ch->interface);
+               json_object_object_add(json, ch->interface->name,
+                                      json_iface);
+       }
+
+       json_row = json_object_new_object();
+       json_object_string_add(json_row, "source", ch_src_str);
+       json_object_string_add(json_row, "group", ch_grp_str);
+       json_object_string_add(
+               json_row, "localMembership",
+               ch->local_ifmembership == PIM_IFMEMBERSHIP_NOINFO
+               ? "NOINFO"
+               : "INCLUDE");
+       json_object_object_add(json_iface, ch_grp_str, json_row);
+
+}
+static void pim_show_membership(struct pim_instance *pim, struct vty *vty,
+                               u_char uj)
 {
+       struct listnode *if_node;
        struct pim_interface *pim_ifp;
-       struct listnode *ch_node;
        struct pim_ifchannel *ch;
+       struct interface *ifp;
        enum json_type type;
        json_object *json = NULL;
-       json_object *json_iface = NULL;
-       json_object *json_row = NULL;
        json_object *json_tmp = NULL;
 
        json = json_object_new_object();
 
-       for (ALL_LIST_ELEMENTS_RO(pim_ifchannel_list, ch_node, ch)) {
-
-               pim_ifp = ch->interface->info;
-
+       for (ALL_LIST_ELEMENTS_RO(vrf_iflist(pim->vrf_id), if_node, ifp)) {
+               pim_ifp = ifp->info;
                if (!pim_ifp)
                        continue;
 
-               char ch_src_str[INET_ADDRSTRLEN];
-               char ch_grp_str[INET_ADDRSTRLEN];
-
-               pim_inet4_dump("<ch_src?>", ch->sg.src, ch_src_str,
-                              sizeof(ch_src_str));
-               pim_inet4_dump("<ch_grp?>", ch->sg.grp, ch_grp_str,
-                              sizeof(ch_grp_str));
-
-               json_object_object_get_ex(json, ch->interface->name,
-                                         &json_iface);
-
-               if (!json_iface) {
-                       json_iface = json_object_new_object();
-                       json_object_pim_ifp_add(json_iface, ch->interface);
-                       json_object_object_add(json, ch->interface->name,
-                                              json_iface);
-               }
-
-               json_row = json_object_new_object();
-               json_object_string_add(json_row, "source", ch_src_str);
-               json_object_string_add(json_row, "group", ch_grp_str);
-               json_object_string_add(
-                       json_row, "localMembership",
-                       ch->local_ifmembership == PIM_IFMEMBERSHIP_NOINFO
-                               ? "NOINFO"
-                               : "INCLUDE");
-               json_object_object_add(json_iface, ch_grp_str, json_row);
-       } /* scan interface channels */
+               RB_FOREACH(ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb) {
+                       pim_show_membership_helper(vty, pim_ifp, ch, json);
+               } /* scan interface channels */
+       }
 
        if (uj) {
                vty_out(vty, "%s\n", json_object_to_json_string_ext(
@@ -517,7 +581,8 @@ static void pim_print_ifp_flags(struct vty *vty, struct interface *ifp,
        vty_out(vty, "\n");
 }
 
-static void igmp_show_interfaces(struct vty *vty, u_char uj)
+static void igmp_show_interfaces(struct pim_instance *pim, struct vty *vty,
+                                u_char uj)
 {
        struct listnode *node;
        struct interface *ifp;
@@ -533,7 +598,7 @@ static void igmp_show_interfaces(struct vty *vty, u_char uj)
                vty_out(vty,
                        "Interface  State          Address  V  Querier  Query Timer    Uptime\n");
 
-       for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT), node, ifp)) {
+       for (ALL_LIST_ELEMENTS_RO(vrf_iflist(pim->vrf_id), node, ifp)) {
                struct pim_interface *pim_ifp;
                struct listnode *sock_node;
                struct igmp_sock *igmp;
@@ -594,7 +659,8 @@ static void igmp_show_interfaces(struct vty *vty, u_char uj)
        }
 }
 
-static void igmp_show_interfaces_single(struct vty *vty, const char *ifname,
+static void igmp_show_interfaces_single(struct pim_instance *pim,
+                                       struct vty *vty, const char *ifname,
                                        u_char uj)
 {
        struct igmp_sock *igmp;
@@ -607,7 +673,7 @@ static void igmp_show_interfaces_single(struct vty *vty, const char *ifname,
        char other_hhmmss[10];
        int found_ifname = 0;
        int sqi;
-       int mloop;
+       int mloop = 0;
        long gmi_msec; /* Group Membership Interval */
        long lmqt_msec;
        long ohpi_msec;
@@ -623,7 +689,7 @@ static void igmp_show_interfaces_single(struct vty *vty, const char *ifname,
 
        now = pim_time_monotonic_sec();
 
-       for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT), node, ifp)) {
+       for (ALL_LIST_ELEMENTS_RO(vrf_iflist(pim->vrf_id), node, ifp)) {
                pim_ifp = ifp->info;
 
                if (!pim_ifp)
@@ -670,7 +736,11 @@ static void igmp_show_interfaces_single(struct vty *vty, const char *ifname,
 
                        qri_msec = pim_ifp->igmp_query_max_response_time_dsec
                                   * 100;
-                       mloop = pim_socket_mcastloop_get(pim_ifp->pim_sock_fd);
+                       if (pim_ifp->pim_sock_fd >= 0)
+                               mloop = pim_socket_mcastloop_get(
+                                       pim_ifp->pim_sock_fd);
+                       else
+                               mloop = 0;
 
                        if (uj) {
                                json_row = json_object_new_object();
@@ -793,7 +863,7 @@ static void igmp_show_interfaces_single(struct vty *vty, const char *ifname,
        }
 }
 
-static void igmp_show_interface_join(struct vty *vty)
+static void igmp_show_interface_join(struct pim_instance *pim, struct vty *vty)
 {
        struct listnode *node;
        struct interface *ifp;
@@ -804,7 +874,7 @@ static void igmp_show_interface_join(struct vty *vty)
        vty_out(vty,
                "Interface Address         Source          Group           Socket Uptime  \n");
 
-       for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT), node, ifp)) {
+       for (ALL_LIST_ELEMENTS_RO(vrf_iflist(pim->vrf_id), node, ifp)) {
                struct pim_interface *pim_ifp;
                struct listnode *join_node;
                struct igmp_join *ij;
@@ -844,7 +914,8 @@ static void igmp_show_interface_join(struct vty *vty)
        } /* for (iflist) */
 }
 
-static void pim_show_interfaces_single(struct vty *vty, const char *ifname,
+static void pim_show_interfaces_single(struct pim_instance *pim,
+                                      struct vty *vty, const char *ifname,
                                       u_char uj)
 {
        struct in_addr ifaddr;
@@ -866,7 +937,7 @@ static void pim_show_interfaces_single(struct vty *vty, const char *ifname,
        char src_str[INET_ADDRSTRLEN];
        char stat_uptime[10];
        char uptime[10];
-       int mloop;
+       int mloop = 0;
        int found_ifname = 0;
        int print_header;
        json_object *json = NULL;
@@ -884,15 +955,12 @@ static void pim_show_interfaces_single(struct vty *vty, const char *ifname,
        if (uj)
                json = json_object_new_object();
 
-       for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT), node, ifp)) {
+       for (ALL_LIST_ELEMENTS_RO(vrf_iflist(pim->vrf_id), node, ifp)) {
                pim_ifp = ifp->info;
 
                if (!pim_ifp)
                        continue;
 
-               if (pim_ifp->pim_sock_fd < 0)
-                       continue;
-
                if (strcmp(ifname, "detail") && strcmp(ifname, ifp->name))
                        continue;
 
@@ -908,7 +976,10 @@ static void pim_show_interfaces_single(struct vty *vty, const char *ifname,
                              pim_ifp->pim_hello_period);
                pim_time_uptime(stat_uptime, sizeof(stat_uptime),
                                now - pim_ifp->pim_ifstat_start);
-               mloop = pim_socket_mcastloop_get(pim_ifp->pim_sock_fd);
+               if (pim_ifp->pim_sock_fd >= 0)
+                       mloop = pim_socket_mcastloop_get(pim_ifp->pim_sock_fd);
+               else
+                       mloop = 0;
 
                if (uj) {
                        char pbuf[PREFIX2STR_BUFFER];
@@ -989,7 +1060,7 @@ static void pim_show_interfaces_single(struct vty *vty, const char *ifname,
                                            pim_ifp->pim_dr_election_changes);
 
                        // FHR
-                       for (ALL_LIST_ELEMENTS_RO(pim_upstream_list, upnode,
+                       for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, upnode,
                                                  up)) {
                                if (ifp == up->rpf.source_nexthop.interface) {
                                        if (up->flags
@@ -1163,11 +1234,10 @@ static void pim_show_interfaces_single(struct vty *vty, const char *ifname,
 
                        // FHR
                        print_header = 1;
-                       for (ALL_LIST_ELEMENTS_RO(pim_upstream_list, upnode,
+                       for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, upnode,
                                                  up)) {
-                               if (strcmp(ifp->name,
-                                          up->rpf.source_nexthop
-                                                  .interface->name)
+                               if (strcmp(ifp->name, up->rpf.source_nexthop
+                                                             .interface->name)
                                    == 0) {
                                        if (up->flags
                                            & PIM_UPSTREAM_FLAG_MASK_FHR) {
@@ -1263,7 +1333,8 @@ static void pim_show_interfaces_single(struct vty *vty, const char *ifname,
        }
 }
 
-static void pim_show_interfaces(struct vty *vty, u_char uj)
+static void pim_show_interfaces(struct pim_instance *pim, struct vty *vty,
+                               u_char uj)
 {
        struct interface *ifp;
        struct listnode *node;
@@ -1279,20 +1350,17 @@ static void pim_show_interfaces(struct vty *vty, u_char uj)
 
        json = json_object_new_object();
 
-       for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT), node, ifp)) {
+       for (ALL_LIST_ELEMENTS_RO(vrf_iflist(pim->vrf_id), node, ifp)) {
                pim_ifp = ifp->info;
 
                if (!pim_ifp)
                        continue;
 
-               if (pim_ifp->pim_sock_fd < 0)
-                       continue;
-
                pim_nbrs = pim_ifp->pim_neighbor_list->count;
-               pim_ifchannels = pim_ifp->pim_ifchannel_list->count;
+               pim_ifchannels = pim_if_ifchannel_count(pim_ifp);
                fhr = 0;
 
-               for (ALL_LIST_ELEMENTS_RO(pim_upstream_list, upnode, up))
+               for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, upnode, up))
                        if (ifp == up->rpf.source_nexthop.interface)
                                if (up->flags & PIM_UPSTREAM_FLAG_MASK_FHR)
                                        fhr++;
@@ -1359,7 +1427,8 @@ static void pim_show_interfaces(struct vty *vty, u_char uj)
        json_object_free(json);
 }
 
-static void pim_show_interface_traffic(struct vty *vty, u_char uj)
+static void pim_show_interface_traffic(struct pim_instance *pim,
+                                      struct vty *vty, u_char uj)
 {
        struct interface *ifp = NULL;
        struct pim_interface *pim_ifp = NULL;
@@ -1381,7 +1450,7 @@ static void pim_show_interface_traffic(struct vty *vty, u_char uj)
                        "---------------------------------------------------------------------------------------------------------------\n");
        }
 
-       for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT), node, ifp)) {
+       for (ALL_LIST_ELEMENTS_RO(vrf_iflist(pim->vrf_id), node, ifp)) {
                pim_ifp = ifp->info;
 
                if (!pim_ifp)
@@ -1438,7 +1507,8 @@ static void pim_show_interface_traffic(struct vty *vty, u_char uj)
        }
 }
 
-static void pim_show_interface_traffic_single(struct vty *vty,
+static void pim_show_interface_traffic_single(struct pim_instance *pim,
+                                             struct vty *vty,
                                              const char *ifname, u_char uj)
 {
        struct interface *ifp = NULL;
@@ -1462,7 +1532,7 @@ static void pim_show_interface_traffic_single(struct vty *vty,
                        "---------------------------------------------------------------------------------------------------------------\n");
        }
 
-       for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT), node, ifp)) {
+       for (ALL_LIST_ELEMENTS_RO(vrf_iflist(pim->vrf_id), node, ifp)) {
                if (strcmp(ifname, ifp->name))
                        continue;
 
@@ -1527,17 +1597,92 @@ static void pim_show_interface_traffic_single(struct vty *vty,
        }
 }
 
-static void pim_show_join(struct vty *vty, u_char uj)
+static void pim_show_join_helper(struct vty *vty,
+                                struct pim_interface *pim_ifp,
+                                struct pim_ifchannel *ch,
+                                json_object *json,
+                                time_t now,
+                                u_char uj)
 {
-       struct pim_interface *pim_ifp;
+       char ch_src_str[INET_ADDRSTRLEN];
+       char ch_grp_str[INET_ADDRSTRLEN];
+       json_object *json_iface = NULL;
+       json_object *json_row = NULL;
+       json_object *json_grp = NULL;
        struct in_addr ifaddr;
-       struct listnode *ch_node;
+       char uptime[10];
+       char expire[10];
+       char prune[10];
+
+       ifaddr = pim_ifp->primary_address;
+
+       pim_inet4_dump("<ch_src?>", ch->sg.src, ch_src_str,
+                      sizeof(ch_src_str));
+       pim_inet4_dump("<ch_grp?>", ch->sg.grp, ch_grp_str,
+                      sizeof(ch_grp_str));
+
+       pim_time_uptime_begin(uptime, sizeof(uptime), now,
+                             ch->ifjoin_creation);
+       pim_time_timer_to_mmss(expire, sizeof(expire),
+                              ch->t_ifjoin_expiry_timer);
+       pim_time_timer_to_mmss(prune, sizeof(prune),
+                              ch->t_ifjoin_prune_pending_timer);
+
+       if (uj) {
+               json_object_object_get_ex(json, ch->interface->name,
+                                         &json_iface);
+
+               if (!json_iface) {
+                       json_iface = json_object_new_object();
+                       json_object_pim_ifp_add(json_iface,
+                                               ch->interface);
+                       json_object_object_add(
+                               json, ch->interface->name, json_iface);
+               }
+
+               json_row = json_object_new_object();
+               json_object_string_add(json_row, "source", ch_src_str);
+               json_object_string_add(json_row, "group", ch_grp_str);
+               json_object_string_add(json_row, "upTime", uptime);
+               json_object_string_add(json_row, "expire", expire);
+               json_object_string_add(json_row, "prune", prune);
+               json_object_string_add(
+                       json_row, "channelJoinName",
+                       pim_ifchannel_ifjoin_name(ch->ifjoin_state,
+                                                 ch->flags));
+               if (PIM_IF_FLAG_TEST_S_G_RPT(ch->flags))
+                       json_object_int_add(json_row, "SGRpt", 1);
+
+               json_object_object_get_ex(json_iface, ch_grp_str,
+                                         &json_grp);
+               if (!json_grp) {
+                       json_grp = json_object_new_object();
+                       json_object_object_add(json_grp, ch_src_str,
+                                              json_row);
+                       json_object_object_add(json_iface, ch_grp_str,
+                                              json_grp);
+               } else
+                       json_object_object_add(json_grp, ch_src_str,
+                                              json_row);
+       } else {
+               vty_out(vty,
+                       "%-9s %-15s %-15s %-15s %-6s %8s %-6s %5s\n",
+                       ch->interface->name, inet_ntoa(ifaddr),
+                       ch_src_str, ch_grp_str,
+                       pim_ifchannel_ifjoin_name(ch->ifjoin_state,
+                                                 ch->flags),
+                       uptime, expire, prune);
+       }
+}
+
+static void pim_show_join(struct pim_instance *pim, struct vty *vty, u_char uj)
+{
+       struct listnode *if_node;
+       struct pim_interface *pim_ifp;
        struct pim_ifchannel *ch;
+       struct interface *ifp;
        time_t now;
        json_object *json = NULL;
-       json_object *json_iface = NULL;
-       json_object *json_row = NULL;
-       json_object *json_grp = NULL;
 
        now = pim_time_monotonic_sec();
 
@@ -1547,89 +1692,26 @@ static void pim_show_join(struct vty *vty, u_char uj)
                vty_out(vty,
                        "Interface Address         Source          Group           State  Uptime   Expire Prune\n");
 
-       for (ALL_LIST_ELEMENTS_RO(pim_ifchannel_list, ch_node, ch)) {
-
-               pim_ifp = ch->interface->info;
-
+       for (ALL_LIST_ELEMENTS_RO(vrf_iflist(pim->vrf_id), if_node, ifp)) {
+               pim_ifp = ifp->info;
                if (!pim_ifp)
                        continue;
 
-               ifaddr = pim_ifp->primary_address;
-
-               char ch_src_str[INET_ADDRSTRLEN];
-               char ch_grp_str[INET_ADDRSTRLEN];
-               char uptime[10];
-               char expire[10];
-               char prune[10];
-
-               pim_inet4_dump("<ch_src?>", ch->sg.src, ch_src_str,
-                              sizeof(ch_src_str));
-               pim_inet4_dump("<ch_grp?>", ch->sg.grp, ch_grp_str,
-                              sizeof(ch_grp_str));
-
-               pim_time_uptime_begin(uptime, sizeof(uptime), now,
-                                     ch->ifjoin_creation);
-               pim_time_timer_to_mmss(expire, sizeof(expire),
-                                      ch->t_ifjoin_expiry_timer);
-               pim_time_timer_to_mmss(prune, sizeof(prune),
-                                      ch->t_ifjoin_prune_pending_timer);
-
-               if (uj) {
-                       json_object_object_get_ex(json, ch->interface->name,
-                                                 &json_iface);
-
-                       if (!json_iface) {
-                               json_iface = json_object_new_object();
-                               json_object_pim_ifp_add(json_iface,
-                                                       ch->interface);
-                               json_object_object_add(
-                                       json, ch->interface->name, json_iface);
-                       }
-
-                       json_row = json_object_new_object();
-                       json_object_string_add(json_row, "source", ch_src_str);
-                       json_object_string_add(json_row, "group", ch_grp_str);
-                       json_object_string_add(json_row, "upTime", uptime);
-                       json_object_string_add(json_row, "expire", expire);
-                       json_object_string_add(json_row, "prune", prune);
-                       json_object_string_add(
-                               json_row, "channelJoinName",
-                               pim_ifchannel_ifjoin_name(ch->ifjoin_state,
-                                                         ch->flags));
-                       if (PIM_IF_FLAG_TEST_S_G_RPT(ch->flags))
-                               json_object_int_add(json_row, "SGRpt", 1);
-
-                       json_object_object_get_ex(json_iface, ch_grp_str,
-                                                 &json_grp);
-                       if (!json_grp) {
-                               json_grp = json_object_new_object();
-                               json_object_object_add(json_grp, ch_src_str,
-                                                      json_row);
-                               json_object_object_add(json_iface, ch_grp_str,
-                                                      json_grp);
-                       } else
-                               json_object_object_add(json_grp, ch_src_str,
-                                                      json_row);
-               } else {
-                       vty_out(vty,
-                               "%-9s %-15s %-15s %-15s %-6s %8s %-6s %5s\n",
-                               ch->interface->name, inet_ntoa(ifaddr),
-                               ch_src_str, ch_grp_str,
-                               pim_ifchannel_ifjoin_name(ch->ifjoin_state,
-                                                         ch->flags),
-                               uptime, expire, prune);
-               }
-       } /* scan interface channels */
+               RB_FOREACH(ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb) {
+                       pim_show_join_helper(vty, pim_ifp,
+                                            ch, json, now, uj);
+               } /* scan interface channels */
+       }
 
        if (uj) {
                vty_out(vty, "%s\n", json_object_to_json_string_ext(
-                                            json, JSON_C_TO_STRING_PRETTY));
+                               json, JSON_C_TO_STRING_PRETTY));
                json_object_free(json);
        }
 }
 
-static void pim_show_neighbors_single(struct vty *vty, const char *neighbor,
-                                     u_char uj)
+static void pim_show_neighbors_single(struct pim_instance *pim, struct vty *vty,
+                                     const char *neighbor, u_char uj)
 {
        struct listnode *node;
        struct listnode *neighnode;
@@ -1657,7 +1739,7 @@ static void pim_show_neighbors_single(struct vty *vty, const char *neighbor,
        if (uj)
                json = json_object_new_object();
 
-       for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT), node, ifp)) {
+       for (ALL_LIST_ELEMENTS_RO(vrf_iflist(pim->vrf_id), node, ifp)) {
                pim_ifp = ifp->info;
 
                if (!pim_ifp)
@@ -1838,8 +1920,9 @@ static void pim_show_neighbors_single(struct vty *vty, const char *neighbor,
        }
 }
 
-static void pim_show_state(struct vty *vty, const char *src_or_group,
-                          const char *group, u_char uj)
+static void pim_show_state(struct pim_instance *pim, struct vty *vty,
+                          const char *src_or_group, const char *group,
+                          u_char uj)
 {
        struct channel_oil *c_oil;
        struct listnode *node;
@@ -1861,7 +1944,7 @@ static void pim_show_state(struct vty *vty, const char *src_or_group,
                        "\nInstalled Source           Group            IIF      OIL\n");
        }
 
-       for (ALL_LIST_ELEMENTS_RO(pim_channel_oil_list, node, c_oil)) {
+       for (ALL_LIST_ELEMENTS_RO(pim->channel_oil_list, node, c_oil)) {
                char grp_str[INET_ADDRSTRLEN];
                char src_str[INET_ADDRSTRLEN];
                char in_ifname[INTERFACE_NAMSIZ + 1];
@@ -1874,7 +1957,7 @@ static void pim_show_state(struct vty *vty, const char *src_or_group,
                               sizeof(grp_str));
                pim_inet4_dump("<source?>", c_oil->oil.mfcc_origin, src_str,
                               sizeof(src_str));
-               ifp_in = pim_if_find_by_vif_index(c_oil->oil.mfcc_parent);
+               ifp_in = pim_if_find_by_vif_index(pim, c_oil->oil.mfcc_parent);
 
                if (ifp_in)
                        strcpy(in_ifname, ifp_in->name);
@@ -1956,7 +2039,7 @@ static void pim_show_state(struct vty *vty, const char *src_or_group,
                        if (ttl < 1)
                                continue;
 
-                       ifp_out = pim_if_find_by_vif_index(oif_vif_index);
+                       ifp_out = pim_if_find_by_vif_index(pim, oif_vif_index);
                        pim_time_uptime(
                                oif_uptime, sizeof(oif_uptime),
                                now - c_oil->oif_creation[oif_vif_index]);
@@ -2039,7 +2122,8 @@ static void pim_show_state(struct vty *vty, const char *src_or_group,
        }
 }
 
-static void pim_show_neighbors(struct vty *vty, u_char uj)
+static void pim_show_neighbors(struct pim_instance *pim, struct vty *vty,
+                              u_char uj)
 {
        struct listnode *node;
        struct listnode *neighnode;
@@ -2063,7 +2147,7 @@ static void pim_show_neighbors(struct vty *vty, u_char uj)
                        "Interface         Neighbor    Uptime  Holdtime  DR Pri\n");
        }
 
-       for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT), node, ifp)) {
+       for (ALL_LIST_ELEMENTS_RO(vrf_iflist(pim->vrf_id), node, ifp)) {
                pim_ifp = ifp->info;
 
                if (!pim_ifp)
@@ -2121,7 +2205,8 @@ static void pim_show_neighbors(struct vty *vty, u_char uj)
        }
 }
 
-static void pim_show_neighbors_secondary(struct vty *vty)
+static void pim_show_neighbors_secondary(struct pim_instance *pim,
+                                        struct vty *vty)
 {
        struct listnode *node;
        struct interface *ifp;
@@ -2129,7 +2214,7 @@ static void pim_show_neighbors_secondary(struct vty *vty)
        vty_out(vty,
                "Interface Address         Neighbor        Secondary      \n");
 
-       for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT), node, ifp)) {
+       for (ALL_LIST_ELEMENTS_RO(vrf_iflist(pim->vrf_id), node, ifp)) {
                struct pim_interface *pim_ifp;
                struct in_addr ifaddr;
                struct listnode *neighnode;
@@ -2235,7 +2320,8 @@ static const char *pim_reg_state2brief_str(enum pim_reg_state reg_state,
        return state_str;
 }
 
-static void pim_show_upstream(struct vty *vty, u_char uj)
+static void pim_show_upstream(struct pim_instance *pim, struct vty *vty,
+                             u_char uj)
 {
        struct listnode *upnode;
        struct pim_upstream *up;
@@ -2252,7 +2338,7 @@ static void pim_show_upstream(struct vty *vty, u_char uj)
                vty_out(vty,
                        "Iif       Source          Group           State       Uptime   JoinTimer RSTimer   KATimer   RefCnt\n");
 
-       for (ALL_LIST_ELEMENTS_RO(pim_upstream_list, upnode, up)) {
+       for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, upnode, up)) {
                char src_str[INET_ADDRSTRLEN];
                char grp_str[INET_ADDRSTRLEN];
                char uptime[10];
@@ -2352,81 +2438,100 @@ static void pim_show_upstream(struct vty *vty, u_char uj)
        }
 }
 
-static void pim_show_join_desired(struct vty *vty, u_char uj)
+static void pim_show_join_desired_helper(struct pim_instance *pim,
+                                        struct vty *vty,
+                                        struct pim_interface *pim_ifp,
+                                        struct pim_ifchannel *ch,
+                                        json_object *json,
+                                        u_char uj)
 {
-       struct listnode *chnode;
-       struct pim_interface *pim_ifp;
-       struct pim_ifchannel *ch;
+       struct pim_upstream *up = ch->upstream;
+       json_object *json_group = NULL;
        char src_str[INET_ADDRSTRLEN];
        char grp_str[INET_ADDRSTRLEN];
-       json_object *json = NULL;
-       json_object *json_group = NULL;
        json_object *json_row = NULL;
 
-       if (uj)
-               json = json_object_new_object();
-       else
-               vty_out(vty,
-                       "Interface Source          Group           LostAssert Joins PimInclude JoinDesired EvalJD\n");
+       pim_inet4_dump("<src?>", up->sg.src, src_str, sizeof(src_str));
+       pim_inet4_dump("<grp?>", up->sg.grp, grp_str, sizeof(grp_str));
 
-       /* scan per-interface (S,G) state */
-       for (ALL_LIST_ELEMENTS_RO(pim_ifchannel_list, chnode, ch)) {
-               /* scan all interfaces */
-               pim_ifp = ch->interface->info;
-               if (!pim_ifp)
-                       continue;
+       if (uj) {
+               json_object_object_get_ex(json, grp_str, &json_group);
 
-               struct pim_upstream *up = ch->upstream;
+               if (!json_group) {
+                       json_group = json_object_new_object();
+                       json_object_object_add(json, grp_str,
+                                              json_group);
+               }
 
-               pim_inet4_dump("<src?>", up->sg.src, src_str, sizeof(src_str));
-               pim_inet4_dump("<grp?>", up->sg.grp, grp_str, sizeof(grp_str));
+               json_row = json_object_new_object();
+               json_object_pim_upstream_add(json_row, up);
+               json_object_string_add(json_row, "interface",
+                                      ch->interface->name);
+               json_object_string_add(json_row, "source", src_str);
+               json_object_string_add(json_row, "group", grp_str);
 
-               if (uj) {
-                       json_object_object_get_ex(json, grp_str, &json_group);
+               if (pim_macro_ch_lost_assert(ch))
+                       json_object_boolean_true_add(json_row,
+                                                    "lostAssert");
 
-                       if (!json_group) {
-                               json_group = json_object_new_object();
-                               json_object_object_add(json, grp_str,
-                                                      json_group);
-                       }
+               if (pim_macro_chisin_joins(ch))
+                       json_object_boolean_true_add(json_row, "joins");
 
-                       json_row = json_object_new_object();
-                       json_object_pim_upstream_add(json_row, up);
-                       json_object_string_add(json_row, "interface",
-                                              ch->interface->name);
-                       json_object_string_add(json_row, "source", src_str);
-                       json_object_string_add(json_row, "group", grp_str);
+               if (pim_macro_chisin_pim_include(ch))
+                       json_object_boolean_true_add(json_row,
+                                                    "pimInclude");
 
-                       if (pim_macro_ch_lost_assert(ch))
-                               json_object_boolean_true_add(json_row,
-                                                            "lostAssert");
+               if (pim_upstream_evaluate_join_desired(pim, up))
+                       json_object_boolean_true_add(
+                               json_row, "evaluateJoinDesired");
 
-                       if (pim_macro_chisin_joins(ch))
-                               json_object_boolean_true_add(json_row, "joins");
+               json_object_object_add(json_group, src_str, json_row);
 
-                       if (pim_macro_chisin_pim_include(ch))
-                               json_object_boolean_true_add(json_row,
-                                                            "pimInclude");
+       } else {
+               vty_out(vty,
+                       "%-9s %-15s %-15s %-10s %-5s %-10s %-11s %-6s\n",
+                       ch->interface->name, src_str, grp_str,
+                       pim_macro_ch_lost_assert(ch) ? "yes" : "no",
+                       pim_macro_chisin_joins(ch) ? "yes" : "no",
+                       pim_macro_chisin_pim_include(ch) ? "yes" : "no",
+                       PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED(
+                               up->flags)
+                       ? "yes"
+                       : "no",
+                       pim_upstream_evaluate_join_desired(pim, up)
+                       ? "yes"
+                       : "no");
+       }
+}
 
-                       if (pim_upstream_evaluate_join_desired(up))
-                               json_object_boolean_true_add(
-                                       json_row, "evaluateJoinDesired");
+static void pim_show_join_desired(struct pim_instance *pim, struct vty *vty,
+                                 u_char uj)
+{
+       struct listnode *if_node;
+       struct pim_interface *pim_ifp;
+       struct pim_ifchannel *ch;
+       struct interface *ifp;
 
-                       json_object_object_add(json_group, src_str, json_row);
+       json_object *json = NULL;
 
-               } else {
-                       vty_out(vty,
-                               "%-9s %-15s %-15s %-10s %-5s %-10s %-11s %-6s\n",
-                               ch->interface->name, src_str, grp_str,
-                               pim_macro_ch_lost_assert(ch) ? "yes" : "no",
-                               pim_macro_chisin_joins(ch) ? "yes" : "no",
-                               pim_macro_chisin_pim_include(ch) ? "yes" : "no",
-                               PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED(
-                                       up->flags)
-                                       ? "yes"
-                                       : "no",
-                               pim_upstream_evaluate_join_desired(up) ? "yes"
-                                                                      : "no");
+       if (uj)
+               json = json_object_new_object();
+       else
+               vty_out(vty,
+                       "Interface Source          Group           LostAssert Joins PimInclude JoinDesired EvalJD\n");
+
+       /* scan per-interface (S,G) state */
+       for (ALL_LIST_ELEMENTS_RO(vrf_iflist(pim->vrf_id), if_node, ifp)) {
+               pim_ifp = ifp->info;
+               if (!pim_ifp)
+                       continue;
+
+
+               RB_FOREACH(ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb) {
+                       /* scan all interfaces */
+                       pim_show_join_desired_helper(pim, vty,
+                                                    pim_ifp, ch,
+                                                    json, uj);
                }
        }
 
@@ -2437,7 +2542,8 @@ static void pim_show_join_desired(struct vty *vty, u_char uj)
        }
 }
 
-static void pim_show_upstream_rpf(struct vty *vty, u_char uj)
+static void pim_show_upstream_rpf(struct pim_instance *pim, struct vty *vty,
+                                 u_char uj)
 {
        struct listnode *upnode;
        struct pim_upstream *up;
@@ -2451,7 +2557,7 @@ static void pim_show_upstream_rpf(struct vty *vty, u_char uj)
                vty_out(vty,
                        "Source          Group           RpfIface RibNextHop      RpfAddress     \n");
 
-       for (ALL_LIST_ELEMENTS_RO(pim_upstream_list, upnode, up)) {
+       for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, upnode, up)) {
                char src_str[INET_ADDRSTRLEN];
                char grp_str[INET_ADDRSTRLEN];
                char rpf_nexthop_str[PREFIX_STRLEN];
@@ -2547,7 +2653,8 @@ static void show_rpf_refresh_stats(struct vty *vty, time_t now,
        }
 }
 
-static void show_scan_oil_stats(struct vty *vty, time_t now)
+static void show_scan_oil_stats(struct pim_instance *pim, struct vty *vty,
+                               time_t now)
 {
        char uptime_scan_oil[10];
        char uptime_mroute_add[10];
@@ -2556,20 +2663,20 @@ static void show_scan_oil_stats(struct vty *vty, time_t now)
        pim_time_uptime_begin(uptime_scan_oil, sizeof(uptime_scan_oil), now,
                              qpim_scan_oil_last);
        pim_time_uptime_begin(uptime_mroute_add, sizeof(uptime_mroute_add), now,
-                             qpim_mroute_add_last);
+                             pim->mroute_add_last);
        pim_time_uptime_begin(uptime_mroute_del, sizeof(uptime_mroute_del), now,
-                             qpim_mroute_del_last);
+                             pim->mroute_del_last);
 
        vty_out(vty,
                "Scan OIL - Last: %s  Events: %lld\n"
                "MFC Add  - Last: %s  Events: %lld\n"
                "MFC Del  - Last: %s  Events: %lld\n",
                uptime_scan_oil, (long long)qpim_scan_oil_events,
-               uptime_mroute_add, (long long)qpim_mroute_add_events,
-               uptime_mroute_del, (long long)qpim_mroute_del_events);
+               uptime_mroute_add, (long long)pim->mroute_add_events,
+               uptime_mroute_del, (long long)pim->mroute_del_events);
 }
 
-static void pim_show_rpf(struct vty *vty, u_char uj)
+static void pim_show_rpf(struct pim_instance *pim, struct vty *vty, u_char uj)
 {
        struct listnode *up_node;
        struct pim_upstream *up;
@@ -2588,7 +2695,7 @@ static void pim_show_rpf(struct vty *vty, u_char uj)
                        "Source          Group           RpfIface RpfAddress      RibNextHop      Metric Pref\n");
        }
 
-       for (ALL_LIST_ELEMENTS_RO(pim_upstream_list, up_node, up)) {
+       for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, up_node, up)) {
                char src_str[INET_ADDRSTRLEN];
                char grp_str[INET_ADDRSTRLEN];
                char rpf_addr_str[PREFIX_STRLEN];
@@ -2648,10 +2755,17 @@ static void pim_show_rpf(struct vty *vty, u_char uj)
        }
 }
 
+struct pnc_cache_walk_data {
+       struct vty *vty;
+       struct pim_instance *pim;
+};
+
 static int pim_print_pnc_cache_walkcb(struct hash_backet *backet, void *arg)
 {
        struct pim_nexthop_cache *pnc = backet->data;
-       struct vty *vty = arg;
+       struct pnc_cache_walk_data *cwd = arg;
+       struct vty *vty = cwd->vty;
+       struct pim_instance *pim = cwd->pim;
        struct nexthop *nh_node = NULL;
        ifindex_t first_ifindex;
        struct interface *ifp = NULL;
@@ -2661,7 +2775,7 @@ static int pim_print_pnc_cache_walkcb(struct hash_backet *backet, void *arg)
 
        for (nh_node = pnc->nexthop; nh_node; nh_node = nh_node->next) {
                first_ifindex = nh_node->ifindex;
-               ifp = if_lookup_by_index(first_ifindex, VRF_DEFAULT);
+               ifp = if_lookup_by_index(first_ifindex, pim->vrf_id);
 
                vty_out(vty, "%-15s ", inet_ntoa(pnc->rpf.rpf_addr.u.prefix4));
                vty_out(vty, "%-14s ", ifp ? ifp->name : "NULL");
@@ -2671,23 +2785,22 @@ static int pim_print_pnc_cache_walkcb(struct hash_backet *backet, void *arg)
        return CMD_SUCCESS;
 }
 
-static void pim_show_nexthop(struct vty *vty)
+static void pim_show_nexthop(struct pim_instance *pim, struct vty *vty)
 {
+       struct pnc_cache_walk_data cwd;
 
-       if (pimg && !pimg->rpf_hash) {
-               vty_out(vty, "no nexthop cache \n");
-               return;
-       }
-
-       vty_out(vty, "Number of registered addresses: %lu \n",
-               pimg->rpf_hash->count);
+       cwd.vty = vty;
+       cwd.pim = pim;
+       vty_out(vty, "Number of registered addresses: %lu\n",
+               pim->rpf_hash->count);
        vty_out(vty, "Address         Interface      Nexthop\n");
        vty_out(vty, "-------------------------------------------\n");
 
-       hash_walk(pimg->rpf_hash, pim_print_pnc_cache_walkcb, vty);
+       hash_walk(pim->rpf_hash, pim_print_pnc_cache_walkcb, &cwd);
 }
 
-static void igmp_show_groups(struct vty *vty, u_char uj)
+static void igmp_show_groups(struct pim_instance *pim, struct vty *vty,
+                            u_char uj)
 {
        struct listnode *ifnode;
        struct interface *ifp;
@@ -2705,7 +2818,7 @@ static void igmp_show_groups(struct vty *vty, u_char uj)
                        "Interface Address         Group           Mode Timer    Srcs V Uptime  \n");
 
        /* scan interfaces */
-       for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT), ifnode, ifp)) {
+       for (ALL_LIST_ELEMENTS_RO(vrf_iflist(pim->vrf_id), ifnode, ifp)) {
                struct pim_interface *pim_ifp = ifp->info;
                struct listnode *sock_node;
                struct igmp_sock *igmp;
@@ -2808,7 +2921,8 @@ static void igmp_show_groups(struct vty *vty, u_char uj)
        }
 }
 
-static void igmp_show_group_retransmission(struct vty *vty)
+static void igmp_show_group_retransmission(struct pim_instance *pim,
+                                          struct vty *vty)
 {
        struct listnode *ifnode;
        struct interface *ifp;
@@ -2817,7 +2931,7 @@ static void igmp_show_group_retransmission(struct vty *vty)
                "Interface Address         Group           RetTimer Counter RetSrcs\n");
 
        /* scan interfaces */
-       for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT), ifnode, ifp)) {
+       for (ALL_LIST_ELEMENTS_RO(vrf_iflist(pim->vrf_id), ifnode, ifp)) {
                struct pim_interface *pim_ifp = ifp->info;
                struct listnode *sock_node;
                struct igmp_sock *igmp;
@@ -2873,7 +2987,7 @@ static void igmp_show_group_retransmission(struct vty *vty)
        }                 /* scan interfaces */
 }
 
-static void igmp_show_sources(struct vty *vty)
+static void igmp_show_sources(struct pim_instance *pim, struct vty *vty)
 {
        struct listnode *ifnode;
        struct interface *ifp;
@@ -2885,7 +2999,7 @@ static void igmp_show_sources(struct vty *vty)
                "Interface Address         Group           Source          Timer Fwd Uptime  \n");
 
        /* scan interfaces */
-       for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT), ifnode, ifp)) {
+       for (ALL_LIST_ELEMENTS_RO(vrf_iflist(pim->vrf_id), ifnode, ifp)) {
                struct pim_interface *pim_ifp = ifp->info;
                struct listnode *sock_node;
                struct igmp_sock *igmp;
@@ -2949,7 +3063,8 @@ static void igmp_show_sources(struct vty *vty)
        }                         /* scan interfaces */
 }
 
-static void igmp_show_source_retransmission(struct vty *vty)
+static void igmp_show_source_retransmission(struct pim_instance *pim,
+                                           struct vty *vty)
 {
        struct listnode *ifnode;
        struct interface *ifp;
@@ -2958,7 +3073,7 @@ static void igmp_show_source_retransmission(struct vty *vty)
                "Interface Address         Group           Source          Counter\n");
 
        /* scan interfaces */
-       for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT), ifnode, ifp)) {
+       for (ALL_LIST_ELEMENTS_RO(vrf_iflist(pim->vrf_id), ifnode, ifp)) {
                struct pim_interface *pim_ifp = ifp->info;
                struct listnode *sock_node;
                struct igmp_sock *igmp;
@@ -3008,30 +3123,30 @@ static void igmp_show_source_retransmission(struct vty *vty)
        }                         /* scan interfaces */
 }
 
-static void clear_igmp_interfaces()
+static void clear_igmp_interfaces(struct pim_instance *pim)
 {
        struct listnode *ifnode;
        struct listnode *ifnextnode;
        struct interface *ifp;
 
-       for (ALL_LIST_ELEMENTS(vrf_iflist(VRF_DEFAULT), ifnode, ifnextnode,
+       for (ALL_LIST_ELEMENTS(vrf_iflist(pim->vrf_id), ifnode, ifnextnode,
                               ifp)) {
                pim_if_addr_del_all_igmp(ifp);
        }
 
-       for (ALL_LIST_ELEMENTS(vrf_iflist(VRF_DEFAULT), ifnode, ifnextnode,
+       for (ALL_LIST_ELEMENTS(vrf_iflist(pim->vrf_id), ifnode, ifnextnode,
                               ifp)) {
                pim_if_addr_add_all(ifp);
        }
 }
 
-static void clear_pim_interfaces()
+static void clear_pim_interfaces(struct pim_instance *pim)
 {
        struct listnode *ifnode;
        struct listnode *ifnextnode;
        struct interface *ifp;
 
-       for (ALL_LIST_ELEMENTS(vrf_iflist(VRF_DEFAULT), ifnode, ifnextnode,
+       for (ALL_LIST_ELEMENTS(vrf_iflist(pim->vrf_id), ifnode, ifnextnode,
                               ifp)) {
                if (ifp->info) {
                        pim_neighbor_delete_all(ifp, "interface cleared");
@@ -3039,43 +3154,57 @@ static void clear_pim_interfaces()
        }
 }
 
-static void clear_interfaces()
+static void clear_interfaces(struct pim_instance *pim)
 {
-       clear_igmp_interfaces();
-       clear_pim_interfaces();
+       clear_igmp_interfaces(pim);
+       clear_pim_interfaces(pim);
 }
 
 DEFUN (clear_ip_interfaces,
        clear_ip_interfaces_cmd,
-       "clear ip interfaces",
+       "clear ip interfaces [vrf NAME]",
        CLEAR_STR
        IP_STR
-       "Reset interfaces\n")
+       "Reset interfaces\n"
+       VRF_CMD_HELP_STR)
 {
-       clear_interfaces();
+       int idx = 2;
+       struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
+
+       if (!vrf)
+               return CMD_WARNING;
+
+       clear_interfaces(vrf->info);
 
        return CMD_SUCCESS;
 }
 
 DEFUN (clear_ip_igmp_interfaces,
        clear_ip_igmp_interfaces_cmd,
-       "clear ip igmp interfaces",
+       "clear ip igmp [vrf NAME] interfaces",
        CLEAR_STR
        IP_STR
        CLEAR_IP_IGMP_STR
+       VRF_CMD_HELP_STR
        "Reset IGMP interfaces\n")
 {
-       clear_igmp_interfaces();
+       int idx = 2;
+       struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
+
+       if (!vrf)
+               return CMD_WARNING;
+
+       clear_igmp_interfaces(vrf->info);
 
        return CMD_SUCCESS;
 }
 
-static void mroute_add_all()
+static void mroute_add_all(struct pim_instance *pim)
 {
        struct listnode *node;
        struct channel_oil *c_oil;
 
-       for (ALL_LIST_ELEMENTS_RO(pim_channel_oil_list, node, c_oil)) {
+       for (ALL_LIST_ELEMENTS_RO(pim->channel_oil_list, node, c_oil)) {
                if (pim_mroute_add(c_oil, __PRETTY_FUNCTION__)) {
                        /* just log warning */
                        char source_str[INET_ADDRSTRLEN];
@@ -3091,12 +3220,12 @@ static void mroute_add_all()
        }
 }
 
-static void mroute_del_all()
+static void mroute_del_all(struct pim_instance *pim)
 {
        struct listnode *node;
        struct channel_oil *c_oil;
 
-       for (ALL_LIST_ELEMENTS_RO(pim_channel_oil_list, node, c_oil)) {
+       for (ALL_LIST_ELEMENTS_RO(pim->channel_oil_list, node, c_oil)) {
                if (pim_mroute_del(c_oil, __PRETTY_FUNCTION__)) {
                        /* just log warning */
                        char source_str[INET_ADDRSTRLEN];
@@ -3114,45 +3243,65 @@ static void mroute_del_all()
 
 DEFUN (clear_ip_mroute,
        clear_ip_mroute_cmd,
-       "clear ip mroute",
+       "clear ip mroute [vrf NAME]",
        CLEAR_STR
        IP_STR
-       "Reset multicast routes\n")
+       "Reset multicast routes\n"
+       VRF_CMD_HELP_STR)
 {
-       mroute_del_all();
-       mroute_add_all();
+       int idx = 2;
+       struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
+
+       if (!vrf)
+               return CMD_WARNING;
+
+       mroute_del_all(vrf->info);
+       mroute_add_all(vrf->info);
 
        return CMD_SUCCESS;
 }
 
 DEFUN (clear_ip_pim_interfaces,
        clear_ip_pim_interfaces_cmd,
-       "clear ip pim interfaces",
+       "clear ip pim [vrf NAME] interfaces",
        CLEAR_STR
        IP_STR
        CLEAR_IP_PIM_STR
+       VRF_CMD_HELP_STR
        "Reset PIM interfaces\n")
 {
-       clear_pim_interfaces();
+       int idx = 2;
+       struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
+
+       if (!vrf)
+               return CMD_WARNING;
+
+       clear_pim_interfaces(vrf->info);
 
        return CMD_SUCCESS;
 }
 
 DEFUN (clear_ip_pim_interface_traffic,
        clear_ip_pim_interface_traffic_cmd,
-       "clear ip pim interface traffic",
+       "clear ip pim [vrf NAME] interface traffic",
        "Reset functions\n"
        "IP information\n"
        "PIM clear commands\n"
+       VRF_CMD_HELP_STR
        "Reset PIM interfaces\n"
        "Reset Protocol Packet counters\n")
 {
+       int idx = 2;
+       struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
        struct listnode *ifnode = NULL;
        struct listnode *ifnextnode = NULL;
        struct interface *ifp = NULL;
        struct pim_interface *pim_ifp = NULL;
 
-       for (ALL_LIST_ELEMENTS(vrf_iflist(VRF_DEFAULT), ifnode, ifnextnode,
+       if (!vrf)
+               return CMD_WARNING;
+
+       for (ALL_LIST_ELEMENTS(vrf_iflist(vrf->vrf_id), ifnode, ifnextnode,
                               ifp)) {
                pim_ifp = ifp->info;
 
@@ -3178,373 +3327,893 @@ DEFUN (clear_ip_pim_interface_traffic,
 
 DEFUN (clear_ip_pim_oil,
        clear_ip_pim_oil_cmd,
-       "clear ip pim oil",
+       "clear ip pim [vrf NAME] oil",
        CLEAR_STR
        IP_STR
        CLEAR_IP_PIM_STR
+       VRF_CMD_HELP_STR
        "Rescan PIM OIL (output interface list)\n")
 {
-       pim_scan_oil();
+       int idx = 2;
+       struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
+
+       if (!vrf)
+               return CMD_WARNING;
+
+       pim_scan_oil(vrf->info);
 
        return CMD_SUCCESS;
 }
 
 DEFUN (show_ip_igmp_interface,
        show_ip_igmp_interface_cmd,
-       "show ip igmp interface [detail|WORD] [json]",
+       "show ip igmp [vrf NAME] interface [detail|WORD] [json]",
        SHOW_STR
        IP_STR
        IGMP_STR
+       VRF_CMD_HELP_STR
        "IGMP interface information\n"
        "Detailed output\n"
        "interface name\n"
-       "JavaScript Object Notation\n")
+       JSON_STR)
 {
+       int idx = 2;
+       struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
        u_char uj = use_json(argc, argv);
-       int idx = 0;
+
+       if (!vrf)
+               return CMD_WARNING;
 
        if (argv_find(argv, argc, "detail", &idx)
            || argv_find(argv, argc, "WORD", &idx))
-               igmp_show_interfaces_single(vty, argv[idx]->arg, uj);
+               igmp_show_interfaces_single(vrf->info, vty, argv[idx]->arg, uj);
        else
-               igmp_show_interfaces(vty, uj);
+               igmp_show_interfaces(vrf->info, vty, uj);
+
+       return CMD_SUCCESS;
+}
+
+DEFUN (show_ip_igmp_interface_vrf_all,
+       show_ip_igmp_interface_vrf_all_cmd,
+       "show ip igmp vrf all interface [detail|WORD] [json]",
+       SHOW_STR
+       IP_STR
+       IGMP_STR
+       VRF_CMD_HELP_STR
+       "IGMP interface information\n"
+       "Detailed output\n"
+       "interface name\n"
+       JSON_STR)
+{
+       int idx = 2;
+       u_char uj = use_json(argc, argv);
+       struct vrf *vrf;
+       bool first = true;
+
+       if (uj)
+               vty_out(vty, "{ ");
+       RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name)
+       {
+               if (uj) {
+                       if (!first)
+                               vty_out(vty, ", ");
+                       vty_out(vty, " \"%s\": ", vrf->name);
+                       first = false;
+               } else
+                       vty_out(vty, "VRF: %s\n", vrf->name);
+               if (argv_find(argv, argc, "detail", &idx)
+                   || argv_find(argv, argc, "WORD", &idx))
+                       igmp_show_interfaces_single(vrf->info, vty,
+                                                   argv[idx]->arg, uj);
+               else
+                       igmp_show_interfaces(vrf->info, vty, uj);
+       }
+       if (uj)
+               vty_out(vty, "}\n");
 
        return CMD_SUCCESS;
 }
 
 DEFUN (show_ip_igmp_join,
        show_ip_igmp_join_cmd,
-       "show ip igmp join",
+       "show ip igmp [vrf NAME] join",
        SHOW_STR
        IP_STR
        IGMP_STR
+       VRF_CMD_HELP_STR
        "IGMP static join information\n")
 {
-       igmp_show_interface_join(vty);
+       int idx = 2;
+       struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
+
+       if (!vrf)
+               return CMD_WARNING;
+
+       igmp_show_interface_join(vrf->info, vty);
+
+       return CMD_SUCCESS;
+}
+
+DEFUN (show_ip_igmp_join_vrf_all,
+       show_ip_igmp_join_vrf_all_cmd,
+       "show ip igmp vrf all join",
+       SHOW_STR
+       IP_STR
+       IGMP_STR
+       VRF_CMD_HELP_STR
+       "IGMP static join information\n")
+{
+       u_char uj = use_json(argc, argv);
+       struct vrf *vrf;
+       bool first = true;
+
+       if (uj)
+               vty_out(vty, "{ ");
+       RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name)
+       {
+               if (uj) {
+                       if (!first)
+                               vty_out(vty, ", ");
+                       vty_out(vty, " \"%s\": ", vrf->name);
+                       first = false;
+               } else
+                       vty_out(vty, "VRF: %s\n", vrf->name);
+               igmp_show_interface_join(vrf->info, vty);
+       }
+       if (uj)
+               vty_out(vty, "}\n");
 
        return CMD_SUCCESS;
 }
 
 DEFUN (show_ip_igmp_groups,
        show_ip_igmp_groups_cmd,
-       "show ip igmp groups [json]",
+       "show ip igmp [vrf NAME] groups [json]",
        SHOW_STR
        IP_STR
        IGMP_STR
+       VRF_CMD_HELP_STR
        IGMP_GROUP_STR
-       "JavaScript Object Notation\n")
+       JSON_STR)
 {
+       int idx = 2;
+       struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
        u_char uj = use_json(argc, argv);
-       igmp_show_groups(vty, uj);
+
+       if (!vrf)
+               return CMD_WARNING;
+
+       igmp_show_groups(vrf->info, vty, uj);
+
+       return CMD_SUCCESS;
+}
+
+DEFUN (show_ip_igmp_groups_vrf_all,
+       show_ip_igmp_groups_vrf_all_cmd,
+       "show ip igmp vrf all groups [json]",
+       SHOW_STR
+       IP_STR
+       IGMP_STR
+       VRF_CMD_HELP_STR
+       IGMP_GROUP_STR
+       JSON_STR)
+{
+       u_char uj = use_json(argc, argv);
+       struct vrf *vrf;
+       bool first = true;
+
+       if (uj)
+               vty_out(vty, "{ ");
+       RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name)
+       {
+               if (uj) {
+                       if (!first)
+                               vty_out(vty, ", ");
+                       vty_out(vty, " \"%s\": ", vrf->name);
+                       first = false;
+               } else
+                       vty_out(vty, "VRF: %s\n", vrf->name);
+               igmp_show_groups(vrf->info, vty, uj);
+       }
+       if (uj)
+               vty_out(vty, "}\n");
 
        return CMD_SUCCESS;
 }
 
 DEFUN (show_ip_igmp_groups_retransmissions,
        show_ip_igmp_groups_retransmissions_cmd,
-       "show ip igmp groups retransmissions",
+       "show ip igmp [vrf NAME] groups retransmissions",
        SHOW_STR
        IP_STR
        IGMP_STR
+       VRF_CMD_HELP_STR
        IGMP_GROUP_STR
        "IGMP group retransmissions\n")
 {
-       igmp_show_group_retransmission(vty);
+       int idx = 2;
+       struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
+
+       if (!vrf)
+               return CMD_WARNING;
+
+       igmp_show_group_retransmission(vrf->info, vty);
 
        return CMD_SUCCESS;
 }
 
 DEFUN (show_ip_igmp_sources,
        show_ip_igmp_sources_cmd,
-       "show ip igmp sources",
+       "show ip igmp [vrf NAME] sources",
        SHOW_STR
        IP_STR
        IGMP_STR
+       VRF_CMD_HELP_STR
        IGMP_SOURCE_STR)
 {
-       igmp_show_sources(vty);
+       int idx = 2;
+       struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
+
+       if (!vrf)
+               return CMD_WARNING;
+
+       igmp_show_sources(vrf->info, vty);
 
        return CMD_SUCCESS;
 }
 
 DEFUN (show_ip_igmp_sources_retransmissions,
        show_ip_igmp_sources_retransmissions_cmd,
-       "show ip igmp sources retransmissions",
+       "show ip igmp [vrf NAME] sources retransmissions",
        SHOW_STR
        IP_STR
        IGMP_STR
+       VRF_CMD_HELP_STR
        IGMP_SOURCE_STR
        "IGMP source retransmissions\n")
 {
-       igmp_show_source_retransmission(vty);
+       int idx = 2;
+       struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
+
+       if (!vrf)
+               return CMD_WARNING;
+
+       igmp_show_source_retransmission(vrf->info, vty);
 
        return CMD_SUCCESS;
 }
 
 DEFUN (show_ip_pim_assert,
        show_ip_pim_assert_cmd,
-       "show ip pim assert",
+       "show ip pim [vrf NAME] assert",
        SHOW_STR
        IP_STR
        PIM_STR
+       VRF_CMD_HELP_STR
        "PIM interface assert\n")
 {
-       pim_show_assert(vty);
+       int idx = 2;
+       struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
+
+       if (!vrf)
+               return CMD_WARNING;
+
+       pim_show_assert(vrf->info, vty);
 
        return CMD_SUCCESS;
 }
 
 DEFUN (show_ip_pim_assert_internal,
        show_ip_pim_assert_internal_cmd,
-       "show ip pim assert-internal",
+       "show ip pim [vrf NAME] assert-internal",
        SHOW_STR
        IP_STR
        PIM_STR
+       VRF_CMD_HELP_STR
        "PIM interface internal assert state\n")
 {
-       pim_show_assert_internal(vty);
+       int idx = 2;
+       struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
+
+       if (!vrf)
+               return CMD_WARNING;
+
+       pim_show_assert_internal(vrf->info, vty);
 
        return CMD_SUCCESS;
 }
 
 DEFUN (show_ip_pim_assert_metric,
        show_ip_pim_assert_metric_cmd,
-       "show ip pim assert-metric",
+       "show ip pim [vrf NAME] assert-metric",
        SHOW_STR
        IP_STR
        PIM_STR
+       VRF_CMD_HELP_STR
        "PIM interface assert metric\n")
 {
-       pim_show_assert_metric(vty);
+       int idx = 2;
+       struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
+
+       if (!vrf)
+               return CMD_WARNING;
+
+       pim_show_assert_metric(vrf->info, vty);
 
        return CMD_SUCCESS;
 }
 
 DEFUN (show_ip_pim_assert_winner_metric,
        show_ip_pim_assert_winner_metric_cmd,
-       "show ip pim assert-winner-metric",
+       "show ip pim [vrf NAME] assert-winner-metric",
        SHOW_STR
        IP_STR
        PIM_STR
+       VRF_CMD_HELP_STR
        "PIM interface assert winner metric\n")
 {
-       pim_show_assert_winner_metric(vty);
+       int idx = 2;
+       struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
+
+       if (!vrf)
+               return CMD_WARNING;
+
+       pim_show_assert_winner_metric(vrf->info, vty);
 
        return CMD_SUCCESS;
 }
 
 DEFUN (show_ip_pim_interface,
        show_ip_pim_interface_cmd,
-       "show ip pim interface [detail|WORD] [json]",
+       "show ip pim [vrf NAME] interface [detail|WORD] [json]",
        SHOW_STR
        IP_STR
        PIM_STR
+       VRF_CMD_HELP_STR
        "PIM interface information\n"
        "Detailed output\n"
        "interface name\n"
-       "JavaScript Object Notation\n")
+       JSON_STR)
 {
+       int idx = 2;
+       struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
        u_char uj = use_json(argc, argv);
-       int idx = 0;
+
+       if (!vrf)
+               return CMD_WARNING;
 
        if (argv_find(argv, argc, "WORD", &idx)
            || argv_find(argv, argc, "detail", &idx))
-               pim_show_interfaces_single(vty, argv[idx]->arg, uj);
-
+               pim_show_interfaces_single(vrf->info, vty, argv[idx]->arg, uj);
        else
-               pim_show_interfaces(vty, uj);
+               pim_show_interfaces(vrf->info, vty, uj);
+
+       return CMD_SUCCESS;
+}
+
+DEFUN (show_ip_pim_interface_vrf_all,
+       show_ip_pim_interface_vrf_all_cmd,
+       "show ip pim vrf all interface [detail|WORD] [json]",
+       SHOW_STR
+       IP_STR
+       PIM_STR
+       VRF_CMD_HELP_STR
+       "PIM interface information\n"
+       "Detailed output\n"
+       "interface name\n"
+       JSON_STR)
+{
+       int idx = 6;
+       u_char uj = use_json(argc, argv);
+       struct vrf *vrf;
+       bool first = true;
+
+       if (uj)
+               vty_out(vty, "{ ");
+       RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name)
+       {
+               if (uj) {
+                       if (!first)
+                               vty_out(vty, ", ");
+                       vty_out(vty, " \"%s\": ", vrf->name);
+                       first = false;
+               } else
+                       vty_out(vty, "VRF: %s\n", vrf->name);
+               if (argv_find(argv, argc, "WORD", &idx)
+                   || argv_find(argv, argc, "detail", &idx))
+                       pim_show_interfaces_single(vrf->info, vty,
+                                                  argv[idx]->arg, uj);
+               else
+                       pim_show_interfaces(vrf->info, vty, uj);
+       }
+       if (uj)
+               vty_out(vty, "}\n");
 
        return CMD_SUCCESS;
 }
 
 DEFUN (show_ip_pim_join,
        show_ip_pim_join_cmd,
-       "show ip pim join [json]",
+       "show ip pim [vrf NAME] join [json]",
        SHOW_STR
        IP_STR
        PIM_STR
+       VRF_CMD_HELP_STR
        "PIM interface join information\n"
        JSON_STR)
 {
+       int idx = 2;
+       struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
        u_char uj = use_json(argc, argv);
-       pim_show_join(vty, uj);
+
+       if (!vrf)
+               return CMD_WARNING;
+
+       pim_show_join(vrf->info, vty, uj);
 
        return CMD_SUCCESS;
 }
 
+DEFUN (show_ip_pim_join_vrf_all,
+       show_ip_pim_join_vrf_all_cmd,
+       "show ip pim vrf all join [json]",
+       SHOW_STR
+       IP_STR
+       PIM_STR
+       VRF_CMD_HELP_STR
+       "PIM interface join information\n"
+       JSON_STR)
+{
+       u_char uj = use_json(argc, argv);
+       struct vrf *vrf;
+       bool first = true;
+
+       if (uj)
+               vty_out(vty, "{ ");
+       RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name)
+       {
+               if (uj) {
+                       if (!first)
+                               vty_out(vty, ", ");
+                       vty_out(vty, " \"%s\": ", vrf->name);
+                       first = false;
+               } else
+                       vty_out(vty, "VRF: %s\n", vrf->name);
+               pim_show_join(vrf->info, vty, uj);
+       }
+       if (uj)
+               vty_out(vty, "}\n");
+
+       return CMD_WARNING;
+}
+
 DEFUN (show_ip_pim_local_membership,
        show_ip_pim_local_membership_cmd,
-       "show ip pim local-membership [json]",
+       "show ip pim [vrf NAME] local-membership [json]",
        SHOW_STR
        IP_STR
        PIM_STR
+       VRF_CMD_HELP_STR
        "PIM interface local-membership\n"
        JSON_STR)
 {
+       int idx = 2;
+       struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
        u_char uj = use_json(argc, argv);
-       pim_show_membership(vty, uj);
+
+       if (!vrf)
+               return CMD_WARNING;
+
+       pim_show_membership(vrf->info, vty, uj);
 
        return CMD_SUCCESS;
 }
 
 DEFUN (show_ip_pim_neighbor,
        show_ip_pim_neighbor_cmd,
-       "show ip pim neighbor [detail|WORD] [json]",
+       "show ip pim [vrf NAME] neighbor [detail|WORD] [json]",
        SHOW_STR
        IP_STR
        PIM_STR
+       VRF_CMD_HELP_STR
        "PIM neighbor information\n"
        "Detailed output\n"
        "Name of interface or neighbor\n"
-       "JavaScript Object Notation\n")
+       JSON_STR)
 {
+       int idx = 2;
+       struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
        u_char uj = use_json(argc, argv);
-       int idx = 0;
+
+       if (!vrf)
+               return CMD_WARNING;
 
        if (argv_find(argv, argc, "detail", &idx)
            || argv_find(argv, argc, "WORD", &idx))
-               pim_show_neighbors_single(vty, argv[idx]->arg, uj);
+               pim_show_neighbors_single(vrf->info, vty, argv[idx]->arg, uj);
        else
-               pim_show_neighbors(vty, uj);
+               pim_show_neighbors(vrf->info, vty, uj);
+
+       return CMD_SUCCESS;
+}
+
+DEFUN (show_ip_pim_neighbor_vrf_all,
+       show_ip_pim_neighbor_vrf_all_cmd,
+       "show ip pim vrf all neighbor [detail|WORD] [json]",
+       SHOW_STR
+       IP_STR
+       PIM_STR
+       VRF_CMD_HELP_STR
+       "PIM neighbor information\n"
+       "Detailed output\n"
+       "Name of interface or neighbor\n"
+       JSON_STR)
+{
+       int idx = 2;
+       u_char uj = use_json(argc, argv);
+       struct vrf *vrf;
+       bool first = true;
+
+       if (uj)
+               vty_out(vty, "{ ");
+       RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name)
+       {
+               if (uj) {
+                       if (!first)
+                               vty_out(vty, ", ");
+                       vty_out(vty, " \"%s\": ", vrf->name);
+                       first = false;
+               } else
+                       vty_out(vty, "VRF: %s\n", vrf->name);
+               if (argv_find(argv, argc, "detail", &idx)
+                   || argv_find(argv, argc, "WORD", &idx))
+                       pim_show_neighbors_single(vrf->info, vty,
+                                                 argv[idx]->arg, uj);
+               else
+                       pim_show_neighbors(vrf->info, vty, uj);
+       }
+       if (uj)
+               vty_out(vty, "}\n");
 
        return CMD_SUCCESS;
 }
 
 DEFUN (show_ip_pim_secondary,
        show_ip_pim_secondary_cmd,
-       "show ip pim secondary",
+       "show ip pim [vrf NAME] secondary",
        SHOW_STR
        IP_STR
        PIM_STR
+       VRF_CMD_HELP_STR
        "PIM neighbor addresses\n")
 {
-       pim_show_neighbors_secondary(vty);
+       int idx = 2;
+       struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
+
+       if (!vrf)
+               return CMD_WARNING;
+
+       pim_show_neighbors_secondary(vrf->info, vty);
 
        return CMD_SUCCESS;
 }
 
 DEFUN (show_ip_pim_state,
        show_ip_pim_state_cmd,
-       "show ip pim state [A.B.C.D [A.B.C.D]] [json]",
+       "show ip pim [vrf NAME] state [A.B.C.D [A.B.C.D]] [json]",
        SHOW_STR
        IP_STR
        PIM_STR
+       VRF_CMD_HELP_STR
        "PIM state information\n"
        "Unicast or Multicast address\n"
        "Multicast address\n"
-       "JavaScript Object Notation\n")
+       JSON_STR)
 {
        const char *src_or_group = NULL;
        const char *group = NULL;
+       int idx = 2;
+       struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
        u_char uj = use_json(argc, argv);
+
+       if (!vrf)
+               return CMD_WARNING;
+
        if (uj)
                argc--;
 
-       if (argc == 6) {
-               src_or_group = argv[4]->arg;
-               group = argv[5]->arg;
-       } else if (argc == 5)
-               src_or_group = argv[4]->arg;
+       if (argv_find(argv, argc, "A.B.C.D", &idx)) {
+               src_or_group = argv[idx]->arg;
+               if (idx + 1 < argc)
+                       group = argv[idx + 1]->arg;
+       }
+
+       pim_show_state(vrf->info, vty, src_or_group, group, uj);
+
+       return CMD_SUCCESS;
+}
+
+DEFUN (show_ip_pim_state_vrf_all,
+       show_ip_pim_state_vrf_all_cmd,
+       "show ip pim vrf all state [A.B.C.D [A.B.C.D]] [json]",
+       SHOW_STR
+       IP_STR
+       PIM_STR
+       VRF_CMD_HELP_STR
+       "PIM state information\n"
+       "Unicast or Multicast address\n"
+       "Multicast address\n"
+       JSON_STR)
+{
+       const char *src_or_group = NULL;
+       const char *group = NULL;
+       int idx = 2;
+       u_char uj = use_json(argc, argv);
+       struct vrf *vrf;
+       bool first = true;
+
+       if (uj) {
+               vty_out(vty, "{ ");
+               argc--;
+       }
+
+       if (argv_find(argv, argc, "A.B.C.D", &idx)) {
+               src_or_group = argv[idx]->arg;
+               if (idx + 1 < argc)
+                       group = argv[idx + 1]->arg;
+       }
 
-       pim_show_state(vty, src_or_group, group, uj);
+       RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name)
+       {
+               if (uj) {
+                       if (!first)
+                               vty_out(vty, ", ");
+                       vty_out(vty, " \"%s\": ", vrf->name);
+                       first = false;
+               } else
+                       vty_out(vty, "VRF: %s\n", vrf->name);
+               pim_show_state(vrf->info, vty, src_or_group, group, uj);
+       }
+       if (uj)
+               vty_out(vty, "}\n");
 
        return CMD_SUCCESS;
 }
 
 DEFUN (show_ip_pim_upstream,
        show_ip_pim_upstream_cmd,
-       "show ip pim upstream [json]",
+       "show ip pim [vrf NAME] upstream [json]",
+       SHOW_STR
+       IP_STR
+       PIM_STR
+       VRF_CMD_HELP_STR
+       "PIM upstream information\n"
+       JSON_STR)
+{
+       int idx = 2;
+       struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
+       u_char uj = use_json(argc, argv);
+
+       if (!vrf)
+               return CMD_WARNING;
+
+       pim_show_upstream(vrf->info, vty, uj);
+
+       return CMD_SUCCESS;
+}
+
+DEFUN (show_ip_pim_upstream_vrf_all,
+       show_ip_pim_upstream_vrf_all_cmd,
+       "show ip pim vrf all upstream [json]",
        SHOW_STR
        IP_STR
        PIM_STR
+       VRF_CMD_HELP_STR
        "PIM upstream information\n"
-       "JavaScript Object Notation\n")
+       JSON_STR)
 {
        u_char uj = use_json(argc, argv);
-       pim_show_upstream(vty, uj);
+       struct vrf *vrf;
+       bool first = true;
+
+       if (uj)
+               vty_out(vty, "{ ");
+       RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name)
+       {
+               if (uj) {
+                       if (!first)
+                               vty_out(vty, ", ");
+                       vty_out(vty, " \"%s\": ", vrf->name);
+                       first = false;
+               } else
+                       vty_out(vty, "VRF: %s\n", vrf->name);
+               pim_show_upstream(vrf->info, vty, uj);
+       }
 
        return CMD_SUCCESS;
 }
 
 DEFUN (show_ip_pim_upstream_join_desired,
        show_ip_pim_upstream_join_desired_cmd,
-       "show ip pim upstream-join-desired [json]",
+       "show ip pim [vrf NAME] upstream-join-desired [json]",
        SHOW_STR
        IP_STR
        PIM_STR
+       VRF_CMD_HELP_STR
        "PIM upstream join-desired\n"
-       "JavaScript Object Notation\n")
+       JSON_STR)
 {
+       int idx = 2;
+       struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
        u_char uj = use_json(argc, argv);
-       pim_show_join_desired(vty, uj);
+
+       if (!vrf)
+               return CMD_WARNING;
+
+       pim_show_join_desired(vrf->info, vty, uj);
 
        return CMD_SUCCESS;
 }
 
 DEFUN (show_ip_pim_upstream_rpf,
        show_ip_pim_upstream_rpf_cmd,
-       "show ip pim upstream-rpf [json]",
+       "show ip pim [vrf NAME] upstream-rpf [json]",
        SHOW_STR
        IP_STR
        PIM_STR
+       VRF_CMD_HELP_STR
        "PIM upstream source rpf\n"
-       "JavaScript Object Notation\n")
+       JSON_STR)
 {
+       int idx = 2;
+       struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
        u_char uj = use_json(argc, argv);
-       pim_show_upstream_rpf(vty, uj);
+
+       if (!vrf)
+               return CMD_WARNING;
+
+       pim_show_upstream_rpf(vrf->info, vty, uj);
 
        return CMD_SUCCESS;
 }
 
 DEFUN (show_ip_pim_rp,
        show_ip_pim_rp_cmd,
-       "show ip pim rp-info [json]",
+       "show ip pim [vrf NAME] rp-info [json]",
+       SHOW_STR
+       IP_STR
+       PIM_STR
+       VRF_CMD_HELP_STR
+       "PIM RP information\n"
+       JSON_STR)
+{
+       int idx = 2;
+       struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
+       u_char uj = use_json(argc, argv);
+
+       if (!vrf)
+               return CMD_WARNING;
+
+       pim_rp_show_information(vrf->info, vty, uj);
+
+       return CMD_SUCCESS;
+}
+
+DEFUN (show_ip_pim_rp_vrf_all,
+       show_ip_pim_rp_vrf_all_cmd,
+       "show ip pim vrf all rp-info [json]",
        SHOW_STR
        IP_STR
        PIM_STR
+       VRF_CMD_HELP_STR
        "PIM RP information\n"
-       "JavaScript Object Notation\n")
+       JSON_STR)
 {
        u_char uj = use_json(argc, argv);
-       pim_rp_show_information(vty, uj);
+       struct vrf *vrf;
+       bool first = true;
+
+       if (uj)
+               vty_out(vty, "{ ");
+       RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name)
+       {
+               if (uj) {
+                       if (!first)
+                               vty_out(vty, ", ");
+                       vty_out(vty, " \"%s\": ", vrf->name);
+                       first = false;
+               } else
+                       vty_out(vty, "VRF: %s\n", vrf->name);
+               pim_rp_show_information(vrf->info, vty, uj);
+       }
+       if (uj)
+               vty_out(vty, "}\n");
 
        return CMD_SUCCESS;
 }
 
 DEFUN (show_ip_pim_rpf,
        show_ip_pim_rpf_cmd,
-       "show ip pim rpf [json]",
+       "show ip pim [vrf NAME] rpf [json]",
        SHOW_STR
        IP_STR
        PIM_STR
+       VRF_CMD_HELP_STR
        "PIM cached source rpf information\n"
-       "JavaScript Object Notation\n")
+       JSON_STR)
 {
+       int idx = 2;
+       struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
        u_char uj = use_json(argc, argv);
-       pim_show_rpf(vty, uj);
+
+       if (!vrf)
+               return CMD_WARNING;
+
+       pim_show_rpf(vrf->info, vty, uj);
+
+       return CMD_SUCCESS;
+}
+
+DEFUN (show_ip_pim_rpf_vrf_all,
+       show_ip_pim_rpf_vrf_all_cmd,
+       "show ip pim vrf all rpf [json]",
+       SHOW_STR
+       IP_STR
+       PIM_STR
+       VRF_CMD_HELP_STR
+       "PIM cached source rpf information\n"
+       JSON_STR)
+{
+       u_char uj = use_json(argc, argv);
+       struct vrf *vrf;
+       bool first = true;
+
+       if (uj)
+               vty_out(vty, "{ ");
+       RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name)
+       {
+               if (uj) {
+                       if (!first)
+                               vty_out(vty, ", ");
+                       vty_out(vty, " \"%s\": ", vrf->name);
+                       first = false;
+               } else
+                       vty_out(vty, "VRF: %s\n", vrf->name);
+               pim_show_rpf(vrf->info, vty, uj);
+       }
+       if (uj)
+               vty_out(vty, "}\n");
 
        return CMD_SUCCESS;
 }
 
 DEFUN (show_ip_pim_nexthop,
        show_ip_pim_nexthop_cmd,
-       "show ip pim nexthop",
+       "show ip pim [vrf NAME] nexthop",
        SHOW_STR
        IP_STR
        PIM_STR
+       VRF_CMD_HELP_STR
        "PIM cached nexthop rpf information\n")
 {
-       pim_show_nexthop(vty);
+       int idx = 2;
+       struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
+
+       if (!vrf)
+               return CMD_WARNING;
+
+       pim_show_nexthop(vrf->info, vty);
 
        return CMD_SUCCESS;
 }
 
 DEFUN (show_ip_pim_nexthop_lookup,
        show_ip_pim_nexthop_lookup_cmd,
-       "show ip pim nexthop-lookup A.B.C.D A.B.C.D",
+       "show ip pim [vrf NAME] nexthop-lookup A.B.C.D A.B.C.D",
        SHOW_STR
        IP_STR
        PIM_STR
+       VRF_CMD_HELP_STR
        "PIM cached nexthop rpf lookup\n"
        "Source/RP address\n"
        "Multicast Group address\n")
@@ -3559,8 +4228,14 @@ DEFUN (show_ip_pim_nexthop_lookup,
        struct pim_nexthop nexthop;
        char nexthop_addr_str[PREFIX_STRLEN];
        char grp_str[PREFIX_STRLEN];
+       int idx = 2;
+       struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
 
-       addr_str = argv[4]->arg;
+       if (!vrf)
+               return CMD_WARNING;
+
+       argv_find(argv, argc, "A.B.C.D", &idx);
+       addr_str = argv[idx]->arg;
        result = inet_pton(AF_INET, addr_str, &src_addr);
        if (result <= 0) {
                vty_out(vty, "Bad unicast address %s: errno=%d: %s\n", addr_str,
@@ -3574,7 +4249,7 @@ DEFUN (show_ip_pim_nexthop_lookup,
                return CMD_WARNING;
        }
 
-       addr_str1 = argv[5]->arg;
+       addr_str1 = argv[idx + 1]->arg;
        result = inet_pton(AF_INET, addr_str1, &grp_addr);
        if (result <= 0) {
                vty_out(vty, "Bad unicast address %s: errno=%d: %s\n", addr_str,
@@ -3588,7 +4263,8 @@ DEFUN (show_ip_pim_nexthop_lookup,
                return CMD_WARNING;
        }
 
-       if (!pim_rp_set_upstream_addr(&vif_source, src_addr, grp_addr))
+       if (!pim_rp_set_upstream_addr(vrf->info, &vif_source, src_addr,
+                                     grp_addr))
                return CMD_SUCCESS;
 
        memset(&pnc, 0, sizeof(struct pim_nexthop_cache));
@@ -3600,11 +4276,12 @@ DEFUN (show_ip_pim_nexthop_lookup,
        grp.u.prefix4 = grp_addr;
        memset(&nexthop, 0, sizeof(nexthop));
 
-       if ((pim_find_or_track_nexthop(&nht_p, NULL, NULL, &pnc)) == 1) {
-               // Compute PIM RPF using Cached nexthop
-               pim_ecmp_nexthop_search(&pnc, &nexthop, &nht_p, &grp, 0);
-       } else
-               pim_ecmp_nexthop_lookup(&nexthop, vif_source, &nht_p, &grp, 0);
+       if (pim_find_or_track_nexthop(vrf->info, &nht_p, NULL, NULL, &pnc))
+               pim_ecmp_nexthop_search(vrf->info, &pnc, &nexthop, &nht_p, &grp,
+                                       0);
+       else
+               pim_ecmp_nexthop_lookup(vrf->info, &nexthop, vif_source, &nht_p,
+                                       &grp, 0);
 
        pim_addr_dump("<grp?>", &grp, grp_str, sizeof(grp_str));
        pim_addr_dump("<nexthop?>", &nexthop.mrib_nexthop_addr,
@@ -3617,27 +4294,33 @@ DEFUN (show_ip_pim_nexthop_lookup,
 
 DEFUN (show_ip_pim_interface_traffic,
        show_ip_pim_interface_traffic_cmd,
-       "show ip pim interface traffic [WORD] [json]",
+       "show ip pim [vrf NAME] interface traffic [WORD] [json]",
        SHOW_STR
        IP_STR
        PIM_STR
+       VRF_CMD_HELP_STR
        "PIM interface information\n"
        "Protocol Packet counters\n"
        "Interface name\n"
-       "JavaScript Object Notation\n")
+       JSON_STR)
 {
+       int idx = 2;
+       struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
        u_char uj = use_json(argc, argv);
-       int idx = 0;
+
+       if (!vrf)
+               return CMD_WARNING;
 
        if (argv_find(argv, argc, "WORD", &idx))
-               pim_show_interface_traffic_single(vty, argv[idx]->arg, uj);
+               pim_show_interface_traffic_single(vrf->info, vty,
+                                                 argv[idx]->arg, uj);
        else
-               pim_show_interface_traffic(vty, uj);
+               pim_show_interface_traffic(vrf->info, vty, uj);
 
        return CMD_SUCCESS;
 }
 
-static void show_multicast_interfaces(struct vty *vty)
+static void show_multicast_interfaces(struct pim_instance *pim, struct vty *vty)
 {
        struct listnode *node;
        struct interface *ifp;
@@ -3645,9 +4328,9 @@ static void show_multicast_interfaces(struct vty *vty)
        vty_out(vty, "\n");
 
        vty_out(vty,
-               "Interface Address         ifi Vif  PktsIn PktsOut    BytesIn   BytesOut\n");
+               "Interface Address            ifi Vif  PktsIn PktsOut    BytesIn   BytesOut\n");
 
-       for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT), node, ifp)) {
+       for (ALL_LIST_ELEMENTS_RO(vrf_iflist(pim->vrf_id), node, ifp)) {
                struct pim_interface *pim_ifp;
                struct in_addr ifaddr;
                struct sioc_vif_req vreq;
@@ -3660,9 +4343,9 @@ static void show_multicast_interfaces(struct vty *vty)
                memset(&vreq, 0, sizeof(vreq));
                vreq.vifi = pim_ifp->mroute_vif_index;
 
-               if (ioctl(qpim_mroute_socket_fd, SIOCGETVIFCNT, &vreq)) {
+               if (ioctl(pim->mroute_socket, SIOCGETVIFCNT, &vreq)) {
                        zlog_warn(
-                               "ioctl(SIOCGETVIFCNT=%lu) failure for interface %s vif_index=%d: errno=%d: %s\n",
+                               "ioctl(SIOCGETVIFCNT=%lu) failure for interface %s vif_index=%d: errno=%d: %s",
                                (unsigned long)SIOCGETVIFCNT, ifp->name,
                                pim_ifp->mroute_vif_index, errno,
                                safe_strerror(errno));
@@ -3670,7 +4353,7 @@ static void show_multicast_interfaces(struct vty *vty)
 
                ifaddr = pim_ifp->primary_address;
 
-               vty_out(vty, "%-9s %-15s %3d %3d %7lu %7lu %10lu %10lu\n",
+               vty_out(vty, "%-12s %-15s %3d %3d %7lu %7lu %10lu %10lu\n",
                        ifp->name, inet_ntoa(ifaddr), ifp->ifindex,
                        pim_ifp->mroute_vif_index, (unsigned long)vreq.icount,
                        (unsigned long)vreq.ocount, (unsigned long)vreq.ibytes,
@@ -3678,21 +4361,21 @@ static void show_multicast_interfaces(struct vty *vty)
        }
 }
 
-DEFUN (show_ip_multicast,
-       show_ip_multicast_cmd,
-       "show ip multicast",
-       SHOW_STR
-       IP_STR
-       "Multicast global information\n")
+static void pim_cmd_show_ip_multicast_helper(struct pim_instance *pim,
+                                            struct vty *vty)
 {
+       struct vrf *vrf = pim->vrf;
        time_t now = pim_time_monotonic_sec();
-
        char uptime[10];
 
-       vty_out(vty, "Mroute socket descriptor: %d\n", qpim_mroute_socket_fd);
+       pim = vrf->info;
+
+       vty_out(vty, "Mroute socket descriptor:");
+
+       vty_out(vty, " %d(%s)\n", pim->mroute_socket, vrf->name);
 
        pim_time_uptime(uptime, sizeof(uptime),
-                       now - qpim_mroute_socket_creation);
+                       now - pim->mroute_socket_creation);
        vty_out(vty, "Mroute socket uptime: %s\n", uptime);
 
        vty_out(vty, "\n");
@@ -3716,14 +4399,62 @@ DEFUN (show_ip_multicast,
 
        vty_out(vty, "\n");
 
-       show_scan_oil_stats(vty, now);
+       show_scan_oil_stats(pim, vty, now);
+
+       show_multicast_interfaces(pim, vty);
+}
+
+DEFUN (show_ip_multicast,
+       show_ip_multicast_cmd,
+       "show ip multicast [vrf NAME]",
+       SHOW_STR
+       IP_STR
+       VRF_CMD_HELP_STR
+       "Multicast global information\n")
+{
+       int idx = 2;
+       struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
+
+       if (!vrf)
+               return CMD_WARNING;
+
+       pim_cmd_show_ip_multicast_helper(vrf->info, vty);
+
+       return CMD_SUCCESS;
+}
+
+DEFUN (show_ip_multicast_vrf_all,
+       show_ip_multicast_vrf_all_cmd,
+       "show ip multicast vrf all",
+       SHOW_STR
+       IP_STR
+       VRF_CMD_HELP_STR
+       "Multicast global information\n")
+{
+       u_char uj = use_json(argc, argv);
+       struct vrf *vrf;
+       bool first = true;
 
-       show_multicast_interfaces(vty);
+       if (uj)
+               vty_out(vty, "{ ");
+       RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name)
+       {
+               if (uj) {
+                       if (!first)
+                               vty_out(vty, ", ");
+                       vty_out(vty, " \"%s\": ", vrf->name);
+                       first = false;
+               } else
+                       vty_out(vty, "VRF: %s\n", vrf->name);
+               pim_cmd_show_ip_multicast_helper(vrf->info, vty);
+       }
+       if (uj)
+               vty_out(vty, "}\n");
 
        return CMD_SUCCESS;
 }
 
-static void show_mroute(struct vty *vty, u_char uj)
+static void show_mroute(struct pim_instance *pim, struct vty *vty, u_char uj)
 {
        struct listnode *node;
        struct channel_oil *c_oil;
@@ -3754,7 +4485,7 @@ static void show_mroute(struct vty *vty, u_char uj)
        now = pim_time_monotonic_sec();
 
        /* print list of PIM and IGMP routes */
-       for (ALL_LIST_ELEMENTS_RO(pim_channel_oil_list, node, c_oil)) {
+       for (ALL_LIST_ELEMENTS_RO(pim->channel_oil_list, node, c_oil)) {
                found_oif = 0;
                first = 1;
                if (!c_oil->installed && !uj)
@@ -3764,7 +4495,7 @@ static void show_mroute(struct vty *vty, u_char uj)
                               sizeof(grp_str));
                pim_inet4_dump("<source?>", c_oil->oil.mfcc_origin, src_str,
                               sizeof(src_str));
-               ifp_in = pim_if_find_by_vif_index(c_oil->oil.mfcc_parent);
+               ifp_in = pim_if_find_by_vif_index(pim, c_oil->oil.mfcc_parent);
 
                if (ifp_in)
                        strcpy(in_ifname, ifp_in->name);
@@ -3817,7 +4548,7 @@ static void show_mroute(struct vty *vty, u_char uj)
                        if (ttl < 1)
                                continue;
 
-                       ifp_out = pim_if_find_by_vif_index(oif_vif_index);
+                       ifp_out = pim_if_find_by_vif_index(pim, oif_vif_index);
                        pim_time_uptime(
                                oif_uptime, sizeof(oif_uptime),
                                now - c_oil->oif_creation[oif_vif_index]);
@@ -3919,7 +4650,7 @@ static void show_mroute(struct vty *vty, u_char uj)
        }
 
        /* Print list of static routes */
-       for (ALL_LIST_ELEMENTS_RO(qpim_static_route_list, node, s_route)) {
+       for (ALL_LIST_ELEMENTS_RO(pim->static_routes, node, s_route)) {
                first = 1;
 
                if (!s_route->c_oil.installed)
@@ -3929,7 +4660,7 @@ static void show_mroute(struct vty *vty, u_char uj)
                               sizeof(grp_str));
                pim_inet4_dump("<source?>", s_route->source, src_str,
                               sizeof(src_str));
-               ifp_in = pim_if_find_by_vif_index(s_route->iif);
+               ifp_in = pim_if_find_by_vif_index(pim, s_route->iif);
                found_oif = 0;
 
                if (ifp_in)
@@ -3975,7 +4706,7 @@ static void show_mroute(struct vty *vty, u_char uj)
                        if (ttl < 1)
                                continue;
 
-                       ifp_out = pim_if_find_by_vif_index(oif_vif_index);
+                       ifp_out = pim_if_find_by_vif_index(pim, oif_vif_index);
                        pim_time_uptime(
                                oif_uptime, sizeof(oif_uptime),
                                now
@@ -4019,9 +4750,10 @@ static void show_mroute(struct vty *vty, u_char uj)
                                                       json_ifp_out);
                        } else {
                                vty_out(vty,
-                                       "%-15s %-15s %-6s %-10s %-10s %-3d  %8s\n",
+                                       "%-15s %-15s %-6s %-10s %-10s %-3d  %8s %s\n",
                                        src_str, grp_str, proto, in_ifname,
-                                       out_ifname, ttl, oif_uptime);
+                                       out_ifname, ttl, oif_uptime,
+                                       pim->vrf->name);
                                if (first) {
                                        src_str[0] = '\0';
                                        grp_str[0] = '\0';
@@ -4032,9 +4764,10 @@ static void show_mroute(struct vty *vty, u_char uj)
                }
 
                if (!uj && !found_oif) {
-                       vty_out(vty, "%-15s %-15s %-6s %-10s %-10s %-3d  %8s\n",
+                       vty_out(vty,
+                               "%-15s %-15s %-6s %-10s %-10s %-3d  %8s %s\n",
                                src_str, grp_str, proto, in_ifname, "none", 0,
-                               "--:--:--");
+                               "--:--:--", pim->vrf->name);
                }
        }
 
@@ -4047,18 +4780,57 @@ static void show_mroute(struct vty *vty, u_char uj)
 
 DEFUN (show_ip_mroute,
        show_ip_mroute_cmd,
-       "show ip mroute [json]",
+       "show ip mroute [vrf NAME] [json]",
+       SHOW_STR
+       IP_STR
+       MROUTE_STR
+       VRF_CMD_HELP_STR
+       JSON_STR)
+{
+       u_char uj = use_json(argc, argv);
+       int idx = 2;
+       struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
+
+       if (!vrf)
+               return CMD_WARNING;
+
+       show_mroute(vrf->info, vty, uj);
+       return CMD_SUCCESS;
+}
+
+DEFUN (show_ip_mroute_vrf_all,
+       show_ip_mroute_vrf_all_cmd,
+       "show ip mroute vrf all [json]",
        SHOW_STR
        IP_STR
        MROUTE_STR
+       VRF_CMD_HELP_STR
        JSON_STR)
 {
        u_char uj = use_json(argc, argv);
-       show_mroute(vty, uj);
+       struct vrf *vrf;
+       bool first = true;
+
+       if (uj)
+               vty_out(vty, "{ ");
+       RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name)
+       {
+               if (uj) {
+                       if (!first)
+                               vty_out(vty, ", ");
+                       vty_out(vty, " \"%s\": ", vrf->name);
+                       first = false;
+               } else
+                       vty_out(vty, "VRF: %s\n", vrf->name);
+               show_mroute(vrf->info, vty, uj);
+       }
+       if (uj)
+               vty_out(vty, "}\n");
+
        return CMD_SUCCESS;
 }
 
-static void show_mroute_count(struct vty *vty)
+static void show_mroute_count(struct pim_instance *pim, struct vty *vty)
 {
        struct listnode *node;
        struct channel_oil *c_oil;
@@ -4070,7 +4842,7 @@ static void show_mroute_count(struct vty *vty)
                "Source          Group           LastUsed Packets Bytes WrongIf  \n");
 
        /* Print PIM and IGMP route counts */
-       for (ALL_LIST_ELEMENTS_RO(pim_channel_oil_list, node, c_oil)) {
+       for (ALL_LIST_ELEMENTS_RO(pim->channel_oil_list, node, c_oil)) {
                char group_str[INET_ADDRSTRLEN];
                char source_str[INET_ADDRSTRLEN];
 
@@ -4090,8 +4862,7 @@ static void show_mroute_count(struct vty *vty)
                        c_oil->cc.wrong_if);
        }
 
-       /* Print static route counts */
-       for (ALL_LIST_ELEMENTS_RO(qpim_static_route_list, node, s_route)) {
+       for (ALL_LIST_ELEMENTS_RO(pim->static_routes, node, s_route)) {
                char group_str[INET_ADDRSTRLEN];
                char source_str[INET_ADDRSTRLEN];
 
@@ -4114,33 +4885,75 @@ static void show_mroute_count(struct vty *vty)
 
 DEFUN (show_ip_mroute_count,
        show_ip_mroute_count_cmd,
-       "show ip mroute count",
+       "show ip mroute [vrf NAME] count",
        SHOW_STR
        IP_STR
        MROUTE_STR
+       VRF_CMD_HELP_STR
        "Route and packet count data\n")
 {
-       show_mroute_count(vty);
+       int idx = 2;
+       struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
+
+       show_mroute_count(vrf->info, vty);
+       return CMD_SUCCESS;
+}
+
+DEFUN (show_ip_mroute_count_vrf_all,
+       show_ip_mroute_count_vrf_all_cmd,
+       "show ip mroute vrf all count",
+       SHOW_STR
+       IP_STR
+       MROUTE_STR
+       VRF_CMD_HELP_STR
+       "Route and packet count data\n")
+{
+       u_char uj = use_json(argc, argv);
+       struct vrf *vrf;
+       bool first = true;
+
+       if (uj)
+               vty_out(vty, "{ ");
+       RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name)
+       {
+               if (uj) {
+                       if (!first)
+                               vty_out(vty, ", ");
+                       vty_out(vty, " \"%s\": ", vrf->name);
+                       first = false;
+               } else
+                       vty_out(vty, "VRF: %s\n", vrf->name);
+               show_mroute_count(vrf->info, vty);
+       }
+       if (uj)
+               vty_out(vty, "}\n");
+
        return CMD_SUCCESS;
 }
 
 DEFUN (show_ip_rib,
        show_ip_rib_cmd,
-       "show ip rib A.B.C.D",
+       "show ip rib [vrf NAME] A.B.C.D",
        SHOW_STR
        IP_STR
        RIB_STR
+       VRF_CMD_HELP_STR
        "Unicast address\n")
 {
-       int idx_ipv4 = 3;
+       int idx = 2;
+       struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
        struct in_addr addr;
        const char *addr_str;
        struct pim_nexthop nexthop;
        char nexthop_addr_str[PREFIX_STRLEN];
        int result;
 
+       if (!vrf)
+               return CMD_WARNING;
+
        memset(&nexthop, 0, sizeof(nexthop));
-       addr_str = argv[idx_ipv4]->arg;
+       argv_find(argv, argc, "A.B.C.D", &idx);
+       addr_str = argv[idx]->arg;
        result = inet_pton(AF_INET, addr_str, &addr);
        if (result <= 0) {
                vty_out(vty, "Bad unicast address %s: errno=%d: %s\n", addr_str,
@@ -4148,7 +4961,7 @@ DEFUN (show_ip_rib,
                return CMD_WARNING;
        }
 
-       if (pim_nexthop_lookup(&nexthop, addr, 0)) {
+       if (pim_nexthop_lookup(vrf->info, &nexthop, addr, 0)) {
                vty_out(vty,
                        "Failure querying RIB nexthop for unicast address %s\n",
                        addr_str);
@@ -4168,7 +4981,7 @@ DEFUN (show_ip_rib,
        return CMD_SUCCESS;
 }
 
-static void show_ssmpingd(struct vty *vty)
+static void show_ssmpingd(struct pim_instance *pim, struct vty *vty)
 {
        struct listnode *node;
        struct ssmpingd_sock *ss;
@@ -4177,12 +4990,12 @@ static void show_ssmpingd(struct vty *vty)
        vty_out(vty,
                "Source          Socket Address          Port Uptime   Requests\n");
 
-       if (!qpim_ssmpingd_list)
+       if (!pim->ssmpingd_list)
                return;
 
        now = pim_time_monotonic_sec();
 
-       for (ALL_LIST_ELEMENTS_RO(qpim_ssmpingd_list, node, ss)) {
+       for (ALL_LIST_ELEMENTS_RO(pim->ssmpingd_list, node, ss)) {
                char source_str[INET_ADDRSTRLEN];
                char ss_uptime[10];
                struct sockaddr_in bind_addr;
@@ -4212,21 +5025,29 @@ static void show_ssmpingd(struct vty *vty)
 
 DEFUN (show_ip_ssmpingd,
        show_ip_ssmpingd_cmd,
-       "show ip ssmpingd",
+       "show ip ssmpingd [vrf NAME]",
        SHOW_STR
        IP_STR
-       SHOW_SSMPINGD_STR)
+       SHOW_SSMPINGD_STR
+       VRF_CMD_HELP_STR)
 {
-       show_ssmpingd(vty);
+       int idx = 2;
+       struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
+
+       if (!vrf)
+               return CMD_WARNING;
+
+       show_ssmpingd(vrf->info, vty);
        return CMD_SUCCESS;
 }
 
-static int pim_rp_cmd_worker(struct vty *vty, const char *rp, const char *group,
+static int pim_rp_cmd_worker(struct pim_instance *pim, struct vty *vty,
+                            const char *rp, const char *group,
                             const char *plist)
 {
        int result;
 
-       result = pim_rp_new(rp, group, plist);
+       result = pim_rp_new(pim, rp, group, plist);
 
        if (result == PIM_MALLOC_FAIL) {
                vty_out(vty, "%% Out of memory\n");
@@ -4268,26 +5089,27 @@ static int pim_rp_cmd_worker(struct vty *vty, const char *rp, const char *group,
        return CMD_SUCCESS;
 }
 
-static int pim_cmd_spt_switchover(enum pim_spt_switchover spt,
+static int pim_cmd_spt_switchover(struct pim_instance *pim,
+                                 enum pim_spt_switchover spt,
                                  const char *plist)
 {
-       pimg->spt.switchover = spt;
+       pim->spt.switchover = spt;
 
-       switch (pimg->spt.switchover) {
+       switch (pim->spt.switchover) {
        case PIM_SPT_IMMEDIATE:
-               if (pimg->spt.plist)
-                       XFREE(MTYPE_PIM_SPT_PLIST_NAME, pimg->spt.plist);
+               if (pim->spt.plist)
+                       XFREE(MTYPE_PIM_SPT_PLIST_NAME, pim->spt.plist);
 
-               pim_upstream_add_lhr_star_pimreg();
+               pim_upstream_add_lhr_star_pimreg(pim);
                break;
        case PIM_SPT_INFINITY:
-               pim_upstream_remove_lhr_star_pimreg(plist);
+               pim_upstream_remove_lhr_star_pimreg(pim, plist);
 
-               if (pimg->spt.plist)
-                       XFREE(MTYPE_PIM_SPT_PLIST_NAME, pimg->spt.plist);
+               if (pim->spt.plist)
+                       XFREE(MTYPE_PIM_SPT_PLIST_NAME, pim->spt.plist);
 
                if (plist)
-                       pimg->spt.plist =
+                       pim->spt.plist =
                                XSTRDUP(MTYPE_PIM_SPT_PLIST_NAME, plist);
                break;
        }
@@ -4303,7 +5125,8 @@ DEFUN (ip_pim_spt_switchover_infinity,
        "SPT-Switchover\n"
        "Never switch to SPT Tree\n")
 {
-       return pim_cmd_spt_switchover(PIM_SPT_INFINITY, NULL);
+       PIM_DECLVAR_CONTEXT(vrf, pim);
+       return pim_cmd_spt_switchover(pim, PIM_SPT_INFINITY, NULL);
 }
 
 DEFUN (ip_pim_spt_switchover_infinity_plist,
@@ -4316,7 +5139,8 @@ DEFUN (ip_pim_spt_switchover_infinity_plist,
        "Prefix-List to control which groups to switch\n"
        "Prefix-List name\n")
 {
-       return pim_cmd_spt_switchover(PIM_SPT_INFINITY, argv[5]->arg);
+       PIM_DECLVAR_CONTEXT(vrf, pim);
+       return pim_cmd_spt_switchover(pim, PIM_SPT_INFINITY, argv[5]->arg);
 }
 
 DEFUN (no_ip_pim_spt_switchover_infinity,
@@ -4328,7 +5152,8 @@ DEFUN (no_ip_pim_spt_switchover_infinity,
        "SPT_Switchover\n"
        "Never switch to SPT Tree\n")
 {
-       return pim_cmd_spt_switchover(PIM_SPT_IMMEDIATE, NULL);
+       PIM_DECLVAR_CONTEXT(vrf, pim);
+       return pim_cmd_spt_switchover(pim, PIM_SPT_IMMEDIATE, NULL);
 }
 
 DEFUN (no_ip_pim_spt_switchover_infinity_plist,
@@ -4342,7 +5167,8 @@ DEFUN (no_ip_pim_spt_switchover_infinity_plist,
        "Prefix-List to control which groups to switch\n"
        "Prefix-List name\n")
 {
-       return pim_cmd_spt_switchover(PIM_SPT_IMMEDIATE, NULL);
+       PIM_DECLVAR_CONTEXT(vrf, pim);
+       return pim_cmd_spt_switchover(pim, PIM_SPT_IMMEDIATE, NULL);
 }
 
 DEFUN (ip_pim_joinprune_time,
@@ -4353,6 +5179,7 @@ DEFUN (ip_pim_joinprune_time,
        "Join Prune Send Interval\n"
        "Seconds\n")
 {
+       PIM_DECLVAR_CONTEXT(vrf, pim);
        qpim_t_periodic = atoi(argv[3]->arg);
        return CMD_SUCCESS;
 }
@@ -4366,6 +5193,7 @@ DEFUN (no_ip_pim_joinprune_time,
        "Join Prune Send Interval\n"
        "Seconds\n")
 {
+       PIM_DECLVAR_CONTEXT(vrf, pim);
        qpim_t_periodic = PIM_DEFAULT_T_PERIODIC;
        return CMD_SUCCESS;
 }
@@ -4378,6 +5206,7 @@ DEFUN (ip_pim_register_suppress,
        "Register Suppress Timer\n"
        "Seconds\n")
 {
+       PIM_DECLVAR_CONTEXT(vrf, pim);
        qpim_register_suppress_time = atoi(argv[3]->arg);
        return CMD_SUCCESS;
 }
@@ -4391,10 +5220,40 @@ DEFUN (no_ip_pim_register_suppress,
        "Register Suppress Timer\n"
        "Seconds\n")
 {
+       PIM_DECLVAR_CONTEXT(vrf, pim);
        qpim_register_suppress_time = PIM_REGISTER_SUPPRESSION_TIME_DEFAULT;
        return CMD_SUCCESS;
 }
 
+DEFUN (ip_pim_rp_keep_alive,
+       ip_pim_rp_keep_alive_cmd,
+       "ip pim rp keep-alive-timer (31-60000)",
+       IP_STR
+       "pim multicast routing\n"
+       "Rendevous Point\n"
+       "Keep alive Timer\n"
+       "Seconds\n")
+{
+       PIM_DECLVAR_CONTEXT(vrf, pim);
+       pim->rp_keep_alive_time = atoi(argv[4]->arg);
+       return CMD_SUCCESS;
+}
+
+DEFUN (no_ip_pim_rp_keep_alive,
+       no_ip_pim_rp_keep_alive_cmd,
+       "no ip pim rp keep-alive-timer (31-60000)",
+       NO_STR
+       IP_STR
+       "pim multicast routing\n"
+       "Rendevous Point\n"
+       "Keep alive Timer\n"
+       "Seconds\n")
+{
+       PIM_DECLVAR_CONTEXT(vrf, pim);
+       pim->rp_keep_alive_time = PIM_KEEPALIVE_PERIOD;
+       return CMD_SUCCESS;
+}
+
 DEFUN (ip_pim_keep_alive,
        ip_pim_keep_alive_cmd,
        "ip pim keep-alive-timer (31-60000)",
@@ -4403,7 +5262,8 @@ DEFUN (ip_pim_keep_alive,
        "Keep alive Timer\n"
        "Seconds\n")
 {
-       qpim_keep_alive_time = atoi(argv[3]->arg);
+       PIM_DECLVAR_CONTEXT(vrf, pim);
+       pim->keep_alive_time = atoi(argv[3]->arg);
        return CMD_SUCCESS;
 }
 
@@ -4416,7 +5276,8 @@ DEFUN (no_ip_pim_keep_alive,
        "Keep alive Timer\n"
        "Seconds\n")
 {
-       qpim_keep_alive_time = PIM_KEEPALIVE_PERIOD;
+       PIM_DECLVAR_CONTEXT(vrf, pim);
+       pim->keep_alive_time = PIM_KEEPALIVE_PERIOD;
        return CMD_SUCCESS;
 }
 
@@ -4428,6 +5289,7 @@ DEFUN (ip_pim_packets,
        "packets to process at one time per fd\n"
        "Number of packets\n")
 {
+       PIM_DECLVAR_CONTEXT(vrf, pim);
        qpim_packet_process = atoi(argv[3]->arg);
        return CMD_SUCCESS;
 }
@@ -4441,6 +5303,7 @@ DEFUN (no_ip_pim_packets,
        "packets to process at one time per fd\n"
        "Number of packets\n")
 {
+       PIM_DECLVAR_CONTEXT(vrf, pim);
        qpim_packet_process = PIM_DEFAULT_PACKET_PROCESS;
        return CMD_SUCCESS;
 }
@@ -4452,7 +5315,8 @@ DEFUN (ip_pim_v6_secondary,
        "pim multicast routing\n"
        "Send v6 secondary addresses\n")
 {
-       pimg->send_v6_secondary = 1;
+       PIM_DECLVAR_CONTEXT(vrf, pim);
+       pim->send_v6_secondary = 1;
 
        return CMD_SUCCESS;
 }
@@ -4465,7 +5329,8 @@ DEFUN (no_ip_pim_v6_secondary,
        "pim multicast routing\n"
        "Send v6 secondary addresses\n")
 {
-       pimg->send_v6_secondary = 0;
+       PIM_DECLVAR_CONTEXT(vrf, pim);
+       pim->send_v6_secondary = 0;
 
        return CMD_SUCCESS;
 }
@@ -4479,12 +5344,14 @@ DEFUN (ip_pim_rp,
        "ip address of RP\n"
        "Group Address range to cover\n")
 {
+       PIM_DECLVAR_CONTEXT(vrf, pim);
        int idx_ipv4 = 3;
 
        if (argc == (idx_ipv4 + 1))
-               return pim_rp_cmd_worker(vty, argv[idx_ipv4]->arg, NULL, NULL);
+               return pim_rp_cmd_worker(pim, vty, argv[idx_ipv4]->arg, NULL,
+                                        NULL);
        else
-               return pim_rp_cmd_worker(vty, argv[idx_ipv4]->arg,
+               return pim_rp_cmd_worker(pim, vty, argv[idx_ipv4]->arg,
                                         argv[idx_ipv4 + 1]->arg, NULL);
 }
 
@@ -4498,13 +5365,15 @@ DEFUN (ip_pim_rp_prefix_list,
        "group prefix-list filter\n"
        "Name of a prefix-list\n")
 {
-       return pim_rp_cmd_worker(vty, argv[3]->arg, NULL, argv[5]->arg);
+       PIM_DECLVAR_CONTEXT(vrf, pim);
+       return pim_rp_cmd_worker(pim, vty, argv[3]->arg, NULL, argv[5]->arg);
 }
 
-static int pim_no_rp_cmd_worker(struct vty *vty, const char *rp,
-                               const char *group, const char *plist)
+static int pim_no_rp_cmd_worker(struct pim_instance *pim, struct vty *vty,
+                               const char *rp, const char *group,
+                               const char *plist)
 {
-       int result = pim_rp_del(rp, group, plist);
+       int result = pim_rp_del(pim, rp, group, plist);
 
        if (result == PIM_GROUP_BAD_ADDRESS) {
                vty_out(vty, "%% Bad group address specified: %s\n", group);
@@ -4534,13 +5403,14 @@ DEFUN (no_ip_pim_rp,
        "ip address of RP\n"
        "Group Address range to cover\n")
 {
+       PIM_DECLVAR_CONTEXT(vrf, pim);
        int idx_ipv4 = 4, idx_group = 0;
 
        if (argv_find(argv, argc, "A.B.C.D/M", &idx_group))
-               return pim_no_rp_cmd_worker(vty, argv[idx_ipv4]->arg,
+               return pim_no_rp_cmd_worker(pim, vty, argv[idx_ipv4]->arg,
                                            argv[idx_group]->arg, NULL);
        else
-               return pim_no_rp_cmd_worker(vty, argv[idx_ipv4]->arg, NULL,
+               return pim_no_rp_cmd_worker(pim, vty, argv[idx_ipv4]->arg, NULL,
                                            NULL);
 }
 
@@ -4555,12 +5425,14 @@ DEFUN (no_ip_pim_rp_prefix_list,
        "group prefix-list filter\n"
        "Name of a prefix-list\n")
 {
-       return pim_no_rp_cmd_worker(vty, argv[4]->arg, NULL, argv[6]->arg);
+       PIM_DECLVAR_CONTEXT(vrf, pim);
+       return pim_no_rp_cmd_worker(pim, vty, argv[4]->arg, NULL, argv[6]->arg);
 }
 
-static int pim_ssm_cmd_worker(struct vty *vty, const char *plist)
+static int pim_ssm_cmd_worker(struct pim_instance *pim, struct vty *vty,
+                             const char *plist)
 {
-       int result = pim_ssm_range_set(VRF_DEFAULT, plist);
+       int result = pim_ssm_range_set(pim, pim->vrf_id, plist);
 
        if (result == PIM_SSM_ERR_NONE)
                return CMD_SUCCESS;
@@ -4588,7 +5460,8 @@ DEFUN (ip_pim_ssm_prefix_list,
        "group range prefix-list filter\n"
        "Name of a prefix-list\n")
 {
-       return pim_ssm_cmd_worker(vty, argv[0]->arg);
+       PIM_DECLVAR_CONTEXT(vrf, pim);
+       return pim_ssm_cmd_worker(pim, vty, argv[4]->arg);
 }
 
 DEFUN (no_ip_pim_ssm_prefix_list,
@@ -4600,7 +5473,8 @@ DEFUN (no_ip_pim_ssm_prefix_list,
        "Source Specific Multicast\n"
        "group range prefix-list filter\n")
 {
-       return pim_ssm_cmd_worker(vty, NULL);
+       PIM_DECLVAR_CONTEXT(vrf, pim);
+       return pim_ssm_cmd_worker(pim, vty, NULL);
 }
 
 DEFUN (no_ip_pim_ssm_prefix_list_name,
@@ -4613,19 +5487,21 @@ DEFUN (no_ip_pim_ssm_prefix_list_name,
        "group range prefix-list filter\n"
        "Name of a prefix-list\n")
 {
-       struct pim_ssm *ssm = pimg->ssm_info;
+       PIM_DECLVAR_CONTEXT(vrf, pim);
+       struct pim_ssm *ssm = pim->ssm_info;
 
-       if (ssm->plist_name && !strcmp(ssm->plist_name, argv[0]->arg))
-               return pim_ssm_cmd_worker(vty, NULL);
+       if (ssm->plist_name && !strcmp(ssm->plist_name, argv[5]->arg))
+               return pim_ssm_cmd_worker(pim, vty, NULL);
 
-       vty_out(vty, "%% pim ssm prefix-list %s doesn't exist\n", argv[0]->arg);
+       vty_out(vty, "%% pim ssm prefix-list %s doesn't exist\n", argv[5]->arg);
 
        return CMD_WARNING_CONFIG_FAILED;
 }
 
-static void ip_pim_ssm_show_group_range(struct vty *vty, u_char uj)
+static void ip_pim_ssm_show_group_range(struct pim_instance *pim,
+                                       struct vty *vty, u_char uj)
 {
-       struct pim_ssm *ssm = pimg->ssm_info;
+       struct pim_ssm *ssm = pim->ssm_info;
        const char *range_str =
                ssm->plist_name ? ssm->plist_name : PIM_SSM_STANDARD_RANGE;
 
@@ -4642,20 +5518,28 @@ static void ip_pim_ssm_show_group_range(struct vty *vty, u_char uj)
 
 DEFUN (show_ip_pim_ssm_range,
        show_ip_pim_ssm_range_cmd,
-       "show ip pim group-type [json]",
+       "show ip pim [vrf NAME] group-type [json]",
        SHOW_STR
        IP_STR
        PIM_STR
+       VRF_CMD_HELP_STR
        "PIM group type\n"
-       "JavaScript Object Notation\n")
+       JSON_STR)
 {
+       int idx = 2;
+       struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
        u_char uj = use_json(argc, argv);
-       ip_pim_ssm_show_group_range(vty, uj);
+
+       if (!vrf)
+               return CMD_WARNING;
+
+       ip_pim_ssm_show_group_range(vrf->info, vty, uj);
 
        return CMD_SUCCESS;
 }
 
-static void ip_pim_ssm_show_group_type(struct vty *vty, u_char uj,
+static void ip_pim_ssm_show_group_type(struct pim_instance *pim,
+                                      struct vty *vty, u_char uj,
                                       const char *group)
 {
        struct in_addr group_addr;
@@ -4667,7 +5551,8 @@ static void ip_pim_ssm_show_group_type(struct vty *vty, u_char uj,
                type_str = "invalid";
        else {
                if (pim_is_group_224_4(group_addr))
-                       type_str = pim_is_grp_ssm(group_addr) ? "SSM" : "ASM";
+                       type_str =
+                               pim_is_grp_ssm(pim, group_addr) ? "SSM" : "ASM";
                else
                        type_str = "not-multicast";
        }
@@ -4685,16 +5570,24 @@ static void ip_pim_ssm_show_group_type(struct vty *vty, u_char uj,
 
 DEFUN (show_ip_pim_group_type,
        show_ip_pim_group_type_cmd,
-       "show ip pim group-type A.B.C.D [json]",
+       "show ip pim [vrf NAME] group-type A.B.C.D [json]",
        SHOW_STR
        IP_STR
        PIM_STR
+       VRF_CMD_HELP_STR
        "multicast group type\n"
        "group address\n"
-       "JavaScript Object Notation\n")
+       JSON_STR)
 {
+       int idx = 2;
+       struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
        u_char uj = use_json(argc, argv);
-       ip_pim_ssm_show_group_type(vty, uj, argv[0]->arg);
+
+       if (!vrf)
+               return CMD_WARNING;
+
+       argv_find(argv, argc, "A.B.C.D", &idx);
+       ip_pim_ssm_show_group_type(vrf->info, vty, uj, argv[idx]->arg);
 
        return CMD_SUCCESS;
 }
@@ -4727,6 +5620,7 @@ DEFUN (ip_ssmpingd,
        CONF_SSMPINGD_STR
        "Source address\n")
 {
+       PIM_DECLVAR_CONTEXT(vrf, pim);
        int idx_ipv4 = 2;
        int result;
        struct in_addr source_addr;
@@ -4739,7 +5633,7 @@ DEFUN (ip_ssmpingd,
                return CMD_WARNING_CONFIG_FAILED;
        }
 
-       result = pim_ssmpingd_start(source_addr);
+       result = pim_ssmpingd_start(pim, source_addr);
        if (result) {
                vty_out(vty, "%% Failure starting ssmpingd for source %s: %d\n",
                        source_str, result);
@@ -4757,6 +5651,7 @@ DEFUN (no_ip_ssmpingd,
        CONF_SSMPINGD_STR
        "Source address\n")
 {
+       PIM_DECLVAR_CONTEXT(vrf, pim);
        int idx_ipv4 = 3;
        int result;
        struct in_addr source_addr;
@@ -4769,7 +5664,7 @@ DEFUN (no_ip_ssmpingd,
                return CMD_WARNING_CONFIG_FAILED;
        }
 
-       result = pim_ssmpingd_stop(source_addr);
+       result = pim_ssmpingd_stop(pim, source_addr);
        if (result) {
                vty_out(vty, "%% Failure stopping ssmpingd for source %s: %d\n",
                        source_str, result);
@@ -4786,6 +5681,7 @@ DEFUN (ip_pim_ecmp,
        "pim multicast routing\n"
        "Enable PIM ECMP \n")
 {
+       PIM_DECLVAR_CONTEXT(vrf, pim);
        qpim_ecmp_enable = 1;
 
        return CMD_SUCCESS;
@@ -4799,6 +5695,7 @@ DEFUN (no_ip_pim_ecmp,
        "pim multicast routing\n"
        "Disable PIM ECMP \n")
 {
+       PIM_DECLVAR_CONTEXT(vrf, pim);
        qpim_ecmp_enable = 0;
 
        return CMD_SUCCESS;
@@ -4812,6 +5709,7 @@ DEFUN (ip_pim_ecmp_rebalance,
        "Enable PIM ECMP \n"
        "Enable PIM ECMP Rebalance\n")
 {
+       PIM_DECLVAR_CONTEXT(vrf, pim);
        qpim_ecmp_enable = 1;
        qpim_ecmp_rebalance_enable = 1;
 
@@ -4827,6 +5725,7 @@ DEFUN (no_ip_pim_ecmp_rebalance,
        "Disable PIM ECMP \n"
        "Disable PIM ECMP Rebalance\n")
 {
+       PIM_DECLVAR_CONTEXT(vrf, pim);
        qpim_ecmp_rebalance_enable = 0;
 
        return CMD_SUCCESS;
@@ -5496,13 +6395,17 @@ DEFUN (interface_ip_pim_sm,
        PIM_STR
        IFACE_PIM_SM_STR)
 {
+       struct pim_interface *pim_ifp;
+
        VTY_DECLVAR_CONTEXT(interface, ifp);
        if (!pim_cmd_interface_add(ifp)) {
                vty_out(vty, "Could not enable PIM SM on interface\n");
                return CMD_WARNING_CONFIG_FAILED;
        }
 
-       pim_if_create_pimreg();
+       pim_ifp = ifp->info;
+
+       pim_if_create_pimreg(pim_ifp->pim);
 
        return CMD_SUCCESS;
 }
@@ -5575,6 +6478,8 @@ DEFUN (interface_ip_mroute,
        "Group address\n")
 {
        VTY_DECLVAR_CONTEXT(interface, iif);
+       struct pim_interface *pim_ifp;
+       struct pim_instance *pim;
        int idx_interface = 2;
        int idx_ipv4 = 3;
        struct interface *oif;
@@ -5584,11 +6489,14 @@ DEFUN (interface_ip_mroute,
        struct in_addr src_addr;
        int result;
 
+       pim_ifp = iif->info;
+       pim = pim_ifp->pim;
+
        oifname = argv[idx_interface]->arg;
-       oif = if_lookup_by_name(oifname, VRF_DEFAULT);
+       oif = if_lookup_by_name(oifname, pim->vrf_id);
        if (!oif) {
                vty_out(vty, "No such interface name %s\n", oifname);
-               return CMD_WARNING_CONFIG_FAILED;
+               return CMD_WARNING;
        }
 
        grp_str = argv[idx_ipv4]->arg;
@@ -5596,14 +6504,14 @@ DEFUN (interface_ip_mroute,
        if (result <= 0) {
                vty_out(vty, "Bad group address %s: errno=%d: %s\n", grp_str,
                        errno, safe_strerror(errno));
-               return CMD_WARNING_CONFIG_FAILED;
+               return CMD_WARNING;
        }
 
        src_addr.s_addr = INADDR_ANY;
 
-       if (pim_static_add(iif, oif, grp_addr, src_addr)) {
+       if (pim_static_add(pim, iif, oif, grp_addr, src_addr)) {
                vty_out(vty, "Failed to add route\n");
-               return CMD_WARNING_CONFIG_FAILED;
+               return CMD_WARNING;
        }
 
        return CMD_SUCCESS;
@@ -5619,6 +6527,8 @@ DEFUN (interface_ip_mroute_source,
        "Source address\n")
 {
        VTY_DECLVAR_CONTEXT(interface, iif);
+       struct pim_interface *pim_ifp;
+       struct pim_instance *pim;
        int idx_interface = 2;
        int idx_ipv4 = 3;
        int idx_ipv4_2 = 4;
@@ -5630,11 +6540,14 @@ DEFUN (interface_ip_mroute_source,
        struct in_addr src_addr;
        int result;
 
+       pim_ifp = iif->info;
+       pim = pim_ifp->pim;
+
        oifname = argv[idx_interface]->arg;
-       oif = if_lookup_by_name(oifname, VRF_DEFAULT);
+       oif = if_lookup_by_name(oifname, pim->vrf_id);
        if (!oif) {
                vty_out(vty, "No such interface name %s\n", oifname);
-               return CMD_WARNING_CONFIG_FAILED;
+               return CMD_WARNING;
        }
 
        grp_str = argv[idx_ipv4]->arg;
@@ -5642,7 +6555,7 @@ DEFUN (interface_ip_mroute_source,
        if (result <= 0) {
                vty_out(vty, "Bad group address %s: errno=%d: %s\n", grp_str,
                        errno, safe_strerror(errno));
-               return CMD_WARNING_CONFIG_FAILED;
+               return CMD_WARNING;
        }
 
        src_str = argv[idx_ipv4_2]->arg;
@@ -5650,12 +6563,12 @@ DEFUN (interface_ip_mroute_source,
        if (result <= 0) {
                vty_out(vty, "Bad source address %s: errno=%d: %s\n", src_str,
                        errno, safe_strerror(errno));
-               return CMD_WARNING_CONFIG_FAILED;
+               return CMD_WARNING;
        }
 
-       if (pim_static_add(iif, oif, grp_addr, src_addr)) {
+       if (pim_static_add(pim, iif, oif, grp_addr, src_addr)) {
                vty_out(vty, "Failed to add route\n");
-               return CMD_WARNING_CONFIG_FAILED;
+               return CMD_WARNING;
        }
 
        return CMD_SUCCESS;
@@ -5671,6 +6584,8 @@ DEFUN (interface_no_ip_mroute,
        "Group Address\n")
 {
        VTY_DECLVAR_CONTEXT(interface, iif);
+       struct pim_interface *pim_ifp;
+       struct pim_instance *pim;
        int idx_interface = 3;
        int idx_ipv4 = 4;
        struct interface *oif;
@@ -5680,11 +6595,14 @@ DEFUN (interface_no_ip_mroute,
        struct in_addr src_addr;
        int result;
 
+       pim_ifp = iif->info;
+       pim = pim_ifp->pim;
+
        oifname = argv[idx_interface]->arg;
-       oif = if_lookup_by_name(oifname, VRF_DEFAULT);
+       oif = if_lookup_by_name(oifname, pim->vrf_id);
        if (!oif) {
                vty_out(vty, "No such interface name %s\n", oifname);
-               return CMD_WARNING_CONFIG_FAILED;
+               return CMD_WARNING;
        }
 
        grp_str = argv[idx_ipv4]->arg;
@@ -5692,14 +6610,14 @@ DEFUN (interface_no_ip_mroute,
        if (result <= 0) {
                vty_out(vty, "Bad group address %s: errno=%d: %s\n", grp_str,
                        errno, safe_strerror(errno));
-               return CMD_WARNING_CONFIG_FAILED;
+               return CMD_WARNING;
        }
 
        src_addr.s_addr = INADDR_ANY;
 
-       if (pim_static_del(iif, oif, grp_addr, src_addr)) {
+       if (pim_static_del(pim, iif, oif, grp_addr, src_addr)) {
                vty_out(vty, "Failed to remove route\n");
-               return CMD_WARNING_CONFIG_FAILED;
+               return CMD_WARNING;
        }
 
        return CMD_SUCCESS;
@@ -5716,6 +6634,8 @@ DEFUN (interface_no_ip_mroute_source,
        "Source Address\n")
 {
        VTY_DECLVAR_CONTEXT(interface, iif);
+       struct pim_interface *pim_ifp;
+       struct pim_instance *pim;
        int idx_interface = 3;
        int idx_ipv4 = 4;
        int idx_ipv4_2 = 5;
@@ -5727,11 +6647,14 @@ DEFUN (interface_no_ip_mroute_source,
        struct in_addr src_addr;
        int result;
 
+       pim_ifp = iif->info;
+       pim = pim_ifp->pim;
+
        oifname = argv[idx_interface]->arg;
-       oif = if_lookup_by_name(oifname, VRF_DEFAULT);
+       oif = if_lookup_by_name(oifname, pim->vrf_id);
        if (!oif) {
                vty_out(vty, "No such interface name %s\n", oifname);
-               return CMD_WARNING_CONFIG_FAILED;
+               return CMD_WARNING;
        }
 
        grp_str = argv[idx_ipv4]->arg;
@@ -5739,7 +6662,7 @@ DEFUN (interface_no_ip_mroute_source,
        if (result <= 0) {
                vty_out(vty, "Bad group address %s: errno=%d: %s\n", grp_str,
                        errno, safe_strerror(errno));
-               return CMD_WARNING_CONFIG_FAILED;
+               return CMD_WARNING;
        }
 
        src_str = argv[idx_ipv4_2]->arg;
@@ -5747,12 +6670,12 @@ DEFUN (interface_no_ip_mroute_source,
        if (result <= 0) {
                vty_out(vty, "Bad source address %s: errno=%d: %s\n", src_str,
                        errno, safe_strerror(errno));
-               return CMD_WARNING_CONFIG_FAILED;
+               return CMD_WARNING;
        }
 
-       if (pim_static_del(iif, oif, grp_addr, src_addr)) {
+       if (pim_static_del(pim, iif, oif, grp_addr, src_addr)) {
                vty_out(vty, "Failed to remove route\n");
-               return CMD_WARNING_CONFIG_FAILED;
+               return CMD_WARNING;
        }
 
        return CMD_SUCCESS;
@@ -5789,7 +6712,6 @@ DEFUN (interface_ip_pim_hello,
        return CMD_SUCCESS;
 }
 
-
 DEFUN (interface_no_ip_pim_hello,
        interface_no_ip_pim_hello_cmd,
        "no ip pim hello [(1-180) (1-180)]",
@@ -6011,6 +6933,28 @@ DEFUN (no_debug_pim,
        return CMD_SUCCESS;
 }
 
+DEFUN (debug_pim_nht,
+       debug_pim_nht_cmd,
+       "debug pim nht",
+       DEBUG_STR
+       DEBUG_PIM_STR
+       "Nexthop Tracking\n")
+{
+       PIM_DO_DEBUG_PIM_NHT;
+       return CMD_SUCCESS;
+}
+
+DEFUN (no_debug_pim_nht,
+       no_debug_pim_nht_cmd,
+       "no debug pim nht",
+       NO_STR
+       DEBUG_STR
+       DEBUG_PIM_STR
+       "Nexthop Tracking\n")
+{
+       PIM_DONT_DEBUG_PIM_NHT;
+       return CMD_SUCCESS;
+}
 
 DEFUN (debug_pim_events,
        debug_pim_events_cmd,
@@ -6115,7 +7059,6 @@ DEFUN (no_debug_pim_packetdump_send,
        return CMD_SUCCESS;
 }
 
-
 DEFUN (debug_pim_packetdump_recv,
        debug_pim_packetdump_recv_cmd,
        "debug pim packet-dump receive",
@@ -6141,7 +7084,6 @@ DEFUN (no_debug_pim_packetdump_recv,
        return CMD_SUCCESS;
 }
 
-
 DEFUN (debug_pim_trace,
        debug_pim_trace_cmd,
        "debug pim trace",
@@ -6153,6 +7095,18 @@ DEFUN (debug_pim_trace,
        return CMD_SUCCESS;
 }
 
+DEFUN (debug_pim_trace_detail,
+       debug_pim_trace_detail_cmd,
+       "debug pim trace detail",
+       DEBUG_STR
+       DEBUG_PIM_STR
+       DEBUG_PIM_TRACE_STR
+       "Detailed Information\n")
+{
+       PIM_DO_DEBUG_PIM_TRACE_DETAIL;
+       return CMD_SUCCESS;
+}
+
 DEFUN (no_debug_pim_trace,
        no_debug_pim_trace_cmd,
        "no debug pim trace",
@@ -6165,6 +7119,18 @@ DEFUN (no_debug_pim_trace,
        return CMD_SUCCESS;
 }
 
+DEFUN (no_debug_pim_trace_detail,
+       no_debug_pim_trace_detail_cmd,
+       "no debug pim trace detail",
+       NO_STR
+       DEBUG_STR
+       DEBUG_PIM_STR
+       DEBUG_PIM_TRACE_STR
+       "Detailed Information\n")
+{
+       PIM_DONT_DEBUG_PIM_TRACE_DETAIL;
+       return CMD_SUCCESS;
+}
 
 DEFUN (debug_ssmpingd,
        debug_ssmpingd_cmd,
@@ -6187,7 +7153,6 @@ DEFUN (no_debug_ssmpingd,
        return CMD_SUCCESS;
 }
 
-
 DEFUN (debug_pim_zebra,
        debug_pim_zebra_cmd,
        "debug pim zebra",
@@ -6211,7 +7176,6 @@ DEFUN (no_debug_pim_zebra,
        return CMD_SUCCESS;
 }
 
-
 DEFUN (debug_msdp,
        debug_msdp_cmd,
        "debug msdp",
@@ -6435,8 +7399,8 @@ ALIAS(no_ip_pim_bfd, no_ip_pim_bfd_param_cmd,
       "Required min receive interval\n"
       "Desired min transmit interval\n")
 
-static int ip_msdp_peer_cmd_worker(struct vty *vty, const char *peer,
-                                  const char *local)
+static int ip_msdp_peer_cmd_worker(struct pim_instance *pim, struct vty *vty,
+                                  const char *peer, const char *local)
 {
        enum pim_msdp_err result;
        struct in_addr peer_addr;
@@ -6456,7 +7420,7 @@ static int ip_msdp_peer_cmd_worker(struct vty *vty, const char *peer,
                return CMD_WARNING_CONFIG_FAILED;
        }
 
-       result = pim_msdp_peer_add(peer_addr, local_addr, "default",
+       result = pim_msdp_peer_add(pim, peer_addr, local_addr, "default",
                                   NULL /* mp_p */);
        switch (result) {
        case PIM_MSDP_ERR_NONE:
@@ -6487,10 +7451,12 @@ DEFUN_HIDDEN (ip_msdp_peer,
        "Source address for TCP connection\n"
        "local ip address\n")
 {
-       return ip_msdp_peer_cmd_worker(vty, argv[3]->arg, argv[5]->arg);
+       PIM_DECLVAR_CONTEXT(vrf, pim);
+       return ip_msdp_peer_cmd_worker(pim, vty, argv[3]->arg, argv[5]->arg);
 }
 
-static int ip_no_msdp_peer_cmd_worker(struct vty *vty, const char *peer)
+static int ip_no_msdp_peer_cmd_worker(struct pim_instance *pim, struct vty *vty,
+                                     const char *peer)
 {
        enum pim_msdp_err result;
        struct in_addr peer_addr;
@@ -6502,7 +7468,7 @@ static int ip_no_msdp_peer_cmd_worker(struct vty *vty, const char *peer)
                return CMD_WARNING_CONFIG_FAILED;
        }
 
-       result = pim_msdp_peer_del(peer_addr);
+       result = pim_msdp_peer_del(pim, peer_addr);
        switch (result) {
        case PIM_MSDP_ERR_NONE:
                break;
@@ -6525,10 +7491,12 @@ DEFUN_HIDDEN (no_ip_msdp_peer,
        "Delete MSDP peer\n"
        "peer ip address\n")
 {
-       return ip_no_msdp_peer_cmd_worker(vty, argv[4]->arg);
+       PIM_DECLVAR_CONTEXT(vrf, pim);
+       return ip_no_msdp_peer_cmd_worker(pim, vty, argv[4]->arg);
 }
 
-static int ip_msdp_mesh_group_member_cmd_worker(struct vty *vty, const char *mg,
+static int ip_msdp_mesh_group_member_cmd_worker(struct pim_instance *pim,
+                                               struct vty *vty, const char *mg,
                                                const char *mbr)
 {
        enum pim_msdp_err result;
@@ -6541,7 +7509,7 @@ static int ip_msdp_mesh_group_member_cmd_worker(struct vty *vty, const char *mg,
                return CMD_WARNING_CONFIG_FAILED;
        }
 
-       result = pim_msdp_mg_mbr_add(mg, mbr_ip);
+       result = pim_msdp_mg_mbr_add(pim, mg, mbr_ip);
        switch (result) {
        case PIM_MSDP_ERR_NONE:
                break;
@@ -6571,11 +7539,13 @@ DEFUN (ip_msdp_mesh_group_member,
        "mesh group member\n"
        "peer ip address\n")
 {
-       return ip_msdp_mesh_group_member_cmd_worker(vty, argv[3]->arg,
+       PIM_DECLVAR_CONTEXT(vrf, pim);
+       return ip_msdp_mesh_group_member_cmd_worker(pim, vty, argv[3]->arg,
                                                    argv[5]->arg);
 }
 
-static int ip_no_msdp_mesh_group_member_cmd_worker(struct vty *vty,
+static int ip_no_msdp_mesh_group_member_cmd_worker(struct pim_instance *pim,
+                                                  struct vty *vty,
                                                   const char *mg,
                                                   const char *mbr)
 {
@@ -6589,7 +7559,7 @@ static int ip_no_msdp_mesh_group_member_cmd_worker(struct vty *vty,
                return CMD_WARNING_CONFIG_FAILED;
        }
 
-       result = pim_msdp_mg_mbr_del(mg, mbr_ip);
+       result = pim_msdp_mg_mbr_del(pim, mg, mbr_ip);
        switch (result) {
        case PIM_MSDP_ERR_NONE:
                break;
@@ -6616,11 +7586,13 @@ DEFUN (no_ip_msdp_mesh_group_member,
        "mesh group member\n"
        "peer ip address\n")
 {
-       return ip_no_msdp_mesh_group_member_cmd_worker(vty, argv[4]->arg,
+       PIM_DECLVAR_CONTEXT(vrf, pim);
+       return ip_no_msdp_mesh_group_member_cmd_worker(pim, vty, argv[4]->arg,
                                                       argv[6]->arg);
 }
 
-static int ip_msdp_mesh_group_source_cmd_worker(struct vty *vty, const char *mg,
+static int ip_msdp_mesh_group_source_cmd_worker(struct pim_instance *pim,
+                                               struct vty *vty, const char *mg,
                                                const char *src)
 {
        enum pim_msdp_err result;
@@ -6633,7 +7605,7 @@ static int ip_msdp_mesh_group_source_cmd_worker(struct vty *vty, const char *mg,
                return CMD_WARNING_CONFIG_FAILED;
        }
 
-       result = pim_msdp_mg_src_add(mg, src_ip);
+       result = pim_msdp_mg_src_add(pim, mg, src_ip);
        switch (result) {
        case PIM_MSDP_ERR_NONE:
                break;
@@ -6661,16 +7633,18 @@ DEFUN (ip_msdp_mesh_group_source,
        "mesh group local address\n"
        "source ip address for the TCP connection\n")
 {
-       return ip_msdp_mesh_group_source_cmd_worker(vty, argv[3]->arg,
+       PIM_DECLVAR_CONTEXT(vrf, pim);
+       return ip_msdp_mesh_group_source_cmd_worker(pim, vty, argv[3]->arg,
                                                    argv[5]->arg);
 }
 
-static int ip_no_msdp_mesh_group_source_cmd_worker(struct vty *vty,
+static int ip_no_msdp_mesh_group_source_cmd_worker(struct pim_instance *pim,
+                                                  struct vty *vty,
                                                   const char *mg)
 {
        enum pim_msdp_err result;
 
-       result = pim_msdp_mg_src_del(mg);
+       result = pim_msdp_mg_src_del(pim, mg);
        switch (result) {
        case PIM_MSDP_ERR_NONE:
                break;
@@ -6684,11 +7658,12 @@ static int ip_no_msdp_mesh_group_source_cmd_worker(struct vty *vty,
        return result ? CMD_WARNING_CONFIG_FAILED : CMD_SUCCESS;
 }
 
-static int ip_no_msdp_mesh_group_cmd_worker(struct vty *vty, const char *mg)
+static int ip_no_msdp_mesh_group_cmd_worker(struct pim_instance *pim,
+                                           struct vty *vty, const char *mg)
 {
        enum pim_msdp_err result;
 
-       result = pim_msdp_mg_del(mg);
+       result = pim_msdp_mg_del(pim, mg);
        switch (result) {
        case PIM_MSDP_ERR_NONE:
                break;
@@ -6713,10 +7688,11 @@ DEFUN (no_ip_msdp_mesh_group_source,
        "mesh group source\n"
        "mesh group local address\n")
 {
+       PIM_DECLVAR_CONTEXT(vrf, pim);
        if (argc == 7)
-               return ip_no_msdp_mesh_group_cmd_worker(vty, argv[6]->arg);
+               return ip_no_msdp_mesh_group_cmd_worker(pim, vty, argv[6]->arg);
        else
-               return ip_no_msdp_mesh_group_source_cmd_worker(vty,
+               return ip_no_msdp_mesh_group_source_cmd_worker(pim, vty,
                                                               argv[4]->arg);
 }
 
@@ -6729,11 +7705,12 @@ static void print_empty_json_obj(struct vty *vty)
        json_object_free(json);
 }
 
-static void ip_msdp_show_mesh_group(struct vty *vty, u_char uj)
+static void ip_msdp_show_mesh_group(struct pim_instance *pim, struct vty *vty,
+                                   u_char uj)
 {
        struct listnode *mbrnode;
        struct pim_msdp_mg_mbr *mbr;
-       struct pim_msdp_mg *mg = msdp->mg;
+       struct pim_msdp_mg *mg = pim->msdp.mg;
        char mbr_str[INET_ADDRSTRLEN];
        char src_str[INET_ADDRSTRLEN];
        char state_str[PIM_MSDP_STATE_STRLEN];
@@ -6798,20 +7775,61 @@ static void ip_msdp_show_mesh_group(struct vty *vty, u_char uj)
 
 DEFUN (show_ip_msdp_mesh_group,
        show_ip_msdp_mesh_group_cmd,
-       "show ip msdp mesh-group [json]",
+       "show ip msdp [vrf NAME] mesh-group [json]",
+       SHOW_STR
+       IP_STR
+       MSDP_STR
+       VRF_CMD_HELP_STR
+       "MSDP mesh-group information\n"
+       JSON_STR)
+{
+       u_char uj = use_json(argc, argv);
+       int idx = 2;
+       struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
+
+       if (!vrf)
+               return CMD_WARNING;
+
+       ip_msdp_show_mesh_group(vrf->info, vty, uj);
+
+       return CMD_SUCCESS;
+}
+
+DEFUN (show_ip_msdp_mesh_group_vrf_all,
+       show_ip_msdp_mesh_group_vrf_all_cmd,
+       "show ip msdp vrf all mesh-group [json]",
        SHOW_STR
        IP_STR
        MSDP_STR
+       VRF_CMD_HELP_STR
        "MSDP mesh-group information\n"
-       "JavaScript Object Notation\n")
+       JSON_STR)
 {
        u_char uj = use_json(argc, argv);
-       ip_msdp_show_mesh_group(vty, uj);
+       struct vrf *vrf;
+       bool first = true;
+
+       if (uj)
+               vty_out(vty, "{ ");
+       RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name)
+       {
+               if (uj) {
+                       if (!first)
+                               vty_out(vty, ", ");
+                       vty_out(vty, " \"%s\": ", vrf->name);
+                       first = false;
+               } else
+                       vty_out(vty, "VRF: %s\n", vrf->name);
+               ip_msdp_show_mesh_group(vrf->info, vty, uj);
+       }
+       if (uj)
+               vty_out(vty, "}\n");
 
        return CMD_SUCCESS;
 }
 
-static void ip_msdp_show_peers(struct vty *vty, u_char uj)
+static void ip_msdp_show_peers(struct pim_instance *pim, struct vty *vty,
+                              u_char uj)
 {
        struct listnode *mpnode;
        struct pim_msdp_peer *mp;
@@ -6831,7 +7849,7 @@ static void ip_msdp_show_peers(struct vty *vty, u_char uj)
                        "Peer                       Local        State    Uptime   SaCnt\n");
        }
 
-       for (ALL_LIST_ELEMENTS_RO(msdp->peer_list, mpnode, mp)) {
+       for (ALL_LIST_ELEMENTS_RO(pim->msdp.peer_list, mpnode, mp)) {
                if (mp->state == PIM_MSDP_ESTABLISHED) {
                        now = pim_time_monotonic_sec();
                        pim_time_uptime(timebuf, sizeof(timebuf),
@@ -6864,8 +7882,8 @@ static void ip_msdp_show_peers(struct vty *vty, u_char uj)
        }
 }
 
-static void ip_msdp_show_peers_detail(struct vty *vty, const char *peer,
-                                     u_char uj)
+static void ip_msdp_show_peers_detail(struct pim_instance *pim, struct vty *vty,
+                                     const char *peer, u_char uj)
 {
        struct listnode *mpnode;
        struct pim_msdp_peer *mp;
@@ -6884,7 +7902,7 @@ static void ip_msdp_show_peers_detail(struct vty *vty, const char *peer,
                json = json_object_new_object();
        }
 
-       for (ALL_LIST_ELEMENTS_RO(msdp->peer_list, mpnode, mp)) {
+       for (ALL_LIST_ELEMENTS_RO(pim->msdp.peer_list, mpnode, mp)) {
                pim_inet4_dump("<peer?>", mp->peer, peer_str, sizeof(peer_str));
                if (strcmp(peer, "detail") && strcmp(peer, peer_str))
                        continue;
@@ -6971,28 +7989,81 @@ static void ip_msdp_show_peers_detail(struct vty *vty, const char *peer,
 
 DEFUN (show_ip_msdp_peer_detail,
        show_ip_msdp_peer_detail_cmd,
-       "show ip msdp peer [detail|A.B.C.D] [json]",
+       "show ip msdp [vrf NAME] peer [detail|A.B.C.D] [json]",
        SHOW_STR
        IP_STR
        MSDP_STR
+       VRF_CMD_HELP_STR
        "MSDP peer information\n"
        "Detailed output\n"
        "peer ip address\n"
-       "JavaScript Object Notation\n")
+       JSON_STR)
 {
        u_char uj = use_json(argc, argv);
-       if (uj)
-               argc--;
+       int idx = 2;
+       struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
+
+       if (!vrf)
+               return CMD_WARNING;
+
+       char *arg = NULL;
 
-       if (argc > 4)
-               ip_msdp_show_peers_detail(vty, argv[4]->arg, uj);
+       if (argv_find(argv, argc, "detail", &idx))
+               arg = argv[idx]->text;
+       else if (argv_find(argv, argc, "A.B.C.D", &idx))
+               arg = argv[idx]->arg;
+
+       if (arg)
+               ip_msdp_show_peers_detail(vrf->info, vty, argv[idx]->arg, uj);
        else
-               ip_msdp_show_peers(vty, uj);
+               ip_msdp_show_peers(vrf->info, vty, uj);
+
+       return CMD_SUCCESS;
+}
+
+DEFUN (show_ip_msdp_peer_detail_vrf_all,
+       show_ip_msdp_peer_detail_vrf_all_cmd,
+       "show ip msdp vrf all peer [detail|A.B.C.D] [json]",
+       SHOW_STR
+       IP_STR
+       MSDP_STR
+       VRF_CMD_HELP_STR
+       "MSDP peer information\n"
+       "Detailed output\n"
+       "peer ip address\n"
+       JSON_STR)
+{
+       int idx = 2;
+       u_char uj = use_json(argc, argv);
+       struct vrf *vrf;
+       bool first = true;
+
+       if (uj)
+               vty_out(vty, "{ ");
+       RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name)
+       {
+               if (uj) {
+                       if (!first)
+                               vty_out(vty, ", ");
+                       vty_out(vty, " \"%s\": ", vrf->name);
+                       first = false;
+               } else
+                       vty_out(vty, "VRF: %s\n", vrf->name);
+               if (argv_find(argv, argc, "detail", &idx)
+                   || argv_find(argv, argc, "A.B.C.D", &idx))
+                       ip_msdp_show_peers_detail(vrf->info, vty,
+                                                 argv[idx]->arg, uj);
+               else
+                       ip_msdp_show_peers(vrf->info, vty, uj);
+       }
+       if (uj)
+               vty_out(vty, "}\n");
 
        return CMD_SUCCESS;
 }
 
-static void ip_msdp_show_sa(struct vty *vty, u_char uj)
+static void ip_msdp_show_sa(struct pim_instance *pim, struct vty *vty,
+                           u_char uj)
 {
        struct listnode *sanode;
        struct pim_msdp_sa *sa;
@@ -7014,7 +8085,7 @@ static void ip_msdp_show_sa(struct vty *vty, u_char uj)
                        "Source                     Group               RP  Local  SPT    Uptime\n");
        }
 
-       for (ALL_LIST_ELEMENTS_RO(msdp->sa_list, sanode, sa)) {
+       for (ALL_LIST_ELEMENTS_RO(pim->msdp.sa_list, sanode, sa)) {
                now = pim_time_monotonic_sec();
                pim_time_uptime(timebuf, sizeof(timebuf), now - sa->uptime);
                pim_inet4_dump("<src?>", sa->sg.src, src_str, sizeof(src_str));
@@ -7059,7 +8130,6 @@ static void ip_msdp_show_sa(struct vty *vty, u_char uj)
                }
        }
 
-
        if (uj) {
                vty_out(vty, "%s\n", json_object_to_json_string_ext(
                                             json, JSON_C_TO_STRING_PRETTY));
@@ -7133,7 +8203,8 @@ static void ip_msdp_show_sa_entry_detail(struct pim_msdp_sa *sa,
        }
 }
 
-static void ip_msdp_show_sa_detail(struct vty *vty, u_char uj)
+static void ip_msdp_show_sa_detail(struct pim_instance *pim, struct vty *vty,
+                                  u_char uj)
 {
        struct listnode *sanode;
        struct pim_msdp_sa *sa;
@@ -7145,7 +8216,7 @@ static void ip_msdp_show_sa_detail(struct vty *vty, u_char uj)
                json = json_object_new_object();
        }
 
-       for (ALL_LIST_ELEMENTS_RO(msdp->sa_list, sanode, sa)) {
+       for (ALL_LIST_ELEMENTS_RO(pim->msdp.sa_list, sanode, sa)) {
                pim_inet4_dump("<src?>", sa->sg.src, src_str, sizeof(src_str));
                pim_inet4_dump("<grp?>", sa->sg.grp, grp_str, sizeof(grp_str));
                ip_msdp_show_sa_entry_detail(sa, src_str, grp_str, vty, uj,
@@ -7161,21 +8232,63 @@ static void ip_msdp_show_sa_detail(struct vty *vty, u_char uj)
 
 DEFUN (show_ip_msdp_sa_detail,
        show_ip_msdp_sa_detail_cmd,
-       "show ip msdp sa detail [json]",
+       "show ip msdp [vrf NAME] sa detail [json]",
+       SHOW_STR
+       IP_STR
+       MSDP_STR
+       VRF_CMD_HELP_STR
+       "MSDP active-source information\n"
+       "Detailed output\n"
+       JSON_STR)
+{
+       u_char uj = use_json(argc, argv);
+       int idx = 2;
+       struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
+
+       if (!vrf)
+               return CMD_WARNING;
+
+       ip_msdp_show_sa_detail(vrf->info, vty, uj);
+
+       return CMD_SUCCESS;
+}
+
+DEFUN (show_ip_msdp_sa_detail_vrf_all,
+       show_ip_msdp_sa_detail_vrf_all_cmd,
+       "show ip msdp vrf all sa detail [json]",
        SHOW_STR
        IP_STR
        MSDP_STR
+       VRF_CMD_HELP_STR
        "MSDP active-source information\n"
        "Detailed output\n"
-       "JavaScript Object Notation\n")
+       JSON_STR)
 {
        u_char uj = use_json(argc, argv);
-       ip_msdp_show_sa_detail(vty, uj);
+       struct vrf *vrf;
+       bool first = true;
+
+       if (uj)
+               vty_out(vty, "{ ");
+       RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name)
+       {
+               if (uj) {
+                       if (!first)
+                               vty_out(vty, ", ");
+                       vty_out(vty, " \"%s\": ", vrf->name);
+                       first = false;
+               } else
+                       vty_out(vty, "VRF: %s\n", vrf->name);
+               ip_msdp_show_sa_detail(vrf->info, vty, uj);
+       }
+       if (uj)
+               vty_out(vty, "}\n");
 
        return CMD_SUCCESS;
 }
 
-static void ip_msdp_show_sa_addr(struct vty *vty, const char *addr, u_char uj)
+static void ip_msdp_show_sa_addr(struct pim_instance *pim, struct vty *vty,
+                                const char *addr, u_char uj)
 {
        struct listnode *sanode;
        struct pim_msdp_sa *sa;
@@ -7187,7 +8300,7 @@ static void ip_msdp_show_sa_addr(struct vty *vty, const char *addr, u_char uj)
                json = json_object_new_object();
        }
 
-       for (ALL_LIST_ELEMENTS_RO(msdp->sa_list, sanode, sa)) {
+       for (ALL_LIST_ELEMENTS_RO(pim->msdp.sa_list, sanode, sa)) {
                pim_inet4_dump("<src?>", sa->sg.src, src_str, sizeof(src_str));
                pim_inet4_dump("<grp?>", sa->sg.grp, grp_str, sizeof(grp_str));
                if (!strcmp(addr, src_str) || !strcmp(addr, grp_str)) {
@@ -7203,8 +8316,8 @@ static void ip_msdp_show_sa_addr(struct vty *vty, const char *addr, u_char uj)
        }
 }
 
-static void ip_msdp_show_sa_sg(struct vty *vty, const char *src,
-                              const char *grp, u_char uj)
+static void ip_msdp_show_sa_sg(struct pim_instance *pim, struct vty *vty,
+                              const char *src, const char *grp, u_char uj)
 {
        struct listnode *sanode;
        struct pim_msdp_sa *sa;
@@ -7216,7 +8329,7 @@ static void ip_msdp_show_sa_sg(struct vty *vty, const char *src,
                json = json_object_new_object();
        }
 
-       for (ALL_LIST_ELEMENTS_RO(msdp->sa_list, sanode, sa)) {
+       for (ALL_LIST_ELEMENTS_RO(pim->msdp.sa_list, sanode, sa)) {
                pim_inet4_dump("<src?>", sa->sg.src, src_str, sizeof(src_str));
                pim_inet4_dump("<grp?>", sa->sg.grp, grp_str, sizeof(grp_str));
                if (!strcmp(src, src_str) && !strcmp(grp, grp_str)) {
@@ -7234,18 +8347,25 @@ static void ip_msdp_show_sa_sg(struct vty *vty, const char *src,
 
 DEFUN (show_ip_msdp_sa_sg,
        show_ip_msdp_sa_sg_cmd,
-       "show ip msdp sa [A.B.C.D [A.B.C.D]] [json]",
+       "show ip msdp [vrf NAME] sa [A.B.C.D [A.B.C.D]] [json]",
        SHOW_STR
        IP_STR
        MSDP_STR
+       VRF_CMD_HELP_STR
        "MSDP active-source information\n"
        "source or group ip\n"
        "group ip\n"
-       "JavaScript Object Notation\n")
+       JSON_STR)
 {
        u_char uj = use_json(argc, argv);
+       struct vrf *vrf;
+       int idx = 2;
+
+       vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
+
+       if (!vrf)
+               return CMD_WARNING;
 
-       int idx = 0;
        char *src_ip = argv_find(argv, argc, "A.B.C.D", &idx) ? argv[idx++]->arg
                                                              : NULL;
        char *grp_ip = idx < argc && argv_find(argv, argc, "A.B.C.D", &idx)
@@ -7253,16 +8373,16 @@ DEFUN (show_ip_msdp_sa_sg,
                               : NULL;
 
        if (src_ip && grp_ip)
-               ip_msdp_show_sa_sg(vty, src_ip, grp_ip, uj);
+               ip_msdp_show_sa_sg(vrf->info, vty, src_ip, grp_ip, uj);
        else if (src_ip)
-               ip_msdp_show_sa_addr(vty, src_ip, uj);
+               ip_msdp_show_sa_addr(vrf->info, vty, src_ip, uj);
        else
-               ip_msdp_show_sa(vty, uj);
+               ip_msdp_show_sa(vrf->info, vty, uj);
 
        return CMD_SUCCESS;
 }
 
-void pim_cmd_init()
+void pim_cmd_init(void)
 {
        install_node(&pim_global_node, pim_global_config_write); /* PIM_NODE */
        install_node(&interface_node,
@@ -7274,35 +8394,68 @@ void pim_cmd_init()
        install_element(CONFIG_NODE, &ip_multicast_routing_cmd);
        install_element(CONFIG_NODE, &no_ip_multicast_routing_cmd);
        install_element(CONFIG_NODE, &ip_pim_rp_cmd);
+       install_element(VRF_NODE, &ip_pim_rp_cmd);
        install_element(CONFIG_NODE, &no_ip_pim_rp_cmd);
+       install_element(VRF_NODE, &no_ip_pim_rp_cmd);
        install_element(CONFIG_NODE, &ip_pim_rp_prefix_list_cmd);
+       install_element(VRF_NODE, &ip_pim_rp_prefix_list_cmd);
        install_element(CONFIG_NODE, &no_ip_pim_rp_prefix_list_cmd);
+       install_element(VRF_NODE, &no_ip_pim_rp_prefix_list_cmd);
        install_element(CONFIG_NODE, &no_ip_pim_ssm_prefix_list_cmd);
+       install_element(VRF_NODE, &no_ip_pim_ssm_prefix_list_cmd);
        install_element(CONFIG_NODE, &no_ip_pim_ssm_prefix_list_name_cmd);
+       install_element(VRF_NODE, &no_ip_pim_ssm_prefix_list_name_cmd);
        install_element(CONFIG_NODE, &ip_pim_ssm_prefix_list_cmd);
+       install_element(VRF_NODE, &ip_pim_ssm_prefix_list_cmd);
        install_element(CONFIG_NODE, &ip_pim_register_suppress_cmd);
+       install_element(VRF_NODE, &ip_pim_register_suppress_cmd);
        install_element(CONFIG_NODE, &no_ip_pim_register_suppress_cmd);
+       install_element(VRF_NODE, &no_ip_pim_register_suppress_cmd);
        install_element(CONFIG_NODE, &ip_pim_spt_switchover_infinity_cmd);
+       install_element(VRF_NODE, &ip_pim_spt_switchover_infinity_cmd);
        install_element(CONFIG_NODE, &ip_pim_spt_switchover_infinity_plist_cmd);
+       install_element(VRF_NODE, &ip_pim_spt_switchover_infinity_plist_cmd);
        install_element(CONFIG_NODE, &no_ip_pim_spt_switchover_infinity_cmd);
+       install_element(VRF_NODE, &no_ip_pim_spt_switchover_infinity_cmd);
        install_element(CONFIG_NODE,
                        &no_ip_pim_spt_switchover_infinity_plist_cmd);
+       install_element(VRF_NODE, &no_ip_pim_spt_switchover_infinity_plist_cmd);
        install_element(CONFIG_NODE, &ip_pim_joinprune_time_cmd);
+       install_element(VRF_NODE, &ip_pim_joinprune_time_cmd);
        install_element(CONFIG_NODE, &no_ip_pim_joinprune_time_cmd);
+       install_element(VRF_NODE, &no_ip_pim_joinprune_time_cmd);
        install_element(CONFIG_NODE, &ip_pim_keep_alive_cmd);
+       install_element(VRF_NODE, &ip_pim_keep_alive_cmd);
+       install_element(CONFIG_NODE, &ip_pim_rp_keep_alive_cmd);
+       install_element(VRF_NODE, &ip_pim_rp_keep_alive_cmd);
        install_element(CONFIG_NODE, &no_ip_pim_keep_alive_cmd);
+       install_element(VRF_NODE, &no_ip_pim_keep_alive_cmd);
+       install_element(CONFIG_NODE, &no_ip_pim_rp_keep_alive_cmd);
+       install_element(VRF_NODE, &no_ip_pim_rp_keep_alive_cmd);
        install_element(CONFIG_NODE, &ip_pim_packets_cmd);
+       install_element(VRF_NODE, &ip_pim_packets_cmd);
        install_element(CONFIG_NODE, &no_ip_pim_packets_cmd);
+       install_element(VRF_NODE, &no_ip_pim_packets_cmd);
        install_element(CONFIG_NODE, &ip_pim_v6_secondary_cmd);
+       install_element(VRF_NODE, &ip_pim_v6_secondary_cmd);
        install_element(CONFIG_NODE, &no_ip_pim_v6_secondary_cmd);
+       install_element(VRF_NODE, &no_ip_pim_v6_secondary_cmd);
        install_element(CONFIG_NODE, &ip_ssmpingd_cmd);
+       install_element(VRF_NODE, &ip_ssmpingd_cmd);
        install_element(CONFIG_NODE, &no_ip_ssmpingd_cmd);
+       install_element(VRF_NODE, &no_ip_ssmpingd_cmd);
        install_element(CONFIG_NODE, &ip_msdp_peer_cmd);
+       install_element(VRF_NODE, &ip_msdp_peer_cmd);
        install_element(CONFIG_NODE, &no_ip_msdp_peer_cmd);
+       install_element(VRF_NODE, &no_ip_msdp_peer_cmd);
        install_element(CONFIG_NODE, &ip_pim_ecmp_cmd);
+       install_element(VRF_NODE, &ip_pim_ecmp_cmd);
        install_element(CONFIG_NODE, &no_ip_pim_ecmp_cmd);
+       install_element(VRF_NODE, &no_ip_pim_ecmp_cmd);
        install_element(CONFIG_NODE, &ip_pim_ecmp_rebalance_cmd);
+       install_element(VRF_NODE, &ip_pim_ecmp_rebalance_cmd);
        install_element(CONFIG_NODE, &no_ip_pim_ecmp_rebalance_cmd);
+       install_element(VRF_NODE, &no_ip_pim_ecmp_rebalance_cmd);
 
        install_element(INTERFACE_NODE, &interface_ip_igmp_cmd);
        install_element(INTERFACE_NODE, &interface_no_ip_igmp_cmd);
@@ -7337,8 +8490,11 @@ void pim_cmd_init()
        install_element(INTERFACE_NODE, &interface_no_ip_mroute_source_cmd);
 
        install_element(VIEW_NODE, &show_ip_igmp_interface_cmd);
+       install_element(VIEW_NODE, &show_ip_igmp_interface_vrf_all_cmd);
        install_element(VIEW_NODE, &show_ip_igmp_join_cmd);
+       install_element(VIEW_NODE, &show_ip_igmp_join_vrf_all_cmd);
        install_element(VIEW_NODE, &show_ip_igmp_groups_cmd);
+       install_element(VIEW_NODE, &show_ip_igmp_groups_vrf_all_cmd);
        install_element(VIEW_NODE, &show_ip_igmp_groups_retransmissions_cmd);
        install_element(VIEW_NODE, &show_ip_igmp_sources_cmd);
        install_element(VIEW_NODE, &show_ip_igmp_sources_retransmissions_cmd);
@@ -7348,19 +8504,29 @@ void pim_cmd_init()
        install_element(VIEW_NODE, &show_ip_pim_assert_winner_metric_cmd);
        install_element(VIEW_NODE, &show_ip_pim_interface_traffic_cmd);
        install_element(VIEW_NODE, &show_ip_pim_interface_cmd);
+       install_element(VIEW_NODE, &show_ip_pim_interface_vrf_all_cmd);
        install_element(VIEW_NODE, &show_ip_pim_join_cmd);
+       install_element(VIEW_NODE, &show_ip_pim_join_vrf_all_cmd);
        install_element(VIEW_NODE, &show_ip_pim_local_membership_cmd);
        install_element(VIEW_NODE, &show_ip_pim_neighbor_cmd);
+       install_element(VIEW_NODE, &show_ip_pim_neighbor_vrf_all_cmd);
        install_element(VIEW_NODE, &show_ip_pim_rpf_cmd);
+       install_element(VIEW_NODE, &show_ip_pim_rpf_vrf_all_cmd);
        install_element(VIEW_NODE, &show_ip_pim_secondary_cmd);
        install_element(VIEW_NODE, &show_ip_pim_state_cmd);
+       install_element(VIEW_NODE, &show_ip_pim_state_vrf_all_cmd);
        install_element(VIEW_NODE, &show_ip_pim_upstream_cmd);
+       install_element(VIEW_NODE, &show_ip_pim_upstream_vrf_all_cmd);
        install_element(VIEW_NODE, &show_ip_pim_upstream_join_desired_cmd);
        install_element(VIEW_NODE, &show_ip_pim_upstream_rpf_cmd);
        install_element(VIEW_NODE, &show_ip_pim_rp_cmd);
+       install_element(VIEW_NODE, &show_ip_pim_rp_vrf_all_cmd);
        install_element(VIEW_NODE, &show_ip_multicast_cmd);
+       install_element(VIEW_NODE, &show_ip_multicast_vrf_all_cmd);
        install_element(VIEW_NODE, &show_ip_mroute_cmd);
+       install_element(VIEW_NODE, &show_ip_mroute_vrf_all_cmd);
        install_element(VIEW_NODE, &show_ip_mroute_count_cmd);
+       install_element(VIEW_NODE, &show_ip_mroute_count_vrf_all_cmd);
        install_element(VIEW_NODE, &show_ip_rib_cmd);
        install_element(VIEW_NODE, &show_ip_ssmpingd_cmd);
        install_element(VIEW_NODE, &show_debugging_pim_cmd);
@@ -7390,6 +8556,8 @@ void pim_cmd_init()
        install_element(ENABLE_NODE, &no_debug_static_cmd);
        install_element(ENABLE_NODE, &debug_pim_cmd);
        install_element(ENABLE_NODE, &no_debug_pim_cmd);
+       install_element(ENABLE_NODE, &debug_pim_nht_cmd);
+       install_element(ENABLE_NODE, &no_debug_pim_nht_cmd);
        install_element(ENABLE_NODE, &debug_pim_events_cmd);
        install_element(ENABLE_NODE, &no_debug_pim_events_cmd);
        install_element(ENABLE_NODE, &debug_pim_packets_cmd);
@@ -7400,6 +8568,8 @@ void pim_cmd_init()
        install_element(ENABLE_NODE, &no_debug_pim_packetdump_recv_cmd);
        install_element(ENABLE_NODE, &debug_pim_trace_cmd);
        install_element(ENABLE_NODE, &no_debug_pim_trace_cmd);
+       install_element(ENABLE_NODE, &debug_pim_trace_detail_cmd);
+       install_element(ENABLE_NODE, &no_debug_pim_trace_detail_cmd);
        install_element(ENABLE_NODE, &debug_ssmpingd_cmd);
        install_element(ENABLE_NODE, &no_debug_ssmpingd_cmd);
        install_element(ENABLE_NODE, &debug_pim_zebra_cmd);
@@ -7430,12 +8600,16 @@ void pim_cmd_init()
        install_element(CONFIG_NODE, &no_debug_static_cmd);
        install_element(CONFIG_NODE, &debug_pim_cmd);
        install_element(CONFIG_NODE, &no_debug_pim_cmd);
+       install_element(CONFIG_NODE, &debug_pim_nht_cmd);
+       install_element(CONFIG_NODE, &no_debug_pim_nht_cmd);
        install_element(CONFIG_NODE, &debug_pim_events_cmd);
        install_element(CONFIG_NODE, &no_debug_pim_events_cmd);
        install_element(CONFIG_NODE, &debug_pim_packets_cmd);
        install_element(CONFIG_NODE, &no_debug_pim_packets_cmd);
        install_element(CONFIG_NODE, &debug_pim_trace_cmd);
        install_element(CONFIG_NODE, &no_debug_pim_trace_cmd);
+       install_element(CONFIG_NODE, &debug_pim_trace_detail_cmd);
+       install_element(CONFIG_NODE, &no_debug_pim_trace_detail_cmd);
        install_element(CONFIG_NODE, &debug_ssmpingd_cmd);
        install_element(CONFIG_NODE, &no_debug_ssmpingd_cmd);
        install_element(CONFIG_NODE, &debug_pim_zebra_cmd);
@@ -7449,14 +8623,22 @@ void pim_cmd_init()
        install_element(CONFIG_NODE, &debug_msdp_packets_cmd);
        install_element(CONFIG_NODE, &no_debug_msdp_packets_cmd);
        install_element(CONFIG_NODE, &undebug_msdp_packets_cmd);
+
        install_element(CONFIG_NODE, &ip_msdp_mesh_group_member_cmd);
+       install_element(VRF_NODE, &ip_msdp_mesh_group_member_cmd);
        install_element(CONFIG_NODE, &no_ip_msdp_mesh_group_member_cmd);
+       install_element(VRF_NODE, &no_ip_msdp_mesh_group_member_cmd);
        install_element(CONFIG_NODE, &ip_msdp_mesh_group_source_cmd);
+       install_element(VRF_NODE, &ip_msdp_mesh_group_source_cmd);
        install_element(CONFIG_NODE, &no_ip_msdp_mesh_group_source_cmd);
+       install_element(VRF_NODE, &no_ip_msdp_mesh_group_source_cmd);
        install_element(VIEW_NODE, &show_ip_msdp_peer_detail_cmd);
+       install_element(VIEW_NODE, &show_ip_msdp_peer_detail_vrf_all_cmd);
        install_element(VIEW_NODE, &show_ip_msdp_sa_detail_cmd);
+       install_element(VIEW_NODE, &show_ip_msdp_sa_detail_vrf_all_cmd);
        install_element(VIEW_NODE, &show_ip_msdp_sa_sg_cmd);
        install_element(VIEW_NODE, &show_ip_msdp_mesh_group_cmd);
+       install_element(VIEW_NODE, &show_ip_msdp_mesh_group_vrf_all_cmd);
        install_element(VIEW_NODE, &show_ip_pim_ssm_range_cmd);
        install_element(VIEW_NODE, &show_ip_pim_group_type_cmd);
        install_element(INTERFACE_NODE, &interface_pim_use_source_cmd);
index 64751d8682b12fc6da3752dcad735645acaab43e..8867514876a8283a6d3622a8a40192d473e7a563 100644 (file)
 
 void pim_cmd_init(void);
 
+/*
+ * Special Macro to allow us to get the correct pim_instance;
+ */
+#define PIM_DECLVAR_CONTEXT(A, B)                                              \
+       struct vrf *A = VTY_GET_CONTEXT(vrf);                                  \
+       struct pim_instance *B =                                               \
+               (vrf) ? vrf->info : pim_get_pim_instance(VRF_DEFAULT);         \
+       vrf = (vrf) ? vrf : pim->vrf;
+
 #endif /* PIM_CMD_H */
index 2592514f38f50c5a71e66262900aa893e123a9eb..138a110d3a67c87eeb112d78b9b61fdd3d5acb19 100644 (file)
@@ -395,7 +395,8 @@ int pim_hello_recv(struct interface *ifp, struct in_addr src_addr,
                                        ifp->name);
                        }
 
-                       pim_upstream_rpf_genid_changed(neigh->source_addr);
+                       pim_upstream_rpf_genid_changed(pim_ifp->pim,
+                                                      neigh->source_addr);
 
                        pim_neighbor_delete(ifp, neigh, "GenID mismatch");
                        neigh = pim_neighbor_add(ifp, src_addr, hello_options,
@@ -445,6 +446,8 @@ int pim_hello_build_tlv(struct interface *ifp, uint8_t *tlv_buf,
        uint8_t *curr = tlv_buf;
        uint8_t *pastend = tlv_buf + tlv_buf_size;
        uint8_t *tmp;
+       struct pim_interface *pim_ifp = ifp->info;
+       struct pim_instance *pim = pim_ifp->pim;
 
        /*
         * Append options
@@ -516,7 +519,7 @@ int pim_hello_build_tlv(struct interface *ifp, uint8_t *tlv_buf,
                        }
                        return -4;
                }
-               if (pimg->send_v6_secondary) {
+               if (pim->send_v6_secondary) {
                        curr = pim_tlv_append_addrlist_ucast(
                                curr, pastend, ifp->connected, AF_INET6);
                        if (!curr) {
index 820162524557579a055732ed7bf06a3dc00da7fd..1afcff7cb1e06f8493bcb26d5e3a5521b732685a 100644 (file)
@@ -29,6 +29,7 @@
 #include "hash.h"
 
 #include "pimd.h"
+#include "pim_instance.h"
 #include "pim_zebra.h"
 #include "pim_iface.h"
 #include "pim_igmp.h"
 #include "pim_ssmpingd.h"
 #include "pim_rp.h"
 #include "pim_nht.h"
-
-struct interface *pim_regiface = NULL;
-struct list *pim_ifchannel_list = NULL;
-static int pim_iface_vif_index[MAXVIFS];
+#include "pim_jp_agg.h"
 
 static void pim_if_igmp_join_del_all(struct interface *ifp);
 static int igmp_join_sock(const char *ifname, ifindex_t ifindex,
                          struct in_addr group_addr,
                          struct in_addr source_addr);
 
-void pim_if_init(void)
+void pim_if_init(struct pim_instance *pim)
 {
        int i;
 
        for (i = 0; i < MAXVIFS; i++)
-               pim_iface_vif_index[i] = 0;
-
-       pim_ifchannel_list = list_new();
-       pim_ifchannel_list->cmp =
-               (int (*)(void *, void *))pim_ifchannel_compare;
+               pim->iface_vif_index[i] = 0;
 }
 
-void pim_if_terminate(void)
+void pim_if_terminate(struct pim_instance *pim)
 {
-       if (pim_ifchannel_list)
-               list_free(pim_ifchannel_list);
+       // Nothing to do at this moment
+       return;
 }
 
 static void *if_list_clean(struct pim_interface *pim_ifp)
 {
-       if (pim_ifp->igmp_join_list) {
+       struct pim_ifchannel *ch;
+
+       if (pim_ifp->igmp_join_list)
                list_delete(pim_ifp->igmp_join_list);
-       }
 
-       if (pim_ifp->igmp_socket_list) {
+       if (pim_ifp->igmp_socket_list)
                list_delete(pim_ifp->igmp_socket_list);
-       }
 
-       if (pim_ifp->pim_neighbor_list) {
+       if (pim_ifp->pim_neighbor_list)
                list_delete(pim_ifp->pim_neighbor_list);
-       }
 
        if (pim_ifp->upstream_switch_list)
                list_delete(pim_ifp->upstream_switch_list);
 
-       if (pim_ifp->pim_ifchannel_list) {
-               list_delete(pim_ifp->pim_ifchannel_list);
-       }
+       if (pim_ifp->sec_addr_list)
+               list_delete(pim_ifp->sec_addr_list);
 
-       if (pim_ifp->pim_ifchannel_hash)
-               hash_free(pim_ifp->pim_ifchannel_hash);
+       while ((ch = RB_ROOT(pim_ifchannel_rb,
+                            &pim_ifp->ifchannel_rb)) != NULL)
+               pim_ifchannel_delete(ch);
 
        XFREE(MTYPE_PIM_INTERFACE, pim_ifp);
 
        return 0;
 }
 
+static void pim_sec_addr_free(struct pim_secondary_addr *sec_addr)
+{
+       XFREE(MTYPE_PIM_SEC_ADDR, sec_addr);
+}
+
+static int pim_sec_addr_comp(const void *p1, const void *p2)
+{
+       const struct pim_secondary_addr *sec1 = p1;
+       const struct pim_secondary_addr *sec2 = p2;
+
+       if (sec1->addr.family == AF_INET && sec2->addr.family == AF_INET6)
+               return -1;
+
+       if (sec1->addr.family == AF_INET6 && sec2->addr.family == AF_INET)
+               return 1;
+
+       if (sec1->addr.family == AF_INET) {
+               if (ntohl(sec1->addr.u.prefix4.s_addr)
+                   < ntohl(sec2->addr.u.prefix4.s_addr))
+                       return -1;
+
+               if (ntohl(sec1->addr.u.prefix4.s_addr)
+                   > ntohl(sec2->addr.u.prefix4.s_addr))
+                       return 1;
+       } else {
+               return memcmp(&sec1->addr.u.prefix6, &sec2->addr.u.prefix6,
+                             sizeof(struct in6_addr));
+       }
+
+       return 0;
+}
+
 struct pim_interface *pim_if_new(struct interface *ifp, int igmp, int pim)
 {
        struct pim_interface *pim_ifp;
@@ -114,6 +139,7 @@ struct pim_interface *pim_if_new(struct interface *ifp, int igmp, int pim)
        }
 
        pim_ifp->options = 0;
+       pim_ifp->pim = pim_get_pim_instance(ifp->vrf_id);
        pim_ifp->mroute_vif_index = -1;
 
        pim_ifp->igmp_version = IGMP_DEFAULT_VERSION;
@@ -144,15 +170,13 @@ struct pim_interface *pim_if_new(struct interface *ifp, int igmp, int pim)
        pim_ifp->igmp_socket_list = NULL;
        pim_ifp->pim_neighbor_list = NULL;
        pim_ifp->upstream_switch_list = NULL;
-       pim_ifp->pim_ifchannel_list = NULL;
-       pim_ifp->pim_ifchannel_hash = NULL;
        pim_ifp->pim_generation_id = 0;
 
        /* list of struct igmp_sock */
        pim_ifp->igmp_socket_list = list_new();
        if (!pim_ifp->igmp_socket_list) {
-               zlog_err("%s %s: failure: igmp_socket_list=list_new()",
-                        __FILE__, __PRETTY_FUNCTION__);
+               zlog_err("%s: failure: igmp_socket_list=list_new()",
+                        __PRETTY_FUNCTION__);
                return if_list_clean(pim_ifp);
        }
        pim_ifp->igmp_socket_list->del = (void (*)(void *))igmp_sock_free;
@@ -160,32 +184,32 @@ struct pim_interface *pim_if_new(struct interface *ifp, int igmp, int pim)
        /* list of struct pim_neighbor */
        pim_ifp->pim_neighbor_list = list_new();
        if (!pim_ifp->pim_neighbor_list) {
-               zlog_err("%s %s: failure: pim_neighbor_list=list_new()",
-                        __FILE__, __PRETTY_FUNCTION__);
+               zlog_err("%s: failure: pim_neighbor_list=list_new()",
+                        __PRETTY_FUNCTION__);
                return if_list_clean(pim_ifp);
        }
        pim_ifp->pim_neighbor_list->del = (void (*)(void *))pim_neighbor_free;
 
        pim_ifp->upstream_switch_list = list_new();
        if (!pim_ifp->upstream_switch_list) {
-               zlog_err("%s %s: failure: upstream_switch_list=list_new()",
-                        __FILE__, __PRETTY_FUNCTION__);
+               zlog_err("%s: failure: upstream_switch_list=list_new()",
+                        __PRETTY_FUNCTION__);
                return if_list_clean(pim_ifp);
        }
+       pim_ifp->upstream_switch_list->del =
+               (void (*)(void *))pim_jp_agg_group_list_free;
+       pim_ifp->upstream_switch_list->cmp = pim_jp_agg_group_list_cmp;
 
-       /* list of struct pim_ifchannel */
-       pim_ifp->pim_ifchannel_list = list_new();
-       if (!pim_ifp->pim_ifchannel_list) {
-               zlog_err("%s %s: failure: pim_ifchannel_list=list_new()",
-                        __FILE__, __PRETTY_FUNCTION__);
-               return if_list_clean(pim_ifp);
+       pim_ifp->sec_addr_list = list_new();
+       if (!pim_ifp->sec_addr_list) {
+               zlog_err("%s: failure: secondary addresslist",
+                        __PRETTY_FUNCTION__);
        }
-       pim_ifp->pim_ifchannel_list->del = (void (*)(void *))pim_ifchannel_free;
-       pim_ifp->pim_ifchannel_list->cmp =
-               (int (*)(void *, void *))pim_ifchannel_compare;
+       pim_ifp->sec_addr_list->del = (void (*)(void *))pim_sec_addr_free;
+       pim_ifp->sec_addr_list->cmp =
+               (int (*)(void *, void *))pim_sec_addr_comp;
 
-       pim_ifp->pim_ifchannel_hash =
-               hash_create(pim_ifchannel_hash_key, pim_ifchannel_equal, NULL);
+       RB_INIT(pim_ifchannel_rb, &pim_ifp->ifchannel_rb);
 
        ifp->info = pim_ifp;
 
@@ -199,6 +223,7 @@ struct pim_interface *pim_if_new(struct interface *ifp, int igmp, int pim)
 void pim_if_delete(struct interface *ifp)
 {
        struct pim_interface *pim_ifp;
+       struct pim_ifchannel *ch;
 
        zassert(ifp);
        pim_ifp = ifp->info;
@@ -218,9 +243,11 @@ void pim_if_delete(struct interface *ifp)
        list_delete(pim_ifp->igmp_socket_list);
        list_delete(pim_ifp->pim_neighbor_list);
        list_delete(pim_ifp->upstream_switch_list);
-       list_delete(pim_ifp->pim_ifchannel_list);
+       list_delete(pim_ifp->sec_addr_list);
 
-       hash_free(pim_ifp->pim_ifchannel_hash);
+       while ((ch = RB_ROOT(pim_ifchannel_rb,
+                            &pim_ifp->ifchannel_rb)) != NULL)
+               pim_ifchannel_delete(ch);
 
        XFREE(MTYPE_PIM_INTERFACE, pim_ifp);
 
@@ -230,15 +257,12 @@ void pim_if_delete(struct interface *ifp)
 void pim_if_update_could_assert(struct interface *ifp)
 {
        struct pim_interface *pim_ifp;
-       struct listnode *node;
-       struct listnode *next_node;
        struct pim_ifchannel *ch;
 
        pim_ifp = ifp->info;
        zassert(pim_ifp);
 
-       for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, node, next_node,
-                              ch)) {
+       RB_FOREACH(ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb) {
                pim_ifchannel_update_could_assert(ch);
        }
 }
@@ -246,15 +270,12 @@ void pim_if_update_could_assert(struct interface *ifp)
 static void pim_if_update_my_assert_metric(struct interface *ifp)
 {
        struct pim_interface *pim_ifp;
-       struct listnode *node;
-       struct listnode *next_node;
        struct pim_ifchannel *ch;
 
        pim_ifp = ifp->info;
        zassert(pim_ifp);
 
-       for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, node, next_node,
-                              ch)) {
+       RB_FOREACH(ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb) {
                pim_ifchannel_update_my_assert_metric(ch);
        }
 }
@@ -331,48 +352,12 @@ static int detect_primary_address_change(struct interface *ifp,
        return changed;
 }
 
-static int pim_sec_addr_comp(const void *p1, const void *p2)
-{
-       const struct pim_secondary_addr *sec1 = p1;
-       const struct pim_secondary_addr *sec2 = p2;
-
-       if (sec1->addr.family == AF_INET && sec2->addr.family == AF_INET6)
-               return -1;
-
-       if (sec1->addr.family == AF_INET6 && sec2->addr.family == AF_INET)
-               return 1;
-
-       if (sec1->addr.family == AF_INET) {
-               if (ntohl(sec1->addr.u.prefix4.s_addr)
-                   < ntohl(sec2->addr.u.prefix4.s_addr))
-                       return -1;
-
-               if (ntohl(sec1->addr.u.prefix4.s_addr)
-                   > ntohl(sec2->addr.u.prefix4.s_addr))
-                       return 1;
-       } else {
-               return memcmp(&sec1->addr.u.prefix6, &sec2->addr.u.prefix6,
-                             sizeof(struct in6_addr));
-       }
-
-       return 0;
-}
-
-static void pim_sec_addr_free(struct pim_secondary_addr *sec_addr)
-{
-       XFREE(MTYPE_PIM_SEC_ADDR, sec_addr);
-}
-
 static struct pim_secondary_addr *
 pim_sec_addr_find(struct pim_interface *pim_ifp, struct prefix *addr)
 {
        struct pim_secondary_addr *sec_addr;
        struct listnode *node;
 
-       if (!pim_ifp->sec_addr_list) {
-               return NULL;
-       }
-
        for (ALL_LIST_ELEMENTS_RO(pim_ifp->sec_addr_list, node, sec_addr)) {
                if (prefix_cmp(&sec_addr->addr, addr)) {
                        return sec_addr;
@@ -400,22 +385,9 @@ static int pim_sec_addr_add(struct pim_interface *pim_ifp, struct prefix *addr)
                return changed;
        }
 
-       if (!pim_ifp->sec_addr_list) {
-               pim_ifp->sec_addr_list = list_new();
-               pim_ifp->sec_addr_list->del =
-                       (void (*)(void *))pim_sec_addr_free;
-               pim_ifp->sec_addr_list->cmp =
-                       (int (*)(void *, void *))pim_sec_addr_comp;
-       }
-
        sec_addr = XCALLOC(MTYPE_PIM_SEC_ADDR, sizeof(*sec_addr));
-       if (!sec_addr) {
-               if (list_isempty(pim_ifp->sec_addr_list)) {
-                       list_free(pim_ifp->sec_addr_list);
-                       pim_ifp->sec_addr_list = NULL;
-               }
+       if (!sec_addr)
                return changed;
-       }
 
        changed = 1;
        sec_addr->addr = *addr;
@@ -428,15 +400,10 @@ static int pim_sec_addr_del_all(struct pim_interface *pim_ifp)
 {
        int changed = 0;
 
-       if (!pim_ifp->sec_addr_list) {
-               return changed;
-       }
        if (!list_isempty(pim_ifp->sec_addr_list)) {
                changed = 1;
                /* remove all nodes and free up the list itself */
                list_delete_all_node(pim_ifp->sec_addr_list);
-               list_free(pim_ifp->sec_addr_list);
-               pim_ifp->sec_addr_list = NULL;
        }
 
        return changed;
@@ -451,11 +418,9 @@ static int pim_sec_addr_update(struct interface *ifp)
        struct pim_secondary_addr *sec_addr;
        int changed = 0;
 
-       if (pim_ifp->sec_addr_list) {
-               for (ALL_LIST_ELEMENTS_RO(pim_ifp->sec_addr_list, node,
-                                         sec_addr)) {
-                       sec_addr->flags |= PIM_SEC_ADDRF_STALE;
-               }
+       for (ALL_LIST_ELEMENTS_RO(pim_ifp->sec_addr_list, node,
+                                 sec_addr)) {
+               sec_addr->flags |= PIM_SEC_ADDRF_STALE;
        }
 
        for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) {
@@ -476,20 +441,12 @@ static int pim_sec_addr_update(struct interface *ifp)
                }
        }
 
-       if (pim_ifp->sec_addr_list) {
-               /* Drop stale entries */
-               for (ALL_LIST_ELEMENTS(pim_ifp->sec_addr_list, node, nextnode,
-                                      sec_addr)) {
-                       if (sec_addr->flags & PIM_SEC_ADDRF_STALE) {
-                               pim_sec_addr_del(pim_ifp, sec_addr);
-                               changed = 1;
-                       }
-               }
-
-               /* If the list went empty free it up */
-               if (list_isempty(pim_ifp->sec_addr_list)) {
-                       list_free(pim_ifp->sec_addr_list);
-                       pim_ifp->sec_addr_list = NULL;
+       /* Drop stale entries */
+       for (ALL_LIST_ELEMENTS(pim_ifp->sec_addr_list, node, nextnode,
+                              sec_addr)) {
+               if (sec_addr->flags & PIM_SEC_ADDRF_STALE) {
+                       pim_sec_addr_del(pim_ifp, sec_addr);
+                       changed = 1;
                }
        }
 
@@ -596,8 +553,8 @@ void pim_if_addr_add(struct connected *ifc)
 
        detect_address_change(ifp, 0, __PRETTY_FUNCTION__);
 
-       if (ifc->address->family != AF_INET)
-               return;
+       // if (ifc->address->family != AF_INET)
+       //  return;
 
        if (PIM_IF_TEST_IGMP(pim_ifp->options)) {
                struct igmp_sock *igmp;
@@ -607,8 +564,9 @@ void pim_if_addr_add(struct connected *ifc)
                                                   ifaddr);
                if (!igmp) {
                        /* if addr new, add IGMP socket */
-                       pim_igmp_sock_add(pim_ifp->igmp_socket_list, ifaddr,
-                                         ifp);
+                       if (ifc->address->family == AF_INET)
+                               pim_igmp_sock_add(pim_ifp->igmp_socket_list,
+                                                 ifaddr, ifp);
                }
 
                /* Replay Static IGMP groups */
@@ -675,9 +633,10 @@ void pim_if_addr_add(struct connected *ifc)
                        rpf.rpf_addr.family = AF_INET;
                        rpf.rpf_addr.prefixlen = IPV4_MAX_BITLEN;
                        rpf.rpf_addr.u.prefix4 = ifc->address->u.prefix4;
-                       pnc = pim_nexthop_cache_find(&rpf);
+                       pnc = pim_nexthop_cache_find(pim_ifp->pim, &rpf);
                        if (pnc)
-                               pim_sendmsg_zebra_rnh(zclient, pnc,
+                               pim_sendmsg_zebra_rnh(pim_ifp->pim, zclient,
+                                                     pnc,
                                                      ZEBRA_NEXTHOP_REGISTER);
                }
        } /* pim */
@@ -758,9 +717,6 @@ void pim_if_addr_del(struct connected *ifc, int force_prim_as_any)
        ifp = ifc->ifp;
        zassert(ifp);
 
-       if (ifc->address->family != AF_INET)
-               return;
-
        if (PIM_DEBUG_ZEBRA) {
                char buf[BUFSIZ];
                prefix2str(ifc->address, buf, BUFSIZ);
@@ -827,7 +783,7 @@ void pim_if_addr_add_all(struct interface *ifp)
        }
        pim_ifchannel_scan_forward_start(ifp);
 
-       pim_rp_setup();
+       pim_rp_setup(pim_ifp->pim);
        pim_rp_check_on_if_add(pim_ifp);
 }
 
@@ -836,6 +792,8 @@ void pim_if_addr_del_all(struct interface *ifp)
        struct connected *ifc;
        struct listnode *node;
        struct listnode *nextnode;
+       struct vrf *vrf = vrf_lookup_by_id(ifp->vrf_id);
+       struct pim_instance *pim = vrf->info;
 
        /* PIM/IGMP enabled ? */
        if (!ifp->info)
@@ -850,8 +808,8 @@ void pim_if_addr_del_all(struct interface *ifp)
                pim_if_addr_del(ifc, 1 /* force_prim_as_any=true */);
        }
 
-       pim_rp_setup();
-       pim_i_am_rp_re_evaluate();
+       pim_rp_setup(pim);
+       pim_i_am_rp_re_evaluate(pim);
 }
 
 void pim_if_addr_del_all_igmp(struct interface *ifp)
@@ -902,6 +860,7 @@ struct in_addr pim_find_primary_addr(struct interface *ifp)
        int v4_addrs = 0;
        int v6_addrs = 0;
        struct pim_interface *pim_ifp = ifp->info;
+       struct vrf *vrf = vrf_lookup_by_id(ifp->vrf_id);
 
        if (pim_ifp && PIM_INADDR_ISNOT_ANY(pim_ifp->update_source)) {
                return pim_ifp->update_source;
@@ -938,7 +897,12 @@ struct in_addr pim_find_primary_addr(struct interface *ifp)
         */
        if (!v4_addrs && v6_addrs && !if_is_loopback(ifp)) {
                struct interface *lo_ifp;
-               lo_ifp = if_lookup_by_name("lo", VRF_DEFAULT);
+               // DBS - Come back and check here
+               if (ifp->vrf_id == VRF_DEFAULT)
+                       lo_ifp = if_lookup_by_name("lo", vrf->vrf_id);
+               else
+                       lo_ifp = if_lookup_by_name(vrf->name, vrf->vrf_id);
+
                if (lo_ifp)
                        return pim_find_primary_addr(lo_ifp);
        }
@@ -950,7 +914,10 @@ struct in_addr pim_find_primary_addr(struct interface *ifp)
 
 static int pim_iface_next_vif_index(struct interface *ifp)
 {
+       struct pim_interface *pim_ifp = ifp->info;
+       struct pim_instance *pim = pim_ifp->pim;
        int i;
+
        /*
         * The pimreg vif is always going to be in index 0
         * of the table.
@@ -959,7 +926,7 @@ static int pim_iface_next_vif_index(struct interface *ifp)
                return 0;
 
        for (i = 1; i < MAXVIFS; i++) {
-               if (pim_iface_vif_index[i] == 0)
+               if (pim->iface_vif_index[i] == 0)
                        return i;
        }
        return MAXVIFS;
@@ -1021,7 +988,7 @@ int pim_if_add_vif(struct interface *ifp)
                return -5;
        }
 
-       pim_iface_vif_index[pim_ifp->mroute_vif_index] = 1;
+       pim_ifp->pim->iface_vif_index[pim_ifp->mroute_vif_index] = 1;
        return 0;
 }
 
@@ -1036,57 +1003,26 @@ int pim_if_del_vif(struct interface *ifp)
                return -1;
        }
 
-       pim_mroute_del_vif(pim_ifp->mroute_vif_index);
+       pim_mroute_del_vif(ifp);
 
        /*
          Update vif_index
         */
-       pim_iface_vif_index[pim_ifp->mroute_vif_index] = 0;
+       pim_ifp->pim->iface_vif_index[pim_ifp->mroute_vif_index] = 0;
 
        pim_ifp->mroute_vif_index = -1;
 
        return 0;
 }
 
-void pim_if_add_vif_all()
-{
-       struct listnode *ifnode;
-       struct listnode *ifnextnode;
-       struct interface *ifp;
-
-       for (ALL_LIST_ELEMENTS(vrf_iflist(VRF_DEFAULT), ifnode, ifnextnode,
-                              ifp)) {
-               if (!ifp->info)
-                       continue;
-
-               pim_if_add_vif(ifp);
-       }
-}
-
-void pim_if_del_vif_all()
+// DBS - VRF Revist
+struct interface *pim_if_find_by_vif_index(struct pim_instance *pim,
+                                          ifindex_t vif_index)
 {
        struct listnode *ifnode;
-       struct listnode *ifnextnode;
        struct interface *ifp;
 
-       for (ALL_LIST_ELEMENTS(vrf_iflist(VRF_DEFAULT), ifnode, ifnextnode,
-                              ifp)) {
-               if (!ifp->info)
-                       continue;
-
-               pim_if_del_vif(ifp);
-       }
-}
-
-struct interface *pim_if_find_by_vif_index(ifindex_t vif_index)
-{
-       struct listnode *ifnode;
-       struct interface *ifp;
-
-       if (vif_index == 0)
-               return if_lookup_by_name("pimreg", VRF_DEFAULT);
-
-       for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT), ifnode, ifp)) {
+       for (ALL_LIST_ELEMENTS_RO(vrf_iflist(pim->vrf_id), ifnode, ifp)) {
                if (ifp->info) {
                        struct pim_interface *pim_ifp;
                        pim_ifp = ifp->info;
@@ -1102,12 +1038,12 @@ struct interface *pim_if_find_by_vif_index(ifindex_t vif_index)
 /*
   pim_if_add_vif() uses ifindex as vif_index
  */
-int pim_if_find_vifindex_by_ifindex(ifindex_t ifindex)
+int pim_if_find_vifindex_by_ifindex(struct pim_instance *pim, ifindex_t ifindex)
 {
        struct pim_interface *pim_ifp;
        struct interface *ifp;
 
-       ifp = if_lookup_by_index(ifindex, VRF_DEFAULT);
+       ifp = if_lookup_by_index(ifindex, pim->vrf_id);
        if (!ifp || !ifp->info)
                return -1;
        pim_ifp = ifp->info;
@@ -1496,15 +1432,12 @@ void pim_if_assert_on_neighbor_down(struct interface *ifp,
                                    struct in_addr neigh_addr)
 {
        struct pim_interface *pim_ifp;
-       struct listnode *node;
-       struct listnode *next_node;
        struct pim_ifchannel *ch;
 
        pim_ifp = ifp->info;
        zassert(pim_ifp);
 
-       for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, node, next_node,
-                              ch)) {
+       RB_FOREACH(ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb) {
                /* Is (S,G,I) assert loser ? */
                if (ch->ifassert_state != PIM_IFASSERT_I_AM_LOSER)
                        continue;
@@ -1518,24 +1451,23 @@ void pim_if_assert_on_neighbor_down(struct interface *ifp,
 
 void pim_if_update_join_desired(struct pim_interface *pim_ifp)
 {
-       struct listnode *ch_node;
        struct pim_ifchannel *ch;
 
        /* clear off flag from interface's upstreams */
-       for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_ifchannel_list, ch_node, ch)) {
+       RB_FOREACH(ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb) {
                PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED_UPDATED(
                        ch->upstream->flags);
        }
 
        /* scan per-interface (S,G,I) state on this I interface */
-       for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_ifchannel_list, ch_node, ch)) {
+       RB_FOREACH(ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb) {
                struct pim_upstream *up = ch->upstream;
 
                if (PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED_UPDATED(up->flags))
                        continue;
 
                /* update join_desired for the global (S,G) state */
-               pim_upstream_update_join_desired(up);
+               pim_upstream_update_join_desired(pim_ifp->pim, up);
                PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED_UPDATED(up->flags);
        }
 }
@@ -1543,16 +1475,13 @@ void pim_if_update_join_desired(struct pim_interface *pim_ifp)
 void pim_if_update_assert_tracking_desired(struct interface *ifp)
 {
        struct pim_interface *pim_ifp;
-       struct listnode *node;
-       struct listnode *next_node;
        struct pim_ifchannel *ch;
 
        pim_ifp = ifp->info;
        if (!pim_ifp)
                return;
 
-       for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, node, next_node,
-                              ch)) {
+       RB_FOREACH(ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb) {
                pim_ifchannel_update_assert_tracking_desired(ch);
        }
 }
@@ -1562,14 +1491,22 @@ void pim_if_update_assert_tracking_desired(struct interface *ifp)
  * The pimreg is a special interface that we have that is not
  * quite an inteface but a VIF is created for it.
  */
-void pim_if_create_pimreg(void)
+void pim_if_create_pimreg(struct pim_instance *pim)
 {
-       if (!pim_regiface) {
-               pim_regiface =
-                       if_create("pimreg", strlen("pimreg"), VRF_DEFAULT);
-               pim_regiface->ifindex = PIM_OIF_PIM_REGISTER_VIF;
+       char pimreg_name[100];
+
+       if (!pim->regiface) {
+               if (pim->vrf_id == VRF_DEFAULT)
+                       strcpy(pimreg_name, "pimreg");
+               else
+                       sprintf(pimreg_name, "pimreg%d",
+                               pim->vrf->data.l.table_id);
 
-               pim_if_new(pim_regiface, 0, 0);
+               pim->regiface = if_create(pimreg_name, strlen(pimreg_name),
+                                         pim->vrf_id);
+               pim->regiface->ifindex = PIM_OIF_PIM_REGISTER_VIF;
+
+               pim_if_new(pim->regiface, 0, 0);
        }
 }
 
@@ -1596,14 +1533,38 @@ int pim_if_connected_to_source(struct interface *ifp, struct in_addr src)
        return 0;
 }
 
-struct interface *pim_if_lookup_address_vrf(struct in_addr src, vrf_id_t vrf_id)
+int pim_if_is_loopback(struct pim_instance *pim, struct interface *ifp)
 {
-       struct listnode *ifnode;
-       struct interface *ifp;
+       if (if_is_loopback(ifp))
+               return 1;
 
-       for (ALL_LIST_ELEMENTS_RO(vrf_iflist(vrf_id), ifnode, ifp)) {
-               if (pim_if_connected_to_source(ifp, src) && ifp->info)
-                       return ifp;
+       if (strcmp(ifp->name, pim->vrf->name) == 0)
+               return 1;
+
+       return 0;
+}
+
+int pim_if_is_vrf_device(struct interface *ifp)
+{
+       struct vrf *vrf;
+
+       RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name)
+       {
+               if (strncmp(ifp->name, vrf->name, strlen(ifp->name)) == 0)
+                       return 1;
        }
-       return NULL;
+
+       return 0;
+}
+
+int pim_if_ifchannel_count(struct pim_interface *pim_ifp)
+{
+       struct pim_ifchannel *ch;
+       int count = 0;
+
+       RB_FOREACH(ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb) {
+               count++;
+       }
+
+       return count;
 }
index e742e68f6783011f0db2d833b6a38915ea524be9..ed885ff0e375c6f282fceca3bff82c5304719ba2 100644 (file)
@@ -73,6 +73,8 @@ struct pim_secondary_addr {
 struct pim_interface {
        uint32_t options; /* bit vector */
        ifindex_t mroute_vif_index;
+       struct pim_instance *pim;
+
        struct in_addr primary_address; /* remember addr to detect change */
        struct list *sec_addr_list;     /* list of struct pim_secondary_addr */
        struct in_addr update_source;   /* user can statically set the primary
@@ -104,8 +106,7 @@ struct pim_interface {
        uint16_t pim_override_interval_msec; /* config */
        struct list *pim_neighbor_list;      /* list of struct pim_neighbor */
        struct list *upstream_switch_list;
-       struct list *pim_ifchannel_list; /* list of struct pim_ifchannel */
-       struct hash *pim_ifchannel_hash;
+       struct pim_ifchannel_rb ifchannel_rb;
 
        /* neighbors without lan_delay */
        int pim_number_of_nonlandelay_neighbors;
@@ -138,8 +139,6 @@ struct pim_interface {
        struct bfd_info *bfd_info;
 };
 
-extern struct interface *pim_regiface;
-extern struct list *pim_ifchannel_list;
 /*
   if default_holdtime is set (>= 0), use it;
   otherwise default_holdtime is 3.5 * hello_period
@@ -149,8 +148,8 @@ extern struct list *pim_ifchannel_list;
                 ? ((pim_ifp)->pim_hello_period * 7 / 2)                       \
                 : ((pim_ifp)->pim_default_holdtime))
 
-void pim_if_init(void);
-void pim_if_terminate(void);
+void pim_if_init(struct pim_instance *pim);
+void pim_if_terminate(struct pim_instance *pim);
 
 struct pim_interface *pim_if_new(struct interface *ifp, int igmp, int pim);
 void pim_if_delete(struct interface *ifp);
@@ -161,16 +160,15 @@ void pim_if_addr_del_all(struct interface *ifp);
 void pim_if_addr_del_all_igmp(struct interface *ifp);
 void pim_if_addr_del_all_pim(struct interface *ifp);
 
-struct interface *pim_if_lookup_address_vrf(struct in_addr src,
-                                           vrf_id_t vrf_id);
-
 int pim_if_add_vif(struct interface *ifp);
 int pim_if_del_vif(struct interface *ifp);
-void pim_if_add_vif_all(void);
-void pim_if_del_vif_all(void);
+void pim_if_add_vif_all(struct pim_instance *pim);
+void pim_if_del_vif_all(struct pim_instance *pim);
 
-struct interface *pim_if_find_by_vif_index(ifindex_t vif_index);
-int pim_if_find_vifindex_by_ifindex(ifindex_t ifindex);
+struct interface *pim_if_find_by_vif_index(struct pim_instance *pim,
+                                          ifindex_t vif_index);
+int pim_if_find_vifindex_by_ifindex(struct pim_instance *pim,
+                                   ifindex_t ifindex);
 
 int pim_if_lan_delay_enabled(struct interface *ifp);
 uint16_t pim_if_effective_propagation_delay_msec(struct interface *ifp);
@@ -201,9 +199,14 @@ void pim_if_update_join_desired(struct pim_interface *pim_ifp);
 
 void pim_if_update_assert_tracking_desired(struct interface *ifp);
 
-void pim_if_create_pimreg(void);
+void pim_if_create_pimreg(struct pim_instance *pim);
 
 int pim_if_connected_to_source(struct interface *ifp, struct in_addr src);
 int pim_update_source_set(struct interface *ifp, struct in_addr source);
 
+int pim_if_is_loopback(struct pim_instance *pim, struct interface *ifp);
+
+int pim_if_is_vrf_device(struct interface *ifp);
+
+int pim_if_ifchannel_count(struct pim_interface *pim_ifp);
 #endif /* PIM_IFACE_H */
index d4916518e74029afede254faa673ce2ece698ed9..c91efbd8b624e3e685df440262b2d3b85d8e7fe8 100644 (file)
 #include "pim_upstream.h"
 #include "pim_ssm.h"
 
-int pim_ifchannel_compare(struct pim_ifchannel *ch1, struct pim_ifchannel *ch2)
+RB_GENERATE(pim_ifchannel_rb, pim_ifchannel,
+           pim_ifp_rb, pim_ifchannel_compare);
+
+int pim_ifchannel_compare(const struct pim_ifchannel *ch1,
+                         const struct pim_ifchannel *ch2)
 {
        struct pim_interface *pim_ifp1;
        struct pim_interface *pim_ifp2;
@@ -100,7 +104,6 @@ static void pim_ifchannel_find_new_children(struct pim_ifchannel *ch)
 {
        struct pim_interface *pim_ifp = ch->interface->info;
        struct pim_ifchannel *child;
-       struct listnode *ch_node;
 
        // Basic Sanity that we are not being silly
        if ((ch->sg.src.s_addr != INADDR_ANY)
@@ -111,8 +114,7 @@ static void pim_ifchannel_find_new_children(struct pim_ifchannel *ch)
            && (ch->sg.grp.s_addr == INADDR_ANY))
                return;
 
-       for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_ifchannel_list, ch_node,
-                                 child)) {
+       RB_FOREACH(child, pim_ifchannel_rb, &pim_ifp->ifchannel_rb) {
                if ((ch->sg.grp.s_addr != INADDR_ANY)
                    && (child->sg.grp.s_addr == ch->sg.grp.s_addr)
                    && (child != ch)) {
@@ -171,14 +173,14 @@ void pim_ifchannel_delete(struct pim_ifchannel *ch)
        listnode_delete(ch->upstream->ifchannels, ch);
 
        if (ch->ifjoin_state != PIM_IFJOIN_NOINFO) {
-               pim_upstream_update_join_desired(ch->upstream);
+               pim_upstream_update_join_desired(pim_ifp->pim, ch->upstream);
        }
 
        /* upstream is common across ifchannels, check if upstream's
           ifchannel list is empty before deleting upstream_del
           ref count will take care of it.
        */
-       pim_upstream_del(ch->upstream, __PRETTY_FUNCTION__);
+       pim_upstream_del(pim_ifp->pim, ch->upstream, __PRETTY_FUNCTION__);
        ch->upstream = NULL;
 
        THREAD_OFF(ch->t_ifjoin_expiry_timer);
@@ -189,14 +191,8 @@ void pim_ifchannel_delete(struct pim_ifchannel *ch)
                listnode_delete(ch->parent->sources, ch);
                ch->parent = NULL;
        }
-       /*
-         notice that listnode_delete() can't be moved
-         into pim_ifchannel_free() because the later is
-         called by list_delete_all_node()
-       */
-       listnode_delete(pim_ifp->pim_ifchannel_list, ch);
-       hash_release(pim_ifp->pim_ifchannel_hash, ch);
-       listnode_delete(pim_ifchannel_list, ch);
+
+       RB_REMOVE(pim_ifchannel_rb, &pim_ifp->ifchannel_rb, ch);
 
        if (PIM_DEBUG_PIM_TRACE)
                zlog_debug("%s: ifchannel entry %s is deleted ",
@@ -208,17 +204,15 @@ void pim_ifchannel_delete(struct pim_ifchannel *ch)
 void pim_ifchannel_delete_all(struct interface *ifp)
 {
        struct pim_interface *pim_ifp;
-       struct listnode *ifchannel_node;
-       struct listnode *ifchannel_nextnode;
-       struct pim_ifchannel *ifchannel;
+       struct pim_ifchannel *ch;
 
        pim_ifp = ifp->info;
        if (!pim_ifp)
                return;
 
-       for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, ifchannel_node,
-                              ifchannel_nextnode, ifchannel)) {
-               pim_ifchannel_delete(ifchannel);
+       while ((ch = RB_ROOT(pim_ifchannel_rb,
+                            &pim_ifp->ifchannel_rb)) != NULL) {
+               pim_ifchannel_delete(ch);
        }
 }
 
@@ -234,6 +228,7 @@ void pim_ifchannel_ifjoin_switch(const char *caller, struct pim_ifchannel *ch,
                                 enum pim_ifjoin_state new_state)
 {
        enum pim_ifjoin_state old_state = ch->ifjoin_state;
+       struct pim_interface *pim_ifp = ch->interface->info;
 
        if (PIM_DEBUG_PIM_EVENTS)
                zlog_debug(
@@ -266,8 +261,6 @@ void pim_ifchannel_ifjoin_switch(const char *caller, struct pim_ifchannel *ch,
                                                          child)) {
                                        struct channel_oil *c_oil =
                                                child->channel_oil;
-                                       struct pim_interface *pim_ifp =
-                                               ch->interface->info;
 
                                        if (PIM_DEBUG_PIM_TRACE)
                                                zlog_debug(
@@ -280,12 +273,12 @@ void pim_ifchannel_ifjoin_switch(const char *caller, struct pim_ifchannel *ch,
                                                continue;
 
                                        if (!pim_upstream_evaluate_join_desired(
-                                                   child)) {
+                                                   pim_ifp->pim, child)) {
                                                pim_channel_del_oif(
                                                        c_oil, ch->interface,
                                                        PIM_OIF_FLAG_PROTO_STAR);
                                                pim_upstream_update_join_desired(
-                                                       child);
+                                                       pim_ifp->pim, child);
                                        }
 
                                        /*
@@ -296,9 +289,8 @@ void pim_ifchannel_ifjoin_switch(const char *caller, struct pim_ifchannel *ch,
                                         * if channel.  So remove it.
                                         * I think this is dead code now. is it?
                                         */
-                                       if (!ch
-                                           && c_oil->oil.mfcc_ttls
-                                                      [pim_ifp->mroute_vif_index])
+                                       if (c_oil->oil.mfcc_ttls
+                                                   [pim_ifp->mroute_vif_index])
                                                pim_channel_del_oif(
                                                        c_oil, ch->interface,
                                                        PIM_OIF_FLAG_PROTO_STAR);
@@ -316,13 +308,13 @@ void pim_ifchannel_ifjoin_switch(const char *caller, struct pim_ifchannel *ch,
                                                        up->sg_str);
 
                                        if (pim_upstream_evaluate_join_desired(
-                                                   child)) {
+                                                   pim_ifp->pim, child)) {
                                                pim_channel_add_oif(
                                                        child->channel_oil,
                                                        ch->interface,
                                                        PIM_OIF_FLAG_PROTO_STAR);
                                                pim_upstream_update_join_desired(
-                                                       child);
+                                                       pim_ifp->pim, child);
                                        }
                                }
                        }
@@ -344,7 +336,7 @@ void pim_ifchannel_ifjoin_switch(const char *caller, struct pim_ifchannel *ch,
                */
                ch->ifjoin_creation = pim_time_monotonic_sec();
 
-               pim_upstream_update_join_desired(ch->upstream);
+               pim_upstream_update_join_desired(pim_ifp->pim, ch->upstream);
                pim_ifchannel_update_could_assert(ch);
                pim_ifchannel_update_assert_tracking_desired(ch);
        }
@@ -426,7 +418,8 @@ struct pim_ifchannel *pim_ifchannel_find(struct interface *ifp,
        }
 
        lookup.sg = *sg;
-       ch = hash_lookup(pim_ifp->pim_ifchannel_hash, &lookup);
+       lookup.interface = ifp;
+       ch = RB_FIND(pim_ifchannel_rb, &pim_ifp->ifchannel_rb, &lookup);
 
        return ch;
 }
@@ -434,6 +427,8 @@ struct pim_ifchannel *pim_ifchannel_find(struct interface *ifp,
 static void ifmembership_set(struct pim_ifchannel *ch,
                             enum pim_ifmembership membership)
 {
+       struct pim_interface *pim_ifp = ch->interface->info;
+
        if (ch->local_ifmembership == membership)
                return;
 
@@ -447,7 +442,7 @@ static void ifmembership_set(struct pim_ifchannel *ch,
 
        ch->local_ifmembership = membership;
 
-       pim_upstream_update_join_desired(ch->upstream);
+       pim_upstream_update_join_desired(pim_ifp->pim, ch->upstream);
        pim_ifchannel_update_could_assert(ch);
        pim_ifchannel_update_assert_tracking_desired(ch);
 }
@@ -456,31 +451,25 @@ static void ifmembership_set(struct pim_ifchannel *ch,
 void pim_ifchannel_membership_clear(struct interface *ifp)
 {
        struct pim_interface *pim_ifp;
-       struct listnode *ch_node;
        struct pim_ifchannel *ch;
 
        pim_ifp = ifp->info;
        zassert(pim_ifp);
 
-       for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_ifchannel_list, ch_node, ch)) {
+       RB_FOREACH(ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb)
                ifmembership_set(ch, PIM_IFMEMBERSHIP_NOINFO);
-       }
 }
 
 void pim_ifchannel_delete_on_noinfo(struct interface *ifp)
 {
        struct pim_interface *pim_ifp;
-       struct listnode *node;
-       struct listnode *next_node;
-       struct pim_ifchannel *ch;
+       struct pim_ifchannel *ch, *ch_tmp;
 
        pim_ifp = ifp->info;
        zassert(pim_ifp);
 
-       for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, node, next_node,
-                              ch)) {
+       RB_FOREACH_SAFE(ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb, ch_tmp)
                delete_on_noinfo(ch);
-       }
 }
 
 /*
@@ -509,7 +498,8 @@ static struct pim_ifchannel *pim_ifchannel_find_parent(struct pim_ifchannel *ch)
 }
 
 struct pim_ifchannel *pim_ifchannel_add(struct interface *ifp,
-                                       struct prefix_sg *sg, int flags)
+                                       struct prefix_sg *sg,
+                                       uint8_t source_flags, int up_flags)
 {
        struct pim_interface *pim_ifp;
        struct pim_ifchannel *ch;
@@ -521,26 +511,19 @@ struct pim_ifchannel *pim_ifchannel_add(struct interface *ifp,
 
        pim_ifp = ifp->info;
 
-       up = pim_upstream_add(sg, NULL, flags, __PRETTY_FUNCTION__);
-       if (!up) {
-               zlog_err(
-                       "%s: could not attach upstream (S,G)=%s on interface %s",
-                       __PRETTY_FUNCTION__, pim_str_sg_dump(sg), ifp->name);
-               return NULL;
-       }
-
        ch = XCALLOC(MTYPE_PIM_IFCHANNEL, sizeof(*ch));
        if (!ch) {
                zlog_warn(
                        "%s: pim_ifchannel_new() failure for (S,G)=%s on interface %s",
-                       __PRETTY_FUNCTION__, up->sg_str, ifp->name);
-
-               pim_upstream_del(up, __PRETTY_FUNCTION__);
+                       __PRETTY_FUNCTION__, pim_str_sg_dump(sg), ifp->name);
                return NULL;
        }
 
        ch->flags = 0;
-       ch->upstream = up;
+       if ((source_flags & PIM_ENCODE_RPT_BIT)
+           && !(source_flags & PIM_ENCODE_WC_BIT))
+               PIM_IF_FLAG_SET_S_G_RPT(ch->flags);
+
        ch->interface = ifp;
        ch->sg = *sg;
        pim_str_sg_set(sg, ch->sg_str);
@@ -560,6 +543,32 @@ struct pim_ifchannel *pim_ifchannel_add(struct interface *ifp,
        ch->t_ifjoin_prune_pending_timer = NULL;
        ch->ifjoin_creation = 0;
 
+       RB_INSERT(pim_ifchannel_rb, &pim_ifp->ifchannel_rb, ch);
+
+       up = pim_upstream_add(pim_ifp->pim, sg, NULL, up_flags,
+                             __PRETTY_FUNCTION__, ch);
+
+       if (!up) {
+               zlog_err(
+                       "%s: could not attach upstream (S,G)=%s on interface %s",
+                       __PRETTY_FUNCTION__, pim_str_sg_dump(sg), ifp->name);
+
+               pim_ifchannel_remove_children(ch);
+               if (ch->sources)
+                       list_delete(ch->sources);
+
+               THREAD_OFF(ch->t_ifjoin_expiry_timer);
+               THREAD_OFF(ch->t_ifjoin_prune_pending_timer);
+               THREAD_OFF(ch->t_ifassert_timer);
+
+               RB_REMOVE(pim_ifchannel_rb, &pim_ifp->ifchannel_rb, ch);
+               XFREE(MTYPE_PIM_IFCHANNEL, ch);
+               return NULL;
+       }
+       ch->upstream = up;
+
+       listnode_add_sort(up->ifchannels, ch);
+
        ch->ifassert_my_metric = pim_macro_ch_my_assert_metric_eval(ch);
        ch->ifassert_winner_metric = pim_macro_ch_my_assert_metric_eval(ch);
 
@@ -579,13 +588,6 @@ struct pim_ifchannel *pim_ifchannel_add(struct interface *ifp,
        else
                PIM_IF_FLAG_UNSET_ASSERT_TRACKING_DESIRED(ch->flags);
 
-       /* Attach to list */
-       listnode_add_sort(pim_ifp->pim_ifchannel_list, ch);
-       ch = hash_get(pim_ifp->pim_ifchannel_hash, ch, hash_alloc_intern);
-       listnode_add_sort(pim_ifchannel_list, ch);
-
-       listnode_add_sort(up->ifchannels, ch);
-
        if (PIM_DEBUG_PIM_TRACE)
                zlog_debug("%s: ifchannel %s is created ", __PRETTY_FUNCTION__,
                           ch->sg_str);
@@ -595,7 +597,7 @@ struct pim_ifchannel *pim_ifchannel_add(struct interface *ifp,
 
 static void ifjoin_to_noinfo(struct pim_ifchannel *ch, bool ch_del)
 {
-       pim_forward_stop(ch);
+       pim_forward_stop(ch, !ch_del);
        pim_ifchannel_ifjoin_switch(__PRETTY_FUNCTION__, ch, PIM_IFJOIN_NOINFO);
        if (ch_del)
                delete_on_noinfo(ch);
@@ -640,7 +642,8 @@ static int on_ifjoin_prune_pending_timer(struct thread *t)
                */
                if (PIM_IF_FLAG_TEST_S_G_RPT(ch->flags)) {
                        if (ch->upstream)
-                               pim_upstream_update_join_desired(ch->upstream);
+                               pim_upstream_update_join_desired(pim_ifp->pim,
+                                                                ch->upstream);
                        /*
                          ch->ifjoin_state transition to NOINFO state
                          ch_del is set to 0 for not deleteing from here.
@@ -665,9 +668,10 @@ static void check_recv_upstream(int is_join, struct interface *recv_ifp,
                                uint8_t source_flags, int holdtime)
 {
        struct pim_upstream *up;
+       struct pim_interface *pim_ifp = recv_ifp->info;
 
        /* Upstream (S,G) in Joined state ? */
-       up = pim_upstream_find(sg);
+       up = pim_upstream_find(pim_ifp->pim, sg);
        if (!up)
                return;
        if (up->join_state != PIM_UPSTREAM_JOINED)
@@ -769,7 +773,8 @@ void pim_ifchannel_join_add(struct interface *ifp, struct in_addr neigh_addr,
                return;
        }
 
-       ch = pim_ifchannel_add(ifp, sg, PIM_UPSTREAM_FLAG_MASK_SRC_PIM);
+       ch = pim_ifchannel_add(ifp, sg, source_flags,
+                              PIM_UPSTREAM_FLAG_MASK_SRC_PIM);
        if (!ch)
                return;
 
@@ -808,7 +813,8 @@ void pim_ifchannel_join_add(struct interface *ifp, struct in_addr neigh_addr,
                pim_ifchannel_ifjoin_switch(__PRETTY_FUNCTION__, ch,
                                            PIM_IFJOIN_JOIN);
                if (pim_macro_chisin_oiflist(ch)) {
-                       pim_upstream_inherited_olist(ch->upstream);
+                       pim_upstream_inherited_olist(pim_ifp->pim,
+                                                    ch->upstream);
                        pim_forward_start(ch);
                }
                /*
@@ -822,7 +828,7 @@ void pim_ifchannel_join_add(struct interface *ifp, struct in_addr neigh_addr,
                                         PIM_UPSTREAM_FLAG_MASK_SRC_LHR,
                                         __PRETTY_FUNCTION__);
                        pim_upstream_keep_alive_timer_start(
-                               ch->upstream, qpim_keep_alive_time);
+                               ch->upstream, pim_ifp->pim->keep_alive_time);
                }
                break;
        case PIM_IFJOIN_JOIN:
@@ -910,7 +916,8 @@ void pim_ifchannel_prune(struct interface *ifp, struct in_addr upstream,
                return;
        }
 
-       ch = pim_ifchannel_add(ifp, sg, PIM_UPSTREAM_FLAG_MASK_SRC_PIM);
+       ch = pim_ifchannel_add(ifp, sg, source_flags,
+                              PIM_UPSTREAM_FLAG_MASK_SRC_PIM);
        if (!ch)
                return;
 
@@ -942,7 +949,8 @@ void pim_ifchannel_prune(struct interface *ifp, struct in_addr upstream,
                                &ch->t_ifjoin_prune_pending_timer);
                        thread_add_timer(master, on_ifjoin_expiry_timer, ch,
                                         holdtime, &ch->t_ifjoin_expiry_timer);
-                       pim_upstream_update_join_desired(ch->upstream);
+                       pim_upstream_update_join_desired(pim_ifp->pim,
+                                                        ch->upstream);
                }
                break;
        case PIM_IFJOIN_PRUNE_PENDING:
@@ -999,6 +1007,7 @@ int pim_ifchannel_local_membership_add(struct interface *ifp,
 {
        struct pim_ifchannel *ch, *starch;
        struct pim_interface *pim_ifp;
+       struct pim_instance *pim;
 
        /* PIM enabled on interface? */
        pim_ifp = ifp->info;
@@ -1007,9 +1016,11 @@ int pim_ifchannel_local_membership_add(struct interface *ifp,
        if (!PIM_IF_TEST_PIM(pim_ifp->options))
                return 0;
 
+       pim = pim_ifp->pim;
+
        /* skip (*,G) ch creation if G is of type SSM */
        if (sg->src.s_addr == INADDR_ANY) {
-               if (pim_is_grp_ssm(sg->grp)) {
+               if (pim_is_grp_ssm(pim, sg->grp)) {
                        if (PIM_DEBUG_PIM_EVENTS)
                                zlog_debug(
                                        "%s: local membership (S,G)=%s ignored as group is SSM",
@@ -1019,7 +1030,7 @@ int pim_ifchannel_local_membership_add(struct interface *ifp,
                }
        }
 
-       ch = pim_ifchannel_add(ifp, sg, PIM_UPSTREAM_FLAG_MASK_SRC_IGMP);
+       ch = pim_ifchannel_add(ifp, sg, 0, PIM_UPSTREAM_FLAG_MASK_SRC_IGMP);
        if (!ch) {
                return 0;
        }
@@ -1027,7 +1038,7 @@ int pim_ifchannel_local_membership_add(struct interface *ifp,
        ifmembership_set(ch, PIM_IFMEMBERSHIP_INCLUDE);
 
        if (sg->src.s_addr == INADDR_ANY) {
-               struct pim_upstream *up = pim_upstream_find(sg);
+               struct pim_upstream *up = pim_upstream_find(pim, sg);
                struct pim_upstream *child;
                struct listnode *up_node;
 
@@ -1045,14 +1056,15 @@ int pim_ifchannel_local_membership_add(struct interface *ifp,
                                    child, ch, starch)) {
                                pim_channel_add_oif(child->channel_oil, ifp,
                                                    PIM_OIF_FLAG_PROTO_STAR);
-                               pim_upstream_switch(child, PIM_UPSTREAM_JOINED);
+                               pim_upstream_switch(pim, child,
+                                                   PIM_UPSTREAM_JOINED);
                        }
                }
 
-               if (pimg->spt.switchover == PIM_SPT_INFINITY) {
-                       if (pimg->spt.plist) {
+               if (pim->spt.switchover == PIM_SPT_INFINITY) {
+                       if (pim->spt.plist) {
                                struct prefix_list *plist = prefix_list_lookup(
-                                       AFI_IP, pimg->spt.plist);
+                                       AFI_IP, pim->spt.plist);
                                struct prefix g;
                                g.family = AF_INET;
                                g.prefixlen = IPV4_MAX_PREFIXLEN;
@@ -1061,12 +1073,12 @@ int pim_ifchannel_local_membership_add(struct interface *ifp,
                                if (prefix_list_apply(plist, &g)
                                    == PREFIX_DENY) {
                                        pim_channel_add_oif(
-                                               up->channel_oil, pim_regiface,
+                                               up->channel_oil, pim->regiface,
                                                PIM_OIF_FLAG_PROTO_IGMP);
                                }
                        }
                } else
-                       pim_channel_add_oif(up->channel_oil, pim_regiface,
+                       pim_channel_add_oif(up->channel_oil, pim->regiface,
                                            PIM_OIF_FLAG_PROTO_IGMP);
        }
 
@@ -1093,7 +1105,7 @@ void pim_ifchannel_local_membership_del(struct interface *ifp,
        ifmembership_set(ch, PIM_IFMEMBERSHIP_NOINFO);
 
        if (sg->src.s_addr == INADDR_ANY) {
-               struct pim_upstream *up = pim_upstream_find(sg);
+               struct pim_upstream *up = pim_upstream_find(pim_ifp->pim, sg);
                struct pim_upstream *child;
                struct listnode *up_node, *up_nnode;
 
@@ -1261,13 +1273,13 @@ void pim_ifchannel_update_assert_tracking_desired(struct pim_ifchannel *ch)
  */
 void pim_ifchannel_scan_forward_start(struct interface *new_ifp)
 {
+       struct pim_interface *new_pim_ifp = new_ifp->info;
+       struct pim_instance *pim = new_pim_ifp->pim;
        struct listnode *ifnode;
        struct interface *ifp;
-       struct pim_interface *new_pim_ifp = new_ifp->info;
 
-       for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT), ifnode, ifp)) {
+       for (ALL_LIST_ELEMENTS_RO(vrf_iflist(pim->vrf_id), ifnode, ifp)) {
                struct pim_interface *loop_pim_ifp = ifp->info;
-               struct listnode *ch_node;
                struct pim_ifchannel *ch;
 
                if (!loop_pim_ifp)
@@ -1276,8 +1288,7 @@ void pim_ifchannel_scan_forward_start(struct interface *new_ifp)
                if (new_pim_ifp == loop_pim_ifp)
                        continue;
 
-               for (ALL_LIST_ELEMENTS_RO(loop_pim_ifp->pim_ifchannel_list,
-                                         ch_node, ch)) {
+               RB_FOREACH(ch, pim_ifchannel_rb, &loop_pim_ifp->ifchannel_rb) {
                        if (ch->ifjoin_state == PIM_IFJOIN_JOIN) {
                                struct pim_upstream *up = ch->upstream;
                                if ((!up->channel_oil)
@@ -1370,15 +1381,3 @@ unsigned int pim_ifchannel_hash_key(void *arg)
 
        return jhash_2words(ch->sg.src.s_addr, ch->sg.grp.s_addr, 0);
 }
-
-int pim_ifchannel_equal(const void *arg1, const void *arg2)
-{
-       const struct pim_ifchannel *ch1 = (const struct pim_ifchannel *)arg1;
-       const struct pim_ifchannel *ch2 = (const struct pim_ifchannel *)arg2;
-
-       if ((ch1->sg.grp.s_addr == ch2->sg.grp.s_addr)
-           && (ch1->sg.src.s_addr == ch2->sg.src.s_addr))
-               return 1;
-
-       return 0;
-}
index 2260fd451b9b73182ef499e4b5382ca7a974978d..cef431c30d0f35af712b968a83998b26d853bd2f 100644 (file)
@@ -80,6 +80,8 @@ struct pim_assert_metric {
   Per-interface (S,G) state
 */
 struct pim_ifchannel {
+       RB_ENTRY(rb_ifchannel) pim_ifp_rb;
+
        struct pim_ifchannel *parent;
        struct list *sources;
        struct prefix_sg sg;
@@ -108,6 +110,10 @@ struct pim_ifchannel {
        struct pim_upstream *upstream;
 };
 
+RB_HEAD(pim_ifchannel_rb, pim_ifchannel);
+RB_PROTOTYPE(pim_ifchannel_rb, pim_ifchannel,
+            pim_ifp_rb, pim_ifchannel_compare);
+
 void pim_ifchannel_free(struct pim_ifchannel *ch);
 void pim_ifchannel_delete(struct pim_ifchannel *ch);
 void pim_ifchannel_delete_all(struct interface *ifp);
@@ -116,7 +122,8 @@ void pim_ifchannel_delete_on_noinfo(struct interface *ifp);
 struct pim_ifchannel *pim_ifchannel_find(struct interface *ifp,
                                         struct prefix_sg *sg);
 struct pim_ifchannel *pim_ifchannel_add(struct interface *ifp,
-                                       struct prefix_sg *sg, int flags);
+                                       struct prefix_sg *sg, uint8_t ch_flags,
+                                       int up_flags);
 void pim_ifchannel_join_add(struct interface *ifp, struct in_addr neigh_addr,
                            struct in_addr upstream, struct prefix_sg *sg,
                            uint8_t source_flags, uint16_t holdtime);
@@ -147,8 +154,8 @@ void pim_ifchannel_set_star_g_join_state(struct pim_ifchannel *ch, int eom,
                                         uint8_t source_flags, uint8_t join,
                                         uint8_t starg_alone);
 
-int pim_ifchannel_compare(struct pim_ifchannel *ch1, struct pim_ifchannel *ch2);
+int pim_ifchannel_compare(const struct pim_ifchannel *ch1,
+                         const struct pim_ifchannel *ch2);
 
 unsigned int pim_ifchannel_hash_key(void *arg);
-int pim_ifchannel_equal(const void *arg1, const void *arg2);
 #endif /* PIM_IFCHANNEL_H */
index c693f30ac291c1198312c544834eb0e3839e7561..3a870374c044c6e7a4924d6397de106e30d30510 100644 (file)
@@ -696,7 +696,7 @@ void igmp_startup_mode_on(struct igmp_sock *igmp)
 
 static void igmp_group_free(struct igmp_group *group)
 {
-       list_free(group->group_source_list);
+       list_delete(group->group_source_list);
 
        XFREE(MTYPE_PIM_IGMP_GROUP, group);
 }
@@ -748,7 +748,7 @@ void igmp_sock_free(struct igmp_sock *igmp)
        zassert(igmp->igmp_group_list);
        zassert(!listcount(igmp->igmp_group_list));
 
-       list_free(igmp->igmp_group_list);
+       list_delete(igmp->igmp_group_list);
        hash_free(igmp->igmp_group_hash);
 
        XFREE(MTYPE_PIM_IGMP_SOCKET, igmp);
@@ -812,6 +812,7 @@ static struct igmp_sock *igmp_sock_new(int fd, struct in_addr ifaddr,
 {
        struct pim_interface *pim_ifp;
        struct igmp_sock *igmp;
+       char hash_name[64];
 
        pim_ifp = ifp->info;
 
@@ -836,8 +837,10 @@ static struct igmp_sock *igmp_sock_new(int fd, struct in_addr ifaddr,
        }
        igmp->igmp_group_list->del = (void (*)(void *))igmp_group_free;
 
-       igmp->igmp_group_hash =
-               hash_create(igmp_group_hash_key, igmp_group_hash_equal, NULL);
+       snprintf(hash_name, 64, "IGMP %s hash", ifp->name);
+       igmp->igmp_group_hash = hash_create(igmp_group_hash_key,
+                                           igmp_group_hash_equal,
+                                           hash_name);
 
        igmp->fd = fd;
        igmp->interface = ifp;
index 880d840eacd6528a058e2170db38699751fbe8bf..1fc7517e0564fe7e613482e8a10bfc5bc1b9b5a7 100644 (file)
@@ -198,6 +198,7 @@ static void igmp_source_timer_on(struct igmp_group *group,
                                 struct igmp_source *source, long interval_msec)
 {
        source_timer_off(group, source);
+       struct pim_interface *pim_ifp = group->group_igmp_sock->interface->info;
 
        if (PIM_DEBUG_IGMP_EVENTS) {
                char group_str[INET_ADDRSTRLEN];
@@ -220,7 +221,7 @@ static void igmp_source_timer_on(struct igmp_group *group,
 
          Source timer switched from (T == 0) to (T > 0): enable forwarding.
        */
-       igmp_source_forward_start(source);
+       igmp_source_forward_start(pim_ifp->pim, source);
 }
 
 void igmp_source_reset_gmi(struct igmp_sock *igmp, struct igmp_group *group,
@@ -310,10 +311,12 @@ static void source_clear_send_flag(struct list *source_list)
 */
 static void group_exclude_fwd_anysrc_ifempty(struct igmp_group *group)
 {
+       struct pim_interface *pim_ifp = group->group_igmp_sock->interface->info;
+
        zassert(group->group_filtermode_isexcl);
 
        if (listcount(group->group_source_list) < 1) {
-               igmp_anysource_forward_start(group);
+               igmp_anysource_forward_start(pim_ifp->pim, group);
        }
 }
 
diff --git a/pimd/pim_instance.c b/pimd/pim_instance.c
new file mode 100644 (file)
index 0000000..7fc7755
--- /dev/null
@@ -0,0 +1,218 @@
+/*
+ * PIM for FRR - PIM Instance
+ * Copyright (C) 2017 Cumulus Networks, Inc.
+ * Donald Sharp
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ */
+#include <zebra.h>
+
+#include "hash.h"
+#include "vrf.h"
+
+#include "pimd.h"
+#include "pim_ssm.h"
+#include "pim_rpf.h"
+#include "pim_rp.h"
+#include "pim_mroute.h"
+#include "pim_oil.h"
+#include "pim_static.h"
+#include "pim_ssmpingd.h"
+#include "pim_vty.h"
+
+static void pim_instance_terminate(struct pim_instance *pim)
+{
+       /* Traverse and cleanup rpf_hash */
+       if (pim->rpf_hash) {
+               hash_clean(pim->rpf_hash, (void *)pim_rp_list_hash_clean);
+               hash_free(pim->rpf_hash);
+               pim->rpf_hash = NULL;
+       }
+
+       if (pim->ssm_info) {
+               pim_ssm_terminate(pim->ssm_info);
+               pim->ssm_info = NULL;
+       }
+
+       if (pim->static_routes)
+               list_delete(pim->static_routes);
+
+       pim_rp_free(pim);
+
+       pim_upstream_terminate(pim);
+
+       pim_oil_terminate(pim);
+
+       pim_if_terminate(pim);
+
+       pim_msdp_exit(pim);
+
+       XFREE(MTYPE_PIM_PIM_INSTANCE, pim);
+}
+
+static struct pim_instance *pim_instance_init(struct vrf *vrf)
+{
+       struct pim_instance *pim;
+       char hash_name[64];
+
+       pim = XCALLOC(MTYPE_PIM_PIM_INSTANCE, sizeof(struct pim_instance));
+       if (!pim)
+               return NULL;
+
+       pim_if_init(pim);
+
+       pim->keep_alive_time = PIM_KEEPALIVE_PERIOD;
+       pim->rp_keep_alive_time = PIM_RP_KEEPALIVE_PERIOD;
+
+
+       pim->vrf_id = vrf->vrf_id;
+       pim->vrf = vrf;
+
+       pim->spt.switchover = PIM_SPT_IMMEDIATE;
+       pim->spt.plist = NULL;
+
+       pim_msdp_init(pim, master);
+
+       snprintf(hash_name, 64, "PIM %s RPF Hash", vrf->name);
+       pim->rpf_hash = hash_create_size(256, pim_rpf_hash_key,
+                                        pim_rpf_equal, hash_name);
+
+       if (PIM_DEBUG_ZEBRA)
+               zlog_debug("%s: NHT rpf hash init ", __PRETTY_FUNCTION__);
+
+       pim->ssm_info = pim_ssm_init();
+       if (!pim->ssm_info) {
+               pim_instance_terminate(pim);
+               return NULL;
+       }
+
+       pim->static_routes = list_new();
+       if (!pim->static_routes) {
+               zlog_err("%s %s: failure: static_routes=list_new()", __FILE__,
+                        __PRETTY_FUNCTION__);
+               pim_instance_terminate(pim);
+               return NULL;
+       }
+       pim->static_routes->del = (void (*)(void *))pim_static_route_free;
+
+       pim->send_v6_secondary = 1;
+
+       if (vrf->vrf_id == VRF_DEFAULT)
+               pimg = pim;
+
+       pim_rp_init(pim);
+
+       pim_oil_init(pim);
+
+       pim_upstream_init(pim);
+
+       return pim;
+}
+
+struct pim_instance *pim_get_pim_instance(vrf_id_t vrf_id)
+{
+       struct vrf *vrf = vrf_lookup_by_id(vrf_id);
+
+       if (vrf)
+               return vrf->info;
+
+       return NULL;
+}
+
+static int pim_vrf_new(struct vrf *vrf)
+{
+       struct pim_instance *pim = pim_instance_init(vrf);
+
+       zlog_debug("VRF Created: %s(%d)", vrf->name, vrf->vrf_id);
+       if (pim == NULL) {
+               zlog_err("%s %s: pim class init failure ", __FILE__,
+                        __PRETTY_FUNCTION__);
+               /*
+                * We will crash and burn otherwise
+                */
+               exit(1);
+       }
+
+       vrf->info = (void *)pim;
+
+       if (vrf->vrf_id == VRF_DEFAULT)
+               pimg = pim;
+
+       pim_ssmpingd_init(pim);
+       return 0;
+}
+
+static int pim_vrf_delete(struct vrf *vrf)
+{
+       struct pim_instance *pim = vrf->info;
+
+       zlog_debug("VRF Deletion: %s(%d)", vrf->name, vrf->vrf_id);
+
+       pim_ssmpingd_destroy(pim);
+       pim_instance_terminate(pim);
+       return 0;
+}
+
+/*
+ * Code to turn on the pim instance that
+ * we have created with new
+ */
+static int pim_vrf_enable(struct vrf *vrf)
+{
+       struct pim_instance *pim = (struct pim_instance *)vrf->info;
+
+       zlog_debug("%s: for %s", __PRETTY_FUNCTION__, vrf->name);
+
+       pim_mroute_socket_enable(pim);
+
+       return 0;
+}
+
+static int pim_vrf_disable(struct vrf *vrf)
+{
+       /* Note: This is a callback, the VRF will be deleted by the caller. */
+       return 0;
+}
+
+static int pim_vrf_config_write(struct vty *vty)
+{
+       struct vrf *vrf;
+       struct pim_instance *pim;
+
+       RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name)
+       {
+               pim = vrf->info;
+               if (!pim || vrf->vrf_id != VRF_DEFAULT) {
+                       vty_out(vty, "vrf %s\n", vrf->name);
+                       pim_global_config_write_worker(pim, vty);
+                       vty_out(vty, "!\n");
+               }
+       }
+
+       return 0;
+}
+
+void pim_vrf_init(void)
+{
+       vrf_init(pim_vrf_new, pim_vrf_enable, pim_vrf_disable, pim_vrf_delete);
+
+       vrf_cmd_init(pim_vrf_config_write);
+}
+
+void pim_vrf_terminate(void)
+{
+       vrf_terminate();
+}
diff --git a/pimd/pim_instance.h b/pimd/pim_instance.h
new file mode 100644 (file)
index 0000000..0e91b4c
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * PIM for FRR - PIM Instance
+ * Copyright (C) 2017 Cumulus Networks, Inc.
+ * Donald Sharp
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ */
+#ifndef __PIM_INSTANCE_H__
+#define __PIM_INSTANCE_H__
+
+#include "pim_str.h"
+#include "pim_msdp.h"
+
+#if defined(HAVE_LINUX_MROUTE_H)
+#include <linux/mroute.h>
+#else
+/*
+  Below: from <linux/mroute.h>
+*/
+
+#ifndef MAXVIFS
+#define MAXVIFS (256)
+#endif
+#endif
+extern struct pim_instance *pimg; // Pim Global Instance
+
+enum pim_spt_switchover {
+       PIM_SPT_IMMEDIATE,
+       PIM_SPT_INFINITY,
+};
+
+/* Per VRF PIM DB */
+struct pim_instance {
+       vrf_id_t vrf_id;
+       struct vrf *vrf;
+
+       struct {
+               enum pim_spt_switchover switchover;
+               char *plist;
+       } spt;
+
+       struct hash *rpf_hash;
+
+       void *ssm_info; /* per-vrf SSM configuration */
+
+       int send_v6_secondary;
+
+       struct thread *thread;
+       int mroute_socket;
+       int64_t mroute_socket_creation;
+       int64_t mroute_add_events;
+       int64_t mroute_add_last;
+       int64_t mroute_del_events;
+       int64_t mroute_del_last;
+
+       struct interface *regiface;
+
+       // List of static routes;
+       struct list *static_routes;
+
+       // Upstream vrf specific information
+       struct list *upstream_list;
+       struct hash *upstream_hash;
+       struct timer_wheel *upstream_sg_wheel;
+
+       struct list *rp_list;
+
+       int iface_vif_index[MAXVIFS];
+
+       struct list *channel_oil_list;
+       struct hash *channel_oil_hash;
+
+       struct pim_msdp msdp;
+
+       struct list *ssmpingd_list;
+       struct in_addr ssmpingd_group_addr;
+
+       unsigned int keep_alive_time;
+       unsigned int rp_keep_alive_time;
+};
+
+void pim_vrf_init(void);
+void pim_vrf_terminate(void);
+
+struct pim_instance *pim_get_pim_instance(vrf_id_t vrf_id);
+
+#endif
index 9bc5c2d9cce1f2645685f65eda122879d3e9577c..c60e5a65aaee8826eaf084a18e492539b6c16bf8 100644 (file)
@@ -64,9 +64,9 @@ static void recv_join(struct interface *ifp, struct pim_neighbor *neigh,
                zlog_warn(
                        "%s: join (S,G)=%s rpt=%d wc=%d upstream=%s holdtime=%d from %s on %s",
                        __PRETTY_FUNCTION__, pim_str_sg_dump(sg),
-                       source_flags & PIM_RPT_BIT_MASK,
-                       source_flags & PIM_WILDCARD_BIT_MASK, up_str, holdtime,
-                       neigh_str, ifp->name);
+                       !!(source_flags & PIM_RPT_BIT_MASK),
+                       !!(source_flags & PIM_WILDCARD_BIT_MASK), up_str,
+                       holdtime, neigh_str, ifp->name);
        }
 
        pim_ifp = ifp->info;
@@ -80,14 +80,26 @@ static void recv_join(struct interface *ifp, struct pim_neighbor *neigh,
         */
        if ((source_flags & PIM_RPT_BIT_MASK)
            && (source_flags & PIM_WILDCARD_BIT_MASK)) {
-               struct pim_rpf *rp = RP(sg->grp);
+               struct pim_rpf *rp = RP(pim_ifp->pim, sg->grp);
 
                /*
                 * If the RP sent in the message is not
                 * our RP for the group, drop the message
                 */
-               if (sg->src.s_addr != rp->rpf_addr.u.prefix4.s_addr)
+               if (sg->src.s_addr != rp->rpf_addr.u.prefix4.s_addr) {
+                       char received_rp[INET_ADDRSTRLEN];
+                       char local_rp[INET_ADDRSTRLEN];
+                       pim_inet4_dump("<received?>", sg->src, received_rp,
+                                      sizeof(received_rp));
+                       pim_inet4_dump("<local?>", rp->rpf_addr.u.prefix4,
+                                      local_rp, sizeof(local_rp));
+                       if (PIM_DEBUG_PIM_TRACE)
+                               zlog_warn(
+                                       "%s: Specified RP(%s) in join is different than our configured RP(%s)",
+                                       __PRETTY_FUNCTION__, received_rp,
+                                       local_rp);
                        return;
+               }
 
                sg->src.s_addr = INADDR_ANY;
        }
@@ -124,7 +136,7 @@ static void recv_prune(struct interface *ifp, struct pim_neighbor *neigh,
 
        if ((source_flags & PIM_RPT_BIT_MASK)
            && (source_flags & PIM_WILDCARD_BIT_MASK)) {
-               struct pim_rpf *rp = RP(sg->grp);
+               struct pim_rpf *rp = RP(pim_ifp->pim, sg->grp);
 
                // Ignoring Prune *,G's at the moment.
                if (sg->src.s_addr != rp->rpf_addr.u.prefix4.s_addr)
@@ -294,14 +306,20 @@ int pim_joinprune_recv(struct interface *ifp, struct pim_neighbor *neigh,
                                return -8;
                        }
 
-                       sg_ch = pim_ifchannel_find(ifp, &sg);
-
                        buf += addr_offset;
                        starg_alone = 0;
                        recv_prune(ifp, neigh, msg_holdtime,
                                   msg_upstream_addr.u.prefix4, &sg,
                                   msg_source_flags);
 
+                       /*
+                        * So if we are receiving a S,G,RPT prune
+                        * before we have any data for that S,G
+                        * We need to retrieve the sg_ch after
+                        * we parse the prune.
+                        */
+                       sg_ch = pim_ifchannel_find(ifp, &sg);
+
                        /* Received SG-RPT Prune delete oif from specific S,G */
                        if (starg_ch && sg_ch
                            && (msg_source_flags & PIM_RPT_BIT_MASK)
index 16d55d7bf7d9a78776c840d4dcd85a7c08a2ea3b..8e0b4ab5e8ec0b27d328acbb53f45dfa0b7ca13f 100644 (file)
@@ -108,6 +108,7 @@ void pim_jp_agg_clear_group(struct list *group)
                        js->up = NULL;
                        XFREE(MTYPE_PIM_JP_AGG_SOURCE, js);
                }
+               list_delete(jag->sources);
                jag->sources = NULL;
                listnode_delete(group, jag);
                XFREE(MTYPE_PIM_JP_AGG_GROUP, jag);
@@ -215,9 +216,11 @@ void pim_jp_agg_upstream_verification(struct pim_upstream *up, bool ignore)
 #ifdef PIM_JP_AGG_DEBUG
        struct listnode *node;
        struct interface *ifp;
+       struct pim_interface *pim_ifp = up->rpf.source_nexthop.interface->info;
+       struct pim_instance *pim = pim_ifp->pim;
 
-       for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT), node, ifp)) {
-               struct pim_interface *pim_ifp = ifp->info;
+       for (ALL_LIST_ELEMENTS_RO(vrf_iflist(pim->vrf_id), node, ifp)) {
+               pim_ifp = ifp->info;
                struct listnode *nnode;
 
                if (ignore && ifp == up->rpf.source_nexthop.interface)
index b8e6d8ad3db41d6da1d21e03992fa972b6021d2c..c4cab25ae9b202daa8d5f8b0ce395698e20f5b7d 100644 (file)
@@ -40,6 +40,7 @@
 #include "libfrr.h"
 
 #include "pimd.h"
+#include "pim_instance.h"
 #include "pim_version.h"
 #include "pim_signals.h"
 #include "pim_zebra.h"
@@ -115,7 +116,6 @@ int main(int argc, char **argv, char **envp)
 
        pim_route_map_init();
        pim_init();
-       pim_msdp_init(master);
 
        /*
         * Initialize zclient "update" and "lookup" sockets
index a92b01ca0081745dfe46809c332832e9321e2d92..52d240f54b40a06952e5a17a68c2f9c095ab946a 100644 (file)
@@ -24,6 +24,7 @@
 #include "prefix.h"
 #include "vty.h"
 #include "plist.h"
+#include "sockopt.h"
 
 #include "pimd.h"
 #include "pim_rpf.h"
 #include "pim_ifchannel.h"
 #include "pim_zlookup.h"
 #include "pim_ssm.h"
+#include "pim_sock.h"
 
-/* GLOBAL VARS */
-static struct thread *qpim_mroute_socket_reader = NULL;
+static void mroute_read_on(struct pim_instance *pim);
 
-static void mroute_read_on(void);
-
-static int pim_mroute_set(int fd, int enable)
+static int pim_mroute_set(struct pim_instance *pim, int enable)
 {
        int err;
-       int opt = enable ? MRT_INIT : MRT_DONE;
+       int opt;
        socklen_t opt_len = sizeof(opt);
-       int rcvbuf = 1024 * 1024 * 8;
        long flags;
 
-       err = setsockopt(fd, IPPROTO_IP, opt, &opt, opt_len);
+       /*
+        * We need to create the VRF table for the pim mroute_socket
+        */
+       if (pim->vrf_id != VRF_DEFAULT) {
+               if (pimd_privs.change(ZPRIVS_RAISE))
+                       zlog_err(
+                               "pim_mroute_socket_enable: could not raise privs, %s",
+                               safe_strerror(errno));
+
+               opt = pim->vrf->data.l.table_id;
+               err = setsockopt(pim->mroute_socket, IPPROTO_IP, MRT_TABLE,
+                                &opt, opt_len);
+               if (err) {
+                       zlog_warn(
+                               "%s %s: failure: setsockopt(fd=%d,IPPROTO_IP, MRT_TABLE=%d): errno=%d: %s",
+                               __FILE__, __PRETTY_FUNCTION__,
+                               pim->mroute_socket, opt, errno,
+                               safe_strerror(errno));
+                       return -1;
+               }
+
+               if (pimd_privs.change(ZPRIVS_LOWER))
+                       zlog_err(
+                               "pim_mroute_socket_enable: could not lower privs, %s",
+                               safe_strerror(errno));
+       }
+
+       opt = enable ? MRT_INIT : MRT_DONE;
+       err = setsockopt(pim->mroute_socket, IPPROTO_IP, opt, &opt, opt_len);
        if (err) {
                zlog_warn(
                        "%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,%s=%d): errno=%d: %s",
-                       __FILE__, __PRETTY_FUNCTION__, fd,
+                       __FILE__, __PRETTY_FUNCTION__, pim->mroute_socket,
                        enable ? "MRT_INIT" : "MRT_DONE", opt, errno,
                        safe_strerror(errno));
                return -1;
        }
 
-       err = setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(rcvbuf));
-       if (err) {
-               zlog_warn(
-                       "%s: failure: setsockopt(fd=%d, SOL_SOCKET, %d): errno=%d: %s",
-                       __PRETTY_FUNCTION__, fd, rcvbuf, errno,
-                       safe_strerror(errno));
+#if defined(HAVE_IP_PKTINFO)
+       if (enable) {
+               /* Linux and Solaris IP_PKTINFO */
+               opt = 1;
+               if (setsockopt(pim->mroute_socket, IPPROTO_IP, IP_PKTINFO, &opt,
+                              sizeof(opt))) {
+                       zlog_warn(
+                               "Could not set IP_PKTINFO on socket fd=%d: errno=%d: %s",
+                               pim->mroute_socket, errno,
+                               safe_strerror(errno));
+               }
        }
+#endif
+
+       setsockopt_so_recvbuf(pim->mroute_socket, 1024 * 1024 * 8);
 
-       flags = fcntl(fd, F_GETFL, 0);
+       flags = fcntl(pim->mroute_socket, F_GETFL, 0);
        if (flags < 0) {
-               zlog_warn("Could not get flags on socket fd:%d %d %s", fd,
-                         errno, safe_strerror(errno));
-               close(fd);
+               zlog_warn("Could not get flags on socket fd:%d %d %s",
+                         pim->mroute_socket, errno, safe_strerror(errno));
+               close(pim->mroute_socket);
                return -1;
        }
-       if (fcntl(fd, F_SETFL, flags | O_NONBLOCK)) {
-               zlog_warn("Could not set O_NONBLOCK on socket fd:%d %d %s", fd,
-                         errno, safe_strerror(errno));
-               close(fd);
+       if (fcntl(pim->mroute_socket, F_SETFL, flags | O_NONBLOCK)) {
+               zlog_warn("Could not set O_NONBLOCK on socket fd:%d %d %s",
+                         pim->mroute_socket, errno, safe_strerror(errno));
+               close(pim->mroute_socket);
                return -1;
        }
 
@@ -90,7 +124,7 @@ static int pim_mroute_set(int fd, int enable)
                int upcalls = IGMPMSG_WRVIFWHOLE;
                opt = MRT_PIM;
 
-               err = setsockopt(fd, IPPROTO_IP, opt, &upcalls,
+               err = setsockopt(pim->mroute_socket, IPPROTO_IP, opt, &upcalls,
                                 sizeof(upcalls));
                if (err) {
                        zlog_warn(
@@ -118,7 +152,7 @@ static int pim_mroute_msg_nocache(int fd, struct interface *ifp,
        struct pim_rpf *rpg;
        struct prefix_sg sg;
 
-       rpg = RP(msg->im_dst);
+       rpg = RP(pim_ifp->pim, msg->im_dst);
        /*
         * If the incoming interface is unknown OR
         * the Interface type is SSM we don't need to
@@ -170,7 +204,7 @@ static int pim_mroute_msg_nocache(int fd, struct interface *ifp,
        }
 
        PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up->flags);
-       pim_upstream_keep_alive_timer_start(up, qpim_keep_alive_time);
+       pim_upstream_keep_alive_timer_start(up, pim_ifp->pim->keep_alive_time);
 
        up->channel_oil->cc.pktcnt++;
        PIM_UPSTREAM_FLAG_SET_FHR(up->flags);
@@ -178,6 +212,7 @@ static int pim_mroute_msg_nocache(int fd, struct interface *ifp,
        if (up->channel_oil->oil.mfcc_parent >= MAXVIFS) {
                int vif_index = 0;
                vif_index = pim_if_find_vifindex_by_ifindex(
+                       pim_ifp->pim,
                        up->rpf.source_nexthop.interface->ifindex);
                up->channel_oil->oil.mfcc_parent = vif_index;
        }
@@ -195,23 +230,25 @@ static int pim_mroute_msg_wholepkt(int fd, struct interface *ifp,
        const struct ip *ip_hdr;
        struct pim_upstream *up;
 
+       pim_ifp = ifp->info;
+
        ip_hdr = (const struct ip *)buf;
 
        memset(&sg, 0, sizeof(struct prefix_sg));
        sg.src = ip_hdr->ip_src;
        sg.grp = ip_hdr->ip_dst;
 
-       up = pim_upstream_find(&sg);
+       up = pim_upstream_find(pim_ifp->pim, &sg);
        if (!up) {
                struct prefix_sg star = sg;
                star.src.s_addr = INADDR_ANY;
 
-               up = pim_upstream_find(&star);
+               up = pim_upstream_find(pim_ifp->pim, &star);
 
                if (up && PIM_UPSTREAM_FLAG_TEST_SRC_IGMP(up->flags)) {
-                       up = pim_upstream_add(&sg, ifp,
+                       up = pim_upstream_add(pim_ifp->pim, &sg, ifp,
                                              PIM_UPSTREAM_FLAG_MASK_SRC_LHR,
-                                             __PRETTY_FUNCTION__);
+                                             __PRETTY_FUNCTION__, NULL);
                        if (!up) {
                                if (PIM_DEBUG_MROUTE)
                                        zlog_debug(
@@ -221,9 +258,10 @@ static int pim_mroute_msg_wholepkt(int fd, struct interface *ifp,
                                return 0;
                        }
                        pim_upstream_keep_alive_timer_start(
-                               up, qpim_keep_alive_time);
-                       pim_upstream_inherited_olist(up);
-                       pim_upstream_switch(up, PIM_UPSTREAM_JOINED);
+                               up, pim_ifp->pim->keep_alive_time);
+                       pim_upstream_inherited_olist(pim_ifp->pim, up);
+                       pim_upstream_switch(pim_ifp->pim, up,
+                                           PIM_UPSTREAM_JOINED);
 
                        if (PIM_DEBUG_MROUTE)
                                zlog_debug("%s: Creating %s upstream on LHR",
@@ -240,7 +278,7 @@ static int pim_mroute_msg_wholepkt(int fd, struct interface *ifp,
 
        pim_ifp = up->rpf.source_nexthop.interface->info;
 
-       rpg = RP(sg.grp);
+       rpg = RP(pim_ifp->pim, sg.grp);
 
        if ((pim_rpf_addr_is_inaddr_none(rpg)) || (!pim_ifp)
            || (!(PIM_I_am_DR(pim_ifp)))) {
@@ -255,7 +293,7 @@ static int pim_mroute_msg_wholepkt(int fd, struct interface *ifp,
         * If we've received a register suppress
         */
        if (!up->t_rs_timer) {
-               if (pim_is_grp_ssm(sg.grp)) {
+               if (pim_is_grp_ssm(pim_ifp->pim, sg.grp)) {
                        if (PIM_DEBUG_PIM_REG)
                                zlog_debug(
                                        "%s register forward skipped as group is SSM",
@@ -386,6 +424,8 @@ static int pim_mroute_msg_wrvifwhole(int fd, struct interface *ifp,
        struct prefix_sg sg;
        struct channel_oil *oil;
 
+       pim_ifp = ifp->info;
+
        memset(&sg, 0, sizeof(struct prefix_sg));
        sg.src = ip_hdr->ip_src;
        sg.grp = ip_hdr->ip_dst;
@@ -412,11 +452,11 @@ static int pim_mroute_msg_wrvifwhole(int fd, struct interface *ifp,
     }
 #endif
 
-       up = pim_upstream_find(&sg);
+       up = pim_upstream_find(pim_ifp->pim, &sg);
        if (up) {
                struct pim_upstream *parent;
                struct pim_nexthop source;
-               struct pim_rpf *rpf = RP(sg.grp);
+               struct pim_rpf *rpf = RP(pim_ifp->pim, sg.grp);
                if (!rpf || !rpf->source_nexthop.interface)
                        return 0;
 
@@ -426,7 +466,7 @@ static int pim_mroute_msg_wrvifwhole(int fd, struct interface *ifp,
                 * tree, let's check and if so we can safely drop
                 * it.
                 */
-               parent = pim_upstream_find(&star_g);
+               parent = pim_upstream_find(pim_ifp->pim, &star_g);
                if (parent && parent->rpf.source_nexthop.interface == ifp)
                        return 0;
 
@@ -439,23 +479,25 @@ static int pim_mroute_msg_wrvifwhole(int fd, struct interface *ifp,
                 */
                if (!PIM_UPSTREAM_FLAG_TEST_FHR(up->flags)) {
                        // No if channel, but upstream we are at the RP.
-                       if (pim_nexthop_lookup(&source, up->upstream_register,
-                                              0)
-                           == 0)
+                       if (pim_nexthop_lookup(pim_ifp->pim, &source,
+                                              up->upstream_register, 0)
+                           == 0) {
                                pim_register_stop_send(source.interface, &sg,
                                                       pim_ifp->primary_address,
                                                       up->upstream_register);
+                               up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
+                       }
                        if (!up->channel_oil)
                                up->channel_oil = pim_channel_oil_add(
-                                       &sg, pim_ifp->mroute_vif_index);
-                       pim_upstream_inherited_olist(up);
+                                       pim_ifp->pim, &sg,
+                                       pim_ifp->mroute_vif_index);
+                       pim_upstream_inherited_olist(pim_ifp->pim, up);
                        if (!up->channel_oil->installed)
                                pim_mroute_add(up->channel_oil,
                                               __PRETTY_FUNCTION__);
-                       pim_upstream_set_sptbit(up, ifp);
                } else {
-                       if (I_am_RP(up->sg.grp)) {
-                               if (pim_nexthop_lookup(&source,
+                       if (I_am_RP(pim_ifp->pim, up->sg.grp)) {
+                               if (pim_nexthop_lookup(pim_ifp->pim, &source,
                                                       up->upstream_register, 0)
                                    == 0)
                                        pim_register_stop_send(
@@ -465,20 +507,21 @@ static int pim_mroute_msg_wrvifwhole(int fd, struct interface *ifp,
                                up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
                        }
                        pim_upstream_keep_alive_timer_start(
-                               up, qpim_keep_alive_time);
-                       pim_upstream_inherited_olist(up);
+                               up, pim_ifp->pim->keep_alive_time);
+                       pim_upstream_inherited_olist(pim_ifp->pim, up);
                        pim_mroute_msg_wholepkt(fd, ifp, buf);
                }
                return 0;
        }
 
        pim_ifp = ifp->info;
-       oil = pim_channel_oil_add(&sg, pim_ifp->mroute_vif_index);
+       oil = pim_channel_oil_add(pim_ifp->pim, &sg, pim_ifp->mroute_vif_index);
        if (!oil->installed)
                pim_mroute_add(oil, __PRETTY_FUNCTION__);
        if (pim_if_connected_to_source(ifp, sg.src)) {
-               up = pim_upstream_add(&sg, ifp, PIM_UPSTREAM_FLAG_MASK_FHR,
-                                     __PRETTY_FUNCTION__);
+               up = pim_upstream_add(pim_ifp->pim, &sg, ifp,
+                                     PIM_UPSTREAM_FLAG_MASK_FHR,
+                                     __PRETTY_FUNCTION__, NULL);
                if (!up) {
                        if (PIM_DEBUG_MROUTE)
                                zlog_debug(
@@ -487,11 +530,11 @@ static int pim_mroute_msg_wrvifwhole(int fd, struct interface *ifp,
                        return -2;
                }
                PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up->flags);
-               pim_upstream_keep_alive_timer_start(up, qpim_keep_alive_time);
+               pim_upstream_keep_alive_timer_start(up, pim_ifp->pim->keep_alive_time);
                up->channel_oil = oil;
                up->channel_oil->cc.pktcnt++;
                pim_register_join(up);
-               pim_upstream_inherited_olist(up);
+               pim_upstream_inherited_olist(pim_ifp->pim, up);
 
                // Send the packet to the RP
                pim_mroute_msg_wholepkt(fd, ifp, buf);
@@ -500,7 +543,8 @@ static int pim_mroute_msg_wrvifwhole(int fd, struct interface *ifp,
        return 0;
 }
 
-int pim_mroute_msg(int fd, const char *buf, int buf_size)
+static int pim_mroute_msg(struct pim_instance *pim, const char *buf,
+                         int buf_size, ifindex_t ifindex)
 {
        struct interface *ifp;
        struct pim_interface *pim_ifp;
@@ -523,22 +567,11 @@ int pim_mroute_msg(int fd, const char *buf, int buf_size)
                 * the source
                 * of the IP packet.
                 */
-               ifp = pim_if_lookup_address_vrf(ip_hdr->ip_src, VRF_DEFAULT);
-
-               if (!ifp) {
-                       if (PIM_DEBUG_MROUTE_DETAIL) {
-                               pim_inet4_dump("<src?>", ip_hdr->ip_src,
-                                              ip_src_str, sizeof(ip_src_str));
-                               pim_inet4_dump("<dst?>", ip_hdr->ip_dst,
-                                              ip_dst_str, sizeof(ip_dst_str));
+               ifp = if_lookup_by_index(ifindex, pim->vrf_id);
 
-                               zlog_warn(
-                                       "%s: igmp kernel upcall could not find usable interface for %s -> %s",
-                                       __PRETTY_FUNCTION__, ip_src_str,
-                                       ip_dst_str);
-                       }
+               if (!ifp || !ifp->info)
                        return 0;
-               }
+
                pim_ifp = ifp->info;
                ifaddr = pim_find_primary_addr(ifp);
                igmp = pim_igmp_sock_lookup_ifaddr(pim_ifp->igmp_socket_list,
@@ -551,9 +584,9 @@ int pim_mroute_msg(int fd, const char *buf, int buf_size)
                                       sizeof(ip_dst_str));
 
                        zlog_warn(
-                               "%s: igmp kernel upcall on %s(%p) for %s -> %s",
-                               __PRETTY_FUNCTION__, ifp->name, igmp,
-                               ip_src_str, ip_dst_str);
+                               "%s(%s): igmp kernel upcall on %s(%p) for %s -> %s",
+                               __PRETTY_FUNCTION__, pim->vrf->name, ifp->name,
+                               igmp, ip_src_str, ip_dst_str);
                }
                if (igmp)
                        pim_igmp_packet(igmp, (char *)buf, buf_size);
@@ -573,7 +606,7 @@ int pim_mroute_msg(int fd, const char *buf, int buf_size)
        } else {
                msg = (const struct igmpmsg *)buf;
 
-               ifp = pim_if_find_by_vif_index(msg->im_vif);
+               ifp = pim_if_find_by_vif_index(pim, msg->im_vif);
 
                if (!ifp)
                        return 0;
@@ -586,24 +619,27 @@ int pim_mroute_msg(int fd, const char *buf, int buf_size)
                                "%s: pim kernel upcall %s type=%d ip_p=%d from fd=%d for (S,G)=(%s,%s) on %s vifi=%d  size=%d",
                                __PRETTY_FUNCTION__,
                                igmpmsgtype2str[msg->im_msgtype],
-                               msg->im_msgtype, ip_hdr->ip_p, fd, src_str,
-                               grp_str, ifp->name, msg->im_vif, buf_size);
+                               msg->im_msgtype, ip_hdr->ip_p,
+                               pim->mroute_socket, src_str, grp_str, ifp->name,
+                               msg->im_vif, buf_size);
                }
 
                switch (msg->im_msgtype) {
                case IGMPMSG_WRONGVIF:
-                       return pim_mroute_msg_wrongvif(fd, ifp, msg);
+                       return pim_mroute_msg_wrongvif(pim->mroute_socket, ifp,
+                                                      msg);
                        break;
                case IGMPMSG_NOCACHE:
-                       return pim_mroute_msg_nocache(fd, ifp, msg);
+                       return pim_mroute_msg_nocache(pim->mroute_socket, ifp,
+                                                     msg);
                        break;
                case IGMPMSG_WHOLEPKT:
-                       return pim_mroute_msg_wholepkt(fd, ifp,
+                       return pim_mroute_msg_wholepkt(pim->mroute_socket, ifp,
                                                       (const char *)msg);
                        break;
                case IGMPMSG_WRVIFWHOLE:
-                       return pim_mroute_msg_wrvifwhole(fd, ifp,
-                                                        (const char *)msg);
+                       return pim_mroute_msg_wrvifwhole(
+                               pim->mroute_socket, ifp, (const char *)msg);
                        break;
                default:
                        break;
@@ -615,18 +651,20 @@ int pim_mroute_msg(int fd, const char *buf, int buf_size)
 
 static int mroute_read(struct thread *t)
 {
+       struct pim_instance *pim;
        static long long count;
        char buf[10000];
        int result = 0;
        int cont = 1;
-       int fd;
        int rd;
-
-       fd = THREAD_FD(t);
+       ifindex_t ifindex;
+       pim = THREAD_ARG(t);
 
        while (cont) {
-               rd = read(fd, buf, sizeof(buf));
-               if (rd < 0) {
+               rd = pim_socket_recvfromto(pim->mroute_socket, (uint8_t *)buf,
+                                          sizeof(buf), NULL, NULL, NULL, NULL,
+                                          &ifindex);
+               if (rd <= 0) {
                        if (errno == EINTR)
                                continue;
                        if (errno == EWOULDBLOCK || errno == EAGAIN)
@@ -634,13 +672,14 @@ static int mroute_read(struct thread *t)
 
                        if (PIM_DEBUG_MROUTE)
                                zlog_warn(
-                                       "%s: failure reading fd=%d: errno=%d: %s",
-                                       __PRETTY_FUNCTION__, fd, errno,
+                                       "%s: failure reading rd=%d: fd=%d: errno=%d: %s",
+                                       __PRETTY_FUNCTION__, rd,
+                                       pim->mroute_socket, errno,
                                        safe_strerror(errno));
                        goto done;
                }
 
-               result = pim_mroute_msg(fd, buf, rd);
+               result = pim_mroute_msg(pim, buf, rd, ifindex);
 
                count++;
                if (count % qpim_packet_process == 0)
@@ -648,23 +687,23 @@ static int mroute_read(struct thread *t)
        }
 /* Keep reading */
 done:
-       mroute_read_on();
+       mroute_read_on(pim);
 
        return result;
 }
 
-static void mroute_read_on()
+static void mroute_read_on(struct pim_instance *pim)
 {
-       thread_add_read(master, mroute_read, 0, qpim_mroute_socket_fd,
-                       &qpim_mroute_socket_reader);
+       thread_add_read(master, mroute_read, pim, pim->mroute_socket,
+                       &pim->thread);
 }
 
-static void mroute_read_off()
+static void mroute_read_off(struct pim_instance *pim)
 {
-       THREAD_OFF(qpim_mroute_socket_reader);
+       THREAD_OFF(pim->thread);
 }
 
-int pim_mroute_socket_enable()
+int pim_mroute_socket_enable(struct pim_instance *pim)
 {
        int fd;
 
@@ -674,6 +713,11 @@ int pim_mroute_socket_enable()
 
        fd = socket(AF_INET, SOCK_RAW, IPPROTO_IGMP);
 
+#ifdef SO_BINDTODEVICE
+       setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, pim->vrf->name,
+                  strlen(pim->vrf->name));
+#endif
+
        if (pimd_privs.change(ZPRIVS_LOWER))
                zlog_err("pim_mroute_socket_enable: could not lower privs, %s",
                         safe_strerror(errno));
@@ -684,39 +728,40 @@ int pim_mroute_socket_enable()
                return -2;
        }
 
-       if (pim_mroute_set(fd, 1)) {
+       pim->mroute_socket = fd;
+       if (pim_mroute_set(pim, 1)) {
                zlog_warn(
                        "Could not enable mroute on socket fd=%d: errno=%d: %s",
                        fd, errno, safe_strerror(errno));
                close(fd);
+               pim->mroute_socket = -1;
                return -3;
        }
 
-       qpim_mroute_socket_fd = fd;
+       pim->mroute_socket_creation = pim_time_monotonic_sec();
 
-       qpim_mroute_socket_creation = pim_time_monotonic_sec();
-       mroute_read_on();
+       mroute_read_on(pim);
 
        return 0;
 }
 
-int pim_mroute_socket_disable()
+int pim_mroute_socket_disable(struct pim_instance *pim)
 {
-       if (pim_mroute_set(qpim_mroute_socket_fd, 0)) {
+       if (pim_mroute_set(pim, 0)) {
                zlog_warn(
                        "Could not disable mroute on socket fd=%d: errno=%d: %s",
-                       qpim_mroute_socket_fd, errno, safe_strerror(errno));
+                       pim->mroute_socket, errno, safe_strerror(errno));
                return -2;
        }
 
-       if (close(qpim_mroute_socket_fd)) {
+       if (close(pim->mroute_socket)) {
                zlog_warn("Failure closing mroute socket: fd=%d errno=%d: %s",
-                         qpim_mroute_socket_fd, errno, safe_strerror(errno));
+                         pim->mroute_socket, errno, safe_strerror(errno));
                return -3;
        }
 
-       mroute_read_off();
-       qpim_mroute_socket_fd = -1;
+       mroute_read_off(pim);
+       pim->mroute_socket = -1;
 
        return 0;
 }
@@ -733,6 +778,11 @@ int pim_mroute_add_vif(struct interface *ifp, struct in_addr ifaddr,
        struct vifctl vc;
        int err;
 
+       if (PIM_DEBUG_MROUTE)
+               zlog_debug("%s: Add Vif %d (%s[%s])", __PRETTY_FUNCTION__,
+                          pim_ifp->mroute_vif_index,
+                          ifp->name, pim_ifp->pim->vrf->name);
+
        memset(&vc, 0, sizeof(vc));
        vc.vifc_vifi = pim_ifp->mroute_vif_index;
 #ifdef VIFF_USE_IFINDEX
@@ -757,7 +807,7 @@ int pim_mroute_add_vif(struct interface *ifp, struct in_addr ifaddr,
        }
 #endif
 
-       err = setsockopt(qpim_mroute_socket_fd, IPPROTO_IP, MRT_ADD_VIF,
+       err = setsockopt(pim_ifp->pim->mroute_socket, IPPROTO_IP, MRT_ADD_VIF,
                         (void *)&vc, sizeof(vc));
        if (err) {
                char ifaddr_str[INET_ADDRSTRLEN];
@@ -766,38 +816,38 @@ int pim_mroute_add_vif(struct interface *ifp, struct in_addr ifaddr,
                               sizeof(ifaddr_str));
 
                zlog_warn(
-                       "%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_ADD_VIF,vif_index=%d,ifaddr=%s,flag=%d): errno=%d: %s",
-                       __FILE__, __PRETTY_FUNCTION__, qpim_mroute_socket_fd,
-                       ifp->ifindex, ifaddr_str, flags, errno,
-                       safe_strerror(errno));
+                       "%s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_ADD_VIF,vif_index=%d,ifaddr=%s,flag=%d): errno=%d: %s",
+                       __PRETTY_FUNCTION__,
+                       pim_ifp->pim->mroute_socket, ifp->ifindex, ifaddr_str,
+                       flags, errno, safe_strerror(errno));
                return -2;
        }
 
        return 0;
 }
 
-int pim_mroute_del_vif(int vif_index)
+int pim_mroute_del_vif(struct interface *ifp)
 {
+       struct pim_interface *pim_ifp = ifp->info;
        struct vifctl vc;
        int err;
 
-       if (PIM_DEBUG_MROUTE) {
-               struct interface *ifp = pim_if_find_by_vif_index(vif_index);
-               zlog_debug("%s %s: Del Vif %d (%s) ", __FILE__,
-                          __PRETTY_FUNCTION__, vif_index,
-                          ifp ? ifp->name : "NULL");
-       }
+       if (PIM_DEBUG_MROUTE)
+               zlog_debug("%s: Del Vif %d (%s[%s])",  __PRETTY_FUNCTION__,
+                          pim_ifp->mroute_vif_index,
+                          ifp->name, pim_ifp->pim->vrf->name);
 
        memset(&vc, 0, sizeof(vc));
-       vc.vifc_vifi = vif_index;
+       vc.vifc_vifi = pim_ifp->mroute_vif_index;
 
-       err = setsockopt(qpim_mroute_socket_fd, IPPROTO_IP, MRT_DEL_VIF,
+       err = setsockopt(pim_ifp->pim->mroute_socket, IPPROTO_IP, MRT_DEL_VIF,
                         (void *)&vc, sizeof(vc));
        if (err) {
                zlog_warn(
                        "%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_DEL_VIF,vif_index=%d): errno=%d: %s",
-                       __FILE__, __PRETTY_FUNCTION__, qpim_mroute_socket_fd,
-                       vif_index, errno, safe_strerror(errno));
+                       __FILE__, __PRETTY_FUNCTION__,
+                       pim_ifp->pim->mroute_socket, pim_ifp->mroute_vif_index,
+                       errno, safe_strerror(errno));
                return -2;
        }
 
@@ -806,12 +856,13 @@ int pim_mroute_del_vif(int vif_index)
 
 int pim_mroute_add(struct channel_oil *c_oil, const char *name)
 {
+       struct pim_instance *pim = c_oil->pim;
        int err;
        int orig = 0;
        int orig_iif_vif = 0;
 
-       qpim_mroute_add_last = pim_time_monotonic_sec();
-       ++qpim_mroute_add_events;
+       pim->mroute_add_last = pim_time_monotonic_sec();
+       ++pim->mroute_add_events;
 
        /* Do not install route if incoming interface is undefined. */
        if (c_oil->oil.mfcc_parent >= MAXVIFS) {
@@ -846,14 +897,14 @@ int pim_mroute_add(struct channel_oil *c_oil, const char *name)
                orig_iif_vif = c_oil->oil.mfcc_parent;
                c_oil->oil.mfcc_parent = 0;
        }
-       err = setsockopt(qpim_mroute_socket_fd, IPPROTO_IP, MRT_ADD_MFC,
+       err = setsockopt(pim->mroute_socket, IPPROTO_IP, MRT_ADD_MFC,
                         &c_oil->oil, sizeof(c_oil->oil));
 
        if (!err && !c_oil->installed
            && c_oil->oil.mfcc_origin.s_addr != INADDR_ANY
            && orig_iif_vif != 0) {
                c_oil->oil.mfcc_parent = orig_iif_vif;
-               err = setsockopt(qpim_mroute_socket_fd, IPPROTO_IP, MRT_ADD_MFC,
+               err = setsockopt(pim->mroute_socket, IPPROTO_IP, MRT_ADD_MFC,
                                 &c_oil->oil, sizeof(c_oil->oil));
        }
 
@@ -863,14 +914,15 @@ int pim_mroute_add(struct channel_oil *c_oil, const char *name)
        if (err) {
                zlog_warn(
                        "%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_ADD_MFC): errno=%d: %s",
-                       __FILE__, __PRETTY_FUNCTION__, qpim_mroute_socket_fd,
+                       __FILE__, __PRETTY_FUNCTION__, pim->mroute_socket,
                        errno, safe_strerror(errno));
                return -2;
        }
 
        if (PIM_DEBUG_MROUTE) {
                char buf[1000];
-               zlog_debug("%s(%s), Added Route: %s", __PRETTY_FUNCTION__, name,
+               zlog_debug("%s(%s), vrf %s Added Route: %s", __PRETTY_FUNCTION__, name,
+                          pim->vrf->name,
                           pim_channel_oil_dump(c_oil, buf, sizeof(buf)));
        }
 
@@ -880,10 +932,11 @@ int pim_mroute_add(struct channel_oil *c_oil, const char *name)
 
 int pim_mroute_del(struct channel_oil *c_oil, const char *name)
 {
+       struct pim_instance *pim = c_oil->pim;
        int err;
 
-       qpim_mroute_del_last = pim_time_monotonic_sec();
-       ++qpim_mroute_del_events;
+       pim->mroute_del_last = pim_time_monotonic_sec();
+       ++pim->mroute_del_events;
 
        if (!c_oil->installed) {
                if (PIM_DEBUG_MROUTE) {
@@ -897,22 +950,23 @@ int pim_mroute_del(struct channel_oil *c_oil, const char *name)
                return -2;
        }
 
-       err = setsockopt(qpim_mroute_socket_fd, IPPROTO_IP, MRT_DEL_MFC,
+       err = setsockopt(pim->mroute_socket, IPPROTO_IP, MRT_DEL_MFC,
                         &c_oil->oil, sizeof(c_oil->oil));
        if (err) {
                if (PIM_DEBUG_MROUTE)
                        zlog_warn(
                                "%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_DEL_MFC): errno=%d: %s",
                                __FILE__, __PRETTY_FUNCTION__,
-                               qpim_mroute_socket_fd, errno,
+                               pim->mroute_socket, errno,
                                safe_strerror(errno));
                return -2;
        }
 
        if (PIM_DEBUG_MROUTE) {
                char buf[1000];
-               zlog_debug("%s(%s), Deleted Route: %s", __PRETTY_FUNCTION__,
-                          name, pim_channel_oil_dump(c_oil, buf, sizeof(buf)));
+               zlog_debug("%s(%s), vrf %s Deleted Route: %s", __PRETTY_FUNCTION__,
+                          name, pim->vrf->name,
+                          pim_channel_oil_dump(c_oil, buf, sizeof(buf)));
        }
 
        // Reset kernel installed flag
@@ -923,6 +977,7 @@ int pim_mroute_del(struct channel_oil *c_oil, const char *name)
 
 void pim_mroute_update_counters(struct channel_oil *c_oil)
 {
+       struct pim_instance *pim = c_oil->pim;
        struct sioc_sg_req sgreq;
 
        c_oil->cc.oldpktcnt = c_oil->cc.pktcnt;
@@ -930,7 +985,7 @@ void pim_mroute_update_counters(struct channel_oil *c_oil)
        c_oil->cc.oldwrong_if = c_oil->cc.wrong_if;
 
        if (!c_oil->installed) {
-               c_oil->cc.lastused = 100 * qpim_keep_alive_time;
+               c_oil->cc.lastused = 100 * pim->keep_alive_time;
                if (PIM_DEBUG_MROUTE) {
                        struct prefix_sg sg;
 
@@ -949,7 +1004,7 @@ void pim_mroute_update_counters(struct channel_oil *c_oil)
        sgreq.grp = c_oil->oil.mfcc_mcastgrp;
 
        pim_zlookup_sg_statistics(c_oil);
-       if (ioctl(qpim_mroute_socket_fd, SIOCGETSGCNT, &sgreq)) {
+       if (ioctl(pim->mroute_socket, SIOCGETSGCNT, &sgreq)) {
                if (PIM_DEBUG_MROUTE) {
                        struct prefix_sg sg;
 
index eb6c40b676508e7d43752d1a57981722b41ff213..bd71acbf82cab506d7e05a161ea575585f0d4c63 100644 (file)
 #define MRT_PIM      (MRT_BASE+8)    /* enable PIM code      */
 #endif
 
+#ifndef MRT_TABLE
+#define MRT_TABLE    (209)           /* Specify mroute table ID */
+#endif
+
 #ifndef HAVE_VIFI_T
 typedef unsigned short vifi_t;
 #endif
@@ -163,17 +167,15 @@ struct igmpmsg {
   Above: from <linux/mroute.h>
 */
 
-int pim_mroute_socket_enable(void);
-int pim_mroute_socket_disable(void);
+int pim_mroute_socket_enable(struct pim_instance *pim);
+int pim_mroute_socket_disable(struct pim_instance *pim);
 
 int pim_mroute_add_vif(struct interface *ifp, struct in_addr ifaddr,
                       unsigned char flags);
-int pim_mroute_del_vif(int vif_index);
+int pim_mroute_del_vif(struct interface *ifp);
 
 int pim_mroute_add(struct channel_oil *c_oil, const char *name);
 int pim_mroute_del(struct channel_oil *c_oil, const char *name);
 
-int pim_mroute_msg(int fd, const char *buf, int buf_size);
-
 void pim_mroute_update_counters(struct channel_oil *c_oil);
 #endif /* PIM_MROUTE_H */
index 0f653e70a4310d2887bc2bef686fb99097e5ff30..4b049d90ad4bd07cc5b8daf7230371736d817edb 100644 (file)
 #include "pim_str.h"
 #include "pim_time.h"
 #include "pim_upstream.h"
+#include "pim_oil.h"
 
 #include "pim_msdp.h"
 #include "pim_msdp_packet.h"
 #include "pim_msdp_socket.h"
 
-struct pim_msdp pim_msdp, *msdp = &pim_msdp;
+// struct pim_msdp pim_msdp, *msdp = &pim_msdp;
 
 static void pim_msdp_peer_listen(struct pim_msdp_peer *mp);
 static void pim_msdp_peer_cr_timer_setup(struct pim_msdp_peer *mp, bool start);
@@ -50,8 +51,8 @@ static void pim_msdp_peer_ka_timer_setup(struct pim_msdp_peer *mp, bool start);
 static void pim_msdp_peer_hold_timer_setup(struct pim_msdp_peer *mp,
                                           bool start);
 static void pim_msdp_peer_free(struct pim_msdp_peer *mp);
-static void pim_msdp_enable(void);
-static void pim_msdp_sa_adv_timer_setup(bool start);
+static void pim_msdp_enable(struct pim_instance *pim);
+static void pim_msdp_sa_adv_timer_setup(struct pim_instance *pim, bool start);
 static void pim_msdp_sa_deref(struct pim_msdp_sa *sa,
                              enum pim_msdp_sa_flags flags);
 static int pim_msdp_mg_mbr_comp(const void *p1, const void *p2);
@@ -69,21 +70,23 @@ static void pim_msdp_sa_timer_expiry_log(struct pim_msdp_sa *sa,
 /* RFC-3618:Sec-5.1 - global active source advertisement timer */
 static int pim_msdp_sa_adv_timer_cb(struct thread *t)
 {
+       struct pim_instance *pim = THREAD_ARG(t);
+
        if (PIM_DEBUG_MSDP_EVENTS) {
                zlog_debug("MSDP SA advertisment timer expired");
        }
 
-       pim_msdp_sa_adv_timer_setup(true /* start */);
-       pim_msdp_pkt_sa_tx();
+       pim_msdp_sa_adv_timer_setup(pim, true /* start */);
+       pim_msdp_pkt_sa_tx(pim);
        return 0;
 }
-static void pim_msdp_sa_adv_timer_setup(bool start)
+static void pim_msdp_sa_adv_timer_setup(struct pim_instance *pim, bool start)
 {
-       THREAD_OFF(msdp->sa_adv_timer);
+       THREAD_OFF(pim->msdp.sa_adv_timer);
        if (start) {
-               thread_add_timer(msdp->master, pim_msdp_sa_adv_timer_cb, NULL,
-                                PIM_MSDP_SA_ADVERTISMENT_TIME,
-                                &msdp->sa_adv_timer);
+               thread_add_timer(pim->msdp.master, pim_msdp_sa_adv_timer_cb,
+                                pim, PIM_MSDP_SA_ADVERTISMENT_TIME,
+                                &pim->msdp.sa_adv_timer);
        }
 }
 
@@ -105,7 +108,8 @@ static void pim_msdp_sa_state_timer_setup(struct pim_msdp_sa *sa, bool start)
 {
        THREAD_OFF(sa->sa_state_timer);
        if (start) {
-               thread_add_timer(msdp->master, pim_msdp_sa_state_timer_cb, sa,
+               thread_add_timer(sa->pim->msdp.master,
+                                pim_msdp_sa_state_timer_cb, sa,
                                 PIM_MSDP_SA_HOLD_TIME, &sa->sa_state_timer);
        }
 }
@@ -121,7 +125,7 @@ static void pim_msdp_sa_upstream_del(struct pim_msdp_sa *sa)
        if (PIM_UPSTREAM_FLAG_TEST_SRC_MSDP(up->flags)) {
                PIM_UPSTREAM_FLAG_UNSET_SRC_MSDP(up->flags);
                sa->flags |= PIM_MSDP_SAF_UP_DEL_IN_PROG;
-               pim_upstream_del(up, __PRETTY_FUNCTION__);
+               pim_upstream_del(sa->pim, up, __PRETTY_FUNCTION__);
                sa->flags &= ~PIM_MSDP_SAF_UP_DEL_IN_PROG;
        }
 
@@ -138,7 +142,7 @@ static bool pim_msdp_sa_upstream_add_ok(struct pim_msdp_sa *sa,
                return false;
        }
        /* check if we are RP */
-       if (!I_am_RP(sa->sg.grp)) {
+       if (!I_am_RP(sa->pim, sa->sg.grp)) {
                return false;
        }
 
@@ -149,7 +153,7 @@ static bool pim_msdp_sa_upstream_add_ok(struct pim_msdp_sa *sa,
                memset(&sg, 0, sizeof(sg));
                sg.grp = sa->sg.grp;
 
-               xg_up = pim_upstream_find(&sg);
+               xg_up = pim_upstream_find(sa->pim, &sg);
        }
        if (!xg_up || (xg_up->join_state != PIM_UPSTREAM_JOINED)) {
                /* join desired will be true for such (*, G) entries so we will
@@ -186,7 +190,7 @@ static void pim_msdp_sa_upstream_update(struct pim_msdp_sa *sa,
                return;
        }
 
-       up = pim_upstream_find(&sa->sg);
+       up = pim_upstream_find(sa->pim, &sa->sg);
        if (up && (PIM_UPSTREAM_FLAG_TEST_SRC_MSDP(up->flags))) {
                /* somehow we lost track of the upstream ptr? best log it */
                sa->up = up;
@@ -199,14 +203,14 @@ static void pim_msdp_sa_upstream_update(struct pim_msdp_sa *sa,
 
        /* RFC3618: "RP triggers a (S, G) join event towards the data source
         * as if a JP message was rxed addressed to the RP itself." */
-       up = pim_upstream_add(&sa->sg, NULL /* iif */,
+       up = pim_upstream_add(sa->pim, &sa->sg, NULL /* iif */,
                              PIM_UPSTREAM_FLAG_MASK_SRC_MSDP,
-                             __PRETTY_FUNCTION__);
+                             __PRETTY_FUNCTION__, NULL);
 
        sa->up = up;
        if (up) {
                /* update inherited oil */
-               pim_upstream_inherited_olist(up);
+               pim_upstream_inherited_olist(sa->pim, up);
                /* should we also start the kat in parallel? we will need it
                 * when the
                 * SA ages out */
@@ -227,7 +231,8 @@ static void pim_msdp_sa_free(struct pim_msdp_sa *sa)
        XFREE(MTYPE_PIM_MSDP_SA, sa);
 }
 
-static struct pim_msdp_sa *pim_msdp_sa_new(struct prefix_sg *sg,
+static struct pim_msdp_sa *pim_msdp_sa_new(struct pim_instance *pim,
+                                          struct prefix_sg *sg,
                                           struct in_addr rp)
 {
        struct pim_msdp_sa *sa;
@@ -239,19 +244,20 @@ static struct pim_msdp_sa *pim_msdp_sa_new(struct prefix_sg *sg,
                return NULL;
        }
 
+       sa->pim = pim;
        sa->sg = *sg;
        pim_str_sg_set(sg, sa->sg_str);
        sa->rp = rp;
        sa->uptime = pim_time_monotonic_sec();
 
        /* insert into misc tables for easy access */
-       sa = hash_get(msdp->sa_hash, sa, hash_alloc_intern);
+       sa = hash_get(pim->msdp.sa_hash, sa, hash_alloc_intern);
        if (!sa) {
                zlog_err("%s: PIM hash get failure", __PRETTY_FUNCTION__);
                pim_msdp_sa_free(sa);
                return NULL;
        }
-       listnode_add_sort(msdp->sa_list, sa);
+       listnode_add_sort(pim->msdp.sa_list, sa);
 
        if (PIM_DEBUG_MSDP_EVENTS) {
                zlog_debug("MSDP SA %s created", sa->sg_str);
@@ -260,25 +266,27 @@ static struct pim_msdp_sa *pim_msdp_sa_new(struct prefix_sg *sg,
        return sa;
 }
 
-static struct pim_msdp_sa *pim_msdp_sa_find(struct prefix_sg *sg)
+static struct pim_msdp_sa *pim_msdp_sa_find(struct pim_instance *pim,
+                                           struct prefix_sg *sg)
 {
        struct pim_msdp_sa lookup;
 
        lookup.sg = *sg;
-       return hash_lookup(msdp->sa_hash, &lookup);
+       return hash_lookup(pim->msdp.sa_hash, &lookup);
 }
 
-static struct pim_msdp_sa *pim_msdp_sa_add(struct prefix_sg *sg,
+static struct pim_msdp_sa *pim_msdp_sa_add(struct pim_instance *pim,
+                                          struct prefix_sg *sg,
                                           struct in_addr rp)
 {
        struct pim_msdp_sa *sa;
 
-       sa = pim_msdp_sa_find(sg);
+       sa = pim_msdp_sa_find(pim, sg);
        if (sa) {
                return sa;
        }
 
-       return pim_msdp_sa_new(sg, rp);
+       return pim_msdp_sa_new(pim, sg, rp);
 }
 
 static void pim_msdp_sa_del(struct pim_msdp_sa *sa)
@@ -291,8 +299,8 @@ static void pim_msdp_sa_del(struct pim_msdp_sa *sa)
        pim_msdp_sa_state_timer_setup(sa, false /* start */);
 
        /* remove the entry from various tables */
-       listnode_delete(msdp->sa_list, sa);
-       hash_release(msdp->sa_hash, sa);
+       listnode_delete(sa->pim->msdp.sa_list, sa);
+       hash_release(sa->pim->msdp.sa_hash, sa);
 
        if (PIM_DEBUG_MSDP_EVENTS) {
                zlog_debug("MSDP SA %s deleted", sa->sg_str);
@@ -315,7 +323,7 @@ static void pim_msdp_sa_peer_ip_set(struct pim_msdp_sa *sa,
 
        /* any time the peer ip changes also update the rp address */
        if (PIM_INADDR_ISNOT_ANY(sa->peer)) {
-               old_mp = pim_msdp_peer_find(sa->peer);
+               old_mp = pim_msdp_peer_find(sa->pim, sa->peer);
                if (old_mp && old_mp->sa_cnt) {
                        --old_mp->sa_cnt;
                }
@@ -349,8 +357,8 @@ static void pim_msdp_sa_deref(struct pim_msdp_sa *sa,
                                zlog_debug("MSDP SA %s local reference removed",
                                           sa->sg_str);
                        }
-                       if (msdp->local_cnt)
-                               --msdp->local_cnt;
+                       if (sa->pim->msdp.local_cnt)
+                               --sa->pim->msdp.local_cnt;
                }
        }
 
@@ -382,12 +390,12 @@ static void pim_msdp_sa_deref(struct pim_msdp_sa *sa,
        }
 }
 
-void pim_msdp_sa_ref(struct pim_msdp_peer *mp, struct prefix_sg *sg,
-                    struct in_addr rp)
+void pim_msdp_sa_ref(struct pim_instance *pim, struct pim_msdp_peer *mp,
+                    struct prefix_sg *sg, struct in_addr rp)
 {
        struct pim_msdp_sa *sa;
 
-       sa = pim_msdp_sa_add(sg, rp);
+       sa = pim_msdp_sa_add(pim, sg, rp);
        if (!sa) {
                return;
        }
@@ -412,7 +420,7 @@ void pim_msdp_sa_ref(struct pim_msdp_peer *mp, struct prefix_sg *sg,
        } else {
                if (!(sa->flags & PIM_MSDP_SAF_LOCAL)) {
                        sa->flags |= PIM_MSDP_SAF_LOCAL;
-                       ++msdp->local_cnt;
+                       ++sa->pim->msdp.local_cnt;
                        if (PIM_DEBUG_MSDP_EVENTS) {
                                zlog_debug("MSDP SA %s added locally",
                                           sa->sg_str);
@@ -438,7 +446,9 @@ void pim_msdp_sa_ref(struct pim_msdp_peer *mp, struct prefix_sg *sg,
  */
 static bool pim_msdp_sa_local_add_ok(struct pim_upstream *up)
 {
-       if (!(msdp->flags & PIM_MSDPF_ENABLE)) {
+       struct pim_instance *pim = up->channel_oil->pim;
+
+       if (!(pim->msdp.flags & PIM_MSDPF_ENABLE)) {
                return false;
        }
 
@@ -447,7 +457,7 @@ static bool pim_msdp_sa_local_add_ok(struct pim_upstream *up)
                return false;
        }
 
-       if (!I_am_RP(up->sg.grp)) {
+       if (!I_am_RP(pim, up->sg.grp)) {
                /* we are not RP for the group */
                return false;
        }
@@ -462,18 +472,19 @@ static bool pim_msdp_sa_local_add_ok(struct pim_upstream *up)
        return false;
 }
 
-static void pim_msdp_sa_local_add(struct prefix_sg *sg)
+static void pim_msdp_sa_local_add(struct pim_instance *pim,
+                                 struct prefix_sg *sg)
 {
        struct in_addr rp;
        rp.s_addr = 0;
-       pim_msdp_sa_ref(NULL /* mp */, sg, rp);
+       pim_msdp_sa_ref(pim, NULL /* mp */, sg, rp);
 }
 
-void pim_msdp_sa_local_del(struct prefix_sg *sg)
+void pim_msdp_sa_local_del(struct pim_instance *pim, struct prefix_sg *sg)
 {
        struct pim_msdp_sa *sa;
 
-       sa = pim_msdp_sa_find(sg);
+       sa = pim_msdp_sa_find(pim, sg);
        if (sa) {
                pim_msdp_sa_deref(sa, PIM_MSDP_SAF_LOCAL);
        }
@@ -481,11 +492,12 @@ void pim_msdp_sa_local_del(struct prefix_sg *sg)
 
 /* we need to be very cautious with this API as SA del too can trigger an
  * upstream del and we will get stuck in a simple loop */
-static void pim_msdp_sa_local_del_on_up_del(struct prefix_sg *sg)
+static void pim_msdp_sa_local_del_on_up_del(struct pim_instance *pim,
+                                           struct prefix_sg *sg)
 {
        struct pim_msdp_sa *sa;
 
-       sa = pim_msdp_sa_find(sg);
+       sa = pim_msdp_sa_find(pim, sg);
        if (sa) {
                if (PIM_DEBUG_MSDP_INTERNAL) {
                        zlog_debug("MSDP local sa %s del on up del",
@@ -543,32 +555,34 @@ static void pim_msdp_sa_local_del_on_up_del(struct prefix_sg *sg)
  */
 void pim_msdp_sa_local_update(struct pim_upstream *up)
 {
+       struct pim_instance *pim = up->channel_oil->pim;
+
        if (pim_msdp_sa_local_add_ok(up)) {
-               pim_msdp_sa_local_add(&up->sg);
+               pim_msdp_sa_local_add(pim, &up->sg);
        } else {
-               pim_msdp_sa_local_del(&up->sg);
+               pim_msdp_sa_local_del(pim, &up->sg);
        }
 }
 
-static void pim_msdp_sa_local_setup(void)
+static void pim_msdp_sa_local_setup(struct pim_instance *pim)
 {
        struct pim_upstream *up;
        struct listnode *up_node;
 
-       for (ALL_LIST_ELEMENTS_RO(pim_upstream_list, up_node, up)) {
+       for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, up_node, up)) {
                pim_msdp_sa_local_update(up);
        }
 }
 
 /* whenever the RP changes we need to re-evaluate the "local" SA-cache */
 /* XXX: needs to be tested */
-void pim_msdp_i_am_rp_changed(void)
+void pim_msdp_i_am_rp_changed(struct pim_instance *pim)
 {
        struct listnode *sanode;
        struct listnode *nextnode;
        struct pim_msdp_sa *sa;
 
-       if (!(msdp->flags & PIM_MSDPF_ENABLE)) {
+       if (!(pim->msdp.flags & PIM_MSDPF_ENABLE)) {
                /* if the feature is not enabled do nothing */
                return;
        }
@@ -578,16 +592,16 @@ void pim_msdp_i_am_rp_changed(void)
        }
 
        /* mark all local entries as stale */
-       for (ALL_LIST_ELEMENTS_RO(msdp->sa_list, sanode, sa)) {
+       for (ALL_LIST_ELEMENTS_RO(pim->msdp.sa_list, sanode, sa)) {
                if (sa->flags & PIM_MSDP_SAF_LOCAL) {
                        sa->flags |= PIM_MSDP_SAF_STALE;
                }
        }
 
        /* re-setup local SA entries */
-       pim_msdp_sa_local_setup();
+       pim_msdp_sa_local_setup(pim);
 
-       for (ALL_LIST_ELEMENTS(msdp->sa_list, sanode, nextnode, sa)) {
+       for (ALL_LIST_ELEMENTS(pim->msdp.sa_list, sanode, nextnode, sa)) {
                /* purge stale SA entries */
                if (sa->flags & PIM_MSDP_SAF_STALE) {
                        /* clear the stale flag; the entry may be kept even
@@ -609,7 +623,8 @@ void pim_msdp_i_am_rp_changed(void)
 /* We track the join state of (*, G) entries. If G has sources in the SA-cache
  * we need to setup or teardown SPT when the JoinDesired status changes for
  * (*, G) */
-void pim_msdp_up_join_state_changed(struct pim_upstream *xg_up)
+void pim_msdp_up_join_state_changed(struct pim_instance *pim,
+                                   struct pim_upstream *xg_up)
 {
        struct listnode *sanode;
        struct pim_msdp_sa *sa;
@@ -626,7 +641,7 @@ void pim_msdp_up_join_state_changed(struct pim_upstream *xg_up)
 
        /* XXX: Need to maintain SAs per-group to avoid all this unnecessary
         * walking */
-       for (ALL_LIST_ELEMENTS_RO(msdp->sa_list, sanode, sa)) {
+       for (ALL_LIST_ELEMENTS_RO(pim->msdp.sa_list, sanode, sa)) {
                if (sa->sg.grp.s_addr != xg_up->sg.grp.s_addr) {
                        continue;
                }
@@ -634,7 +649,7 @@ void pim_msdp_up_join_state_changed(struct pim_upstream *xg_up)
        }
 }
 
-static void pim_msdp_up_xg_del(struct prefix_sg *sg)
+static void pim_msdp_up_xg_del(struct pim_instance *pim, struct prefix_sg *sg)
 {
        struct listnode *sanode;
        struct pim_msdp_sa *sa;
@@ -650,7 +665,7 @@ static void pim_msdp_up_xg_del(struct prefix_sg *sg)
 
        /* XXX: Need to maintain SAs per-group to avoid all this unnecessary
         * walking */
-       for (ALL_LIST_ELEMENTS_RO(msdp->sa_list, sanode, sa)) {
+       for (ALL_LIST_ELEMENTS_RO(pim->msdp.sa_list, sanode, sa)) {
                if (sa->sg.grp.s_addr != sg->grp.s_addr) {
                        continue;
                }
@@ -658,15 +673,15 @@ static void pim_msdp_up_xg_del(struct prefix_sg *sg)
        }
 }
 
-void pim_msdp_up_del(struct prefix_sg *sg)
+void pim_msdp_up_del(struct pim_instance *pim, struct prefix_sg *sg)
 {
        if (PIM_DEBUG_MSDP_INTERNAL) {
                zlog_debug("MSDP up %s del", pim_str_sg_dump(sg));
        }
        if (sg->src.s_addr == INADDR_ANY) {
-               pim_msdp_up_xg_del(sg);
+               pim_msdp_up_xg_del(pim, sg);
        } else {
-               pim_msdp_sa_local_del_on_up_del(sg);
+               pim_msdp_sa_local_del_on_up_del(pim, sg);
        }
 }
 
@@ -797,7 +812,7 @@ static void pim_msdp_peer_listen(struct pim_msdp_peer *mp)
        * first listening peer is configured; but don't bother tearing it down
        * when
        * all the peers go down */
-       pim_msdp_sock_listen();
+       pim_msdp_sock_listen(mp->pim);
 }
 
 /* 11.2.A4 and 11.2.A5: transition active or passive peer to
@@ -913,12 +928,14 @@ static int pim_msdp_peer_hold_timer_cb(struct thread *t)
        pim_msdp_peer_reset_tcp_conn(mp, "ht-expired");
        return 0;
 }
+
 static void pim_msdp_peer_hold_timer_setup(struct pim_msdp_peer *mp, bool start)
 {
+       struct pim_instance *pim = mp->pim;
        THREAD_OFF(mp->hold_timer);
        if (start) {
-               thread_add_timer(msdp->master, pim_msdp_peer_hold_timer_cb, mp,
-                                PIM_MSDP_PEER_HOLD_TIME, &mp->hold_timer);
+               thread_add_timer(pim->msdp.master, pim_msdp_peer_hold_timer_cb,
+                                mp, PIM_MSDP_PEER_HOLD_TIME, &mp->hold_timer);
        }
 }
 
@@ -942,7 +959,8 @@ static void pim_msdp_peer_ka_timer_setup(struct pim_msdp_peer *mp, bool start)
 {
        THREAD_OFF(mp->ka_timer);
        if (start) {
-               thread_add_timer(msdp->master, pim_msdp_peer_ka_timer_cb, mp,
+               thread_add_timer(mp->pim->msdp.master,
+                                pim_msdp_peer_ka_timer_cb, mp,
                                 PIM_MSDP_PEER_KA_TIME, &mp->ka_timer);
        }
 }
@@ -1005,9 +1023,9 @@ static void pim_msdp_peer_cr_timer_setup(struct pim_msdp_peer *mp, bool start)
 {
        THREAD_OFF(mp->cr_timer);
        if (start) {
-               thread_add_timer(msdp->master, pim_msdp_peer_cr_timer_cb, mp,
-                                PIM_MSDP_PEER_CONNECT_RETRY_TIME,
-                                &mp->cr_timer);
+               thread_add_timer(
+                       mp->pim->msdp.master, pim_msdp_peer_cr_timer_cb, mp,
+                       PIM_MSDP_PEER_CONNECT_RETRY_TIME, &mp->cr_timer);
        }
 }
 
@@ -1043,14 +1061,15 @@ static void pim_msdp_addr2su(union sockunion *su, struct in_addr addr)
 }
 
 /* 11.2.A1: create a new peer and transition state to listen or connecting */
-static enum pim_msdp_err pim_msdp_peer_new(struct in_addr peer_addr,
+static enum pim_msdp_err pim_msdp_peer_new(struct pim_instance *pim,
+                                          struct in_addr peer_addr,
                                           struct in_addr local_addr,
                                           const char *mesh_group_name,
                                           struct pim_msdp_peer **mp_p)
 {
        struct pim_msdp_peer *mp;
 
-       pim_msdp_enable();
+       pim_msdp_enable(pim);
 
        mp = XCALLOC(MTYPE_PIM_MSDP_PEER, sizeof(*mp));
        if (!mp) {
@@ -1059,12 +1078,13 @@ static enum pim_msdp_err pim_msdp_peer_new(struct in_addr peer_addr,
                return PIM_MSDP_ERR_OOM;
        }
 
+       mp->pim = pim;
        mp->peer = peer_addr;
        pim_inet4_dump("<peer?>", mp->peer, mp->key_str, sizeof(mp->key_str));
        pim_msdp_addr2su(&mp->su_peer, mp->peer);
        mp->local = local_addr;
        /* XXX: originator_id setting needs to move to the mesh group */
-       msdp->originator_id = local_addr;
+       pim->msdp.originator_id = local_addr;
        pim_msdp_addr2su(&mp->su_local, mp->local);
        mp->mesh_group_name = XSTRDUP(MTYPE_PIM_MSDP_MG_NAME, mesh_group_name);
        mp->state = PIM_MSDP_INACTIVE;
@@ -1080,8 +1100,8 @@ static enum pim_msdp_err pim_msdp_peer_new(struct in_addr peer_addr,
        mp->obuf = stream_fifo_new();
 
        /* insert into misc tables for easy access */
-       mp = hash_get(msdp->peer_hash, mp, hash_alloc_intern);
-       listnode_add_sort(msdp->peer_list, mp);
+       mp = hash_get(pim->msdp.peer_hash, mp, hash_alloc_intern);
+       listnode_add_sort(pim->msdp.peer_list, mp);
 
        if (PIM_DEBUG_MSDP_EVENTS) {
                zlog_debug("MSDP peer %s created", mp->key_str);
@@ -1101,16 +1121,18 @@ static enum pim_msdp_err pim_msdp_peer_new(struct in_addr peer_addr,
        return PIM_MSDP_ERR_NONE;
 }
 
-struct pim_msdp_peer *pim_msdp_peer_find(struct in_addr peer_addr)
+struct pim_msdp_peer *pim_msdp_peer_find(struct pim_instance *pim,
+                                        struct in_addr peer_addr)
 {
        struct pim_msdp_peer lookup;
 
        lookup.peer = peer_addr;
-       return hash_lookup(msdp->peer_hash, &lookup);
+       return hash_lookup(pim->msdp.peer_hash, &lookup);
 }
 
 /* add peer configuration if it doesn't already exist */
-enum pim_msdp_err pim_msdp_peer_add(struct in_addr peer_addr,
+enum pim_msdp_err pim_msdp_peer_add(struct pim_instance *pim,
+                                   struct in_addr peer_addr,
                                    struct in_addr local_addr,
                                    const char *mesh_group_name,
                                    struct pim_msdp_peer **mp_p)
@@ -1133,7 +1155,7 @@ enum pim_msdp_err pim_msdp_peer_add(struct in_addr peer_addr,
                return PIM_MSDP_ERR_SIP_EQ_DIP;
        }
 
-       mp = pim_msdp_peer_find(peer_addr);
+       mp = pim_msdp_peer_find(pim, peer_addr);
        if (mp) {
                if (mp_p) {
                        *mp_p = mp;
@@ -1141,7 +1163,8 @@ enum pim_msdp_err pim_msdp_peer_add(struct in_addr peer_addr,
                return PIM_MSDP_ERR_PEER_EXISTS;
        }
 
-       return pim_msdp_peer_new(peer_addr, local_addr, mesh_group_name, mp_p);
+       return pim_msdp_peer_new(pim, peer_addr, local_addr, mesh_group_name,
+                                mp_p);
 }
 
 /* release all mem associated with a peer */
@@ -1168,8 +1191,8 @@ static enum pim_msdp_err pim_msdp_peer_do_del(struct pim_msdp_peer *mp)
        pim_msdp_peer_stop_tcp_conn(mp, true /* chg_state */);
 
        /* remove the session from various tables */
-       listnode_delete(msdp->peer_list, mp);
-       hash_release(msdp->peer_hash, mp);
+       listnode_delete(mp->pim->msdp.peer_list, mp);
+       hash_release(mp->pim->msdp.peer_hash, mp);
 
        if (PIM_DEBUG_MSDP_EVENTS) {
                zlog_debug("MSDP peer %s deleted", mp->key_str);
@@ -1181,11 +1204,12 @@ static enum pim_msdp_err pim_msdp_peer_do_del(struct pim_msdp_peer *mp)
        return PIM_MSDP_ERR_NONE;
 }
 
-enum pim_msdp_err pim_msdp_peer_del(struct in_addr peer_addr)
+enum pim_msdp_err pim_msdp_peer_del(struct pim_instance *pim,
+                                   struct in_addr peer_addr)
 {
        struct pim_msdp_peer *mp;
 
-       mp = pim_msdp_peer_find(peer_addr);
+       mp = pim_msdp_peer_find(pim, peer_addr);
        if (!mp) {
                return PIM_MSDP_ERR_NO_PEER;
        }
@@ -1223,7 +1247,7 @@ static int pim_msdp_peer_comp(const void *p1, const void *p2)
 }
 
 /************************** Mesh group management **************************/
-static void pim_msdp_mg_free(struct pim_msdp_mg *mg)
+static void pim_msdp_mg_free(struct pim_instance *pim, struct pim_msdp_mg *mg)
 {
        /* If the mesh-group has valid member or src_ip don't delete it */
        if (!mg || mg->mbr_cnt || (mg->src_ip.s_addr != INADDR_ANY)) {
@@ -1237,10 +1261,10 @@ static void pim_msdp_mg_free(struct pim_msdp_mg *mg)
                XFREE(MTYPE_PIM_MSDP_MG_NAME, mg->mesh_group_name);
 
        if (mg->mbr_list)
-               list_free(mg->mbr_list);
+               list_delete(mg->mbr_list);
 
        XFREE(MTYPE_PIM_MSDP_MG, mg);
-       msdp->mg = NULL;
+       pim->msdp.mg = NULL;
 }
 
 static struct pim_msdp_mg *pim_msdp_mg_new(const char *mesh_group_name)
@@ -1265,9 +1289,10 @@ static struct pim_msdp_mg *pim_msdp_mg_new(const char *mesh_group_name)
        return mg;
 }
 
-enum pim_msdp_err pim_msdp_mg_del(const char *mesh_group_name)
+enum pim_msdp_err pim_msdp_mg_del(struct pim_instance *pim,
+                                 const char *mesh_group_name)
 {
-       struct pim_msdp_mg *mg = msdp->mg;
+       struct pim_msdp_mg *mg = pim->msdp.mg;
        struct pim_msdp_mg_mbr *mbr;
 
        if (!mg || strcmp(mg->mesh_group_name, mesh_group_name)) {
@@ -1284,22 +1309,23 @@ enum pim_msdp_err pim_msdp_mg_del(const char *mesh_group_name)
        mg->src_ip.s_addr = INADDR_ANY;
 
        /* free up the mesh-group */
-       pim_msdp_mg_free(mg);
+       pim_msdp_mg_free(pim, mg);
        return PIM_MSDP_ERR_NONE;
 }
 
-static enum pim_msdp_err pim_msdp_mg_add(const char *mesh_group_name)
+static enum pim_msdp_err pim_msdp_mg_add(struct pim_instance *pim,
+                                        const char *mesh_group_name)
 {
-       if (msdp->mg) {
-               if (!strcmp(msdp->mg->mesh_group_name, mesh_group_name)) {
+       if (pim->msdp.mg) {
+               if (!strcmp(pim->msdp.mg->mesh_group_name, mesh_group_name)) {
                        return PIM_MSDP_ERR_NONE;
                }
                /* currently only one mesh-group can exist at a time */
                return PIM_MSDP_ERR_MAX_MESH_GROUPS;
        }
 
-       msdp->mg = pim_msdp_mg_new(mesh_group_name);
-       if (!msdp->mg) {
+       pim->msdp.mg = pim_msdp_mg_new(mesh_group_name);
+       if (!pim->msdp.mg) {
                return PIM_MSDP_ERR_OOM;
        }
 
@@ -1325,17 +1351,18 @@ static void pim_msdp_mg_mbr_free(struct pim_msdp_mg_mbr *mbr)
        XFREE(MTYPE_PIM_MSDP_MG_MBR, mbr);
 }
 
-static struct pim_msdp_mg_mbr *pim_msdp_mg_mbr_find(struct in_addr mbr_ip)
+static struct pim_msdp_mg_mbr *pim_msdp_mg_mbr_find(struct pim_instance *pim,
+                                                   struct in_addr mbr_ip)
 {
        struct pim_msdp_mg_mbr *mbr;
        struct listnode *mbr_node;
 
-       if (!msdp->mg) {
+       if (!pim->msdp.mg) {
                return NULL;
        }
        /* we can move this to a hash but considering that number of peers in
         * a mesh-group that seems like bit of an overkill */
-       for (ALL_LIST_ELEMENTS_RO(msdp->mg->mbr_list, mbr_node, mbr)) {
+       for (ALL_LIST_ELEMENTS_RO(pim->msdp.mg->mbr_list, mbr_node, mbr)) {
                if (mbr->mbr_ip.s_addr == mbr_ip.s_addr) {
                        return mbr;
                }
@@ -1343,20 +1370,21 @@ static struct pim_msdp_mg_mbr *pim_msdp_mg_mbr_find(struct in_addr mbr_ip)
        return mbr;
 }
 
-enum pim_msdp_err pim_msdp_mg_mbr_add(const char *mesh_group_name,
+enum pim_msdp_err pim_msdp_mg_mbr_add(struct pim_instance *pim,
+                                     const char *mesh_group_name,
                                      struct in_addr mbr_ip)
 {
        int rc;
        struct pim_msdp_mg_mbr *mbr;
        struct pim_msdp_mg *mg;
 
-       rc = pim_msdp_mg_add(mesh_group_name);
+       rc = pim_msdp_mg_add(pim, mesh_group_name);
        if (rc != PIM_MSDP_ERR_NONE) {
                return rc;
        }
 
-       mg = msdp->mg;
-       mbr = pim_msdp_mg_mbr_find(mbr_ip);
+       mg = pim->msdp.mg;
+       mbr = pim_msdp_mg_mbr_find(pim, mbr_ip);
        if (mbr) {
                return PIM_MSDP_ERR_MG_MBR_EXISTS;
        }
@@ -1366,7 +1394,7 @@ enum pim_msdp_err pim_msdp_mg_mbr_add(const char *mesh_group_name,
                zlog_err("%s: PIM XCALLOC(%zu) failure", __PRETTY_FUNCTION__,
                         sizeof(*mbr));
                /* if there are no references to the mg free it */
-               pim_msdp_mg_free(mg);
+               pim_msdp_mg_free(pim, mg);
                return PIM_MSDP_ERR_OOM;
        }
        mbr->mbr_ip = mbr_ip;
@@ -1374,7 +1402,7 @@ enum pim_msdp_err pim_msdp_mg_mbr_add(const char *mesh_group_name,
 
        /* if valid SIP has been configured add peer session */
        if (mg->src_ip.s_addr != INADDR_ANY) {
-               pim_msdp_peer_add(mbr_ip, mg->src_ip, mesh_group_name,
+               pim_msdp_peer_add(pim, mbr_ip, mg->src_ip, mesh_group_name,
                                  &mbr->mp);
        }
 
@@ -1409,33 +1437,34 @@ static void pim_msdp_mg_mbr_do_del(struct pim_msdp_mg *mg,
        }
 }
 
-enum pim_msdp_err pim_msdp_mg_mbr_del(const char *mesh_group_name,
+enum pim_msdp_err pim_msdp_mg_mbr_del(struct pim_instance *pim,
+                                     const char *mesh_group_name,
                                      struct in_addr mbr_ip)
 {
        struct pim_msdp_mg_mbr *mbr;
-       struct pim_msdp_mg *mg = msdp->mg;
+       struct pim_msdp_mg *mg = pim->msdp.mg;
 
        if (!mg || strcmp(mg->mesh_group_name, mesh_group_name)) {
                return PIM_MSDP_ERR_NO_MG;
        }
 
-       mbr = pim_msdp_mg_mbr_find(mbr_ip);
+       mbr = pim_msdp_mg_mbr_find(pim, mbr_ip);
        if (!mbr) {
                return PIM_MSDP_ERR_NO_MG_MBR;
        }
 
        pim_msdp_mg_mbr_do_del(mg, mbr);
        /* if there are no references to the mg free it */
-       pim_msdp_mg_free(mg);
+       pim_msdp_mg_free(pim, mg);
 
        return PIM_MSDP_ERR_NONE;
 }
 
-static void pim_msdp_mg_src_do_del(void)
+static void pim_msdp_mg_src_do_del(struct pim_instance *pim)
 {
        struct pim_msdp_mg_mbr *mbr;
        struct listnode *mbr_node;
-       struct pim_msdp_mg *mg = msdp->mg;
+       struct pim_msdp_mg *mg = pim->msdp.mg;
 
        /* SIP is being removed - tear down all active peer sessions */
        for (ALL_LIST_ELEMENTS_RO(mg->mbr_list, mbr_node, mbr)) {
@@ -1450,9 +1479,10 @@ static void pim_msdp_mg_src_do_del(void)
        }
 }
 
-enum pim_msdp_err pim_msdp_mg_src_del(const char *mesh_group_name)
+enum pim_msdp_err pim_msdp_mg_src_del(struct pim_instance *pim,
+                                     const char *mesh_group_name)
 {
-       struct pim_msdp_mg *mg = msdp->mg;
+       struct pim_msdp_mg *mg = pim->msdp.mg;
 
        if (!mg || strcmp(mg->mesh_group_name, mesh_group_name)) {
                return PIM_MSDP_ERR_NO_MG;
@@ -1460,14 +1490,15 @@ enum pim_msdp_err pim_msdp_mg_src_del(const char *mesh_group_name)
 
        if (mg->src_ip.s_addr != INADDR_ANY) {
                mg->src_ip.s_addr = INADDR_ANY;
-               pim_msdp_mg_src_do_del();
+               pim_msdp_mg_src_do_del(pim);
                /* if there are no references to the mg free it */
-               pim_msdp_mg_free(mg);
+               pim_msdp_mg_free(pim, mg);
        }
        return PIM_MSDP_ERR_NONE;
 }
 
-enum pim_msdp_err pim_msdp_mg_src_add(const char *mesh_group_name,
+enum pim_msdp_err pim_msdp_mg_src_add(struct pim_instance *pim,
+                                     const char *mesh_group_name,
                                      struct in_addr src_ip)
 {
        int rc;
@@ -1476,23 +1507,23 @@ enum pim_msdp_err pim_msdp_mg_src_add(const char *mesh_group_name,
        struct pim_msdp_mg *mg;
 
        if (src_ip.s_addr == INADDR_ANY) {
-               pim_msdp_mg_src_del(mesh_group_name);
+               pim_msdp_mg_src_del(pim, mesh_group_name);
                return PIM_MSDP_ERR_NONE;
        }
 
-       rc = pim_msdp_mg_add(mesh_group_name);
+       rc = pim_msdp_mg_add(pim, mesh_group_name);
        if (rc != PIM_MSDP_ERR_NONE) {
                return rc;
        }
 
-       mg = msdp->mg;
+       mg = pim->msdp.mg;
        if (mg->src_ip.s_addr != INADDR_ANY) {
-               pim_msdp_mg_src_do_del();
+               pim_msdp_mg_src_do_del(pim);
        }
        mg->src_ip = src_ip;
 
        for (ALL_LIST_ELEMENTS_RO(mg->mbr_list, mbr_node, mbr)) {
-               pim_msdp_peer_add(mbr->mbr_ip, mg->src_ip, mesh_group_name,
+               pim_msdp_peer_add(pim, mbr->mbr_ip, mg->src_ip, mesh_group_name,
                                  &mbr->mp);
        }
 
@@ -1506,11 +1537,12 @@ enum pim_msdp_err pim_msdp_mg_src_add(const char *mesh_group_name,
 }
 
 /*********************** MSDP feature APIs *********************************/
-int pim_msdp_config_write(struct vty *vty)
+int pim_msdp_config_write_helper(struct pim_instance *pim, struct vty *vty,
+                                const char *spaces)
 {
        struct listnode *mbrnode;
        struct pim_msdp_mg_mbr *mbr;
-       struct pim_msdp_mg *mg = msdp->mg;
+       struct pim_msdp_mg *mg = pim->msdp.mg;
        char mbr_str[INET_ADDRSTRLEN];
        char src_str[INET_ADDRSTRLEN];
        int count = 0;
@@ -1521,65 +1553,83 @@ int pim_msdp_config_write(struct vty *vty)
 
        if (mg->src_ip.s_addr != INADDR_ANY) {
                pim_inet4_dump("<src?>", mg->src_ip, src_str, sizeof(src_str));
-               vty_out(vty, "ip msdp mesh-group %s source %s\n",
+               vty_out(vty, "%sip msdp mesh-group %s source %s\n", spaces,
                        mg->mesh_group_name, src_str);
                ++count;
        }
 
        for (ALL_LIST_ELEMENTS_RO(mg->mbr_list, mbrnode, mbr)) {
                pim_inet4_dump("<mbr?>", mbr->mbr_ip, mbr_str, sizeof(mbr_str));
-               vty_out(vty, "ip msdp mesh-group %s member %s\n",
+               vty_out(vty, "%sip msdp mesh-group %s member %s\n", spaces,
                        mg->mesh_group_name, mbr_str);
                ++count;
        }
        return count;
 }
 
+int pim_msdp_config_write(struct vty *vty)
+{
+       return pim_msdp_config_write_helper(pimg, vty, "");
+}
+
 /* Enable feature including active/periodic timers etc. on the first peer
  * config. Till then MSDP should just stay quiet. */
-static void pim_msdp_enable(void)
+static void pim_msdp_enable(struct pim_instance *pim)
 {
-       if (msdp->flags & PIM_MSDPF_ENABLE) {
+       if (pim->msdp.flags & PIM_MSDPF_ENABLE) {
                /* feature is already enabled */
                return;
        }
-       msdp->flags |= PIM_MSDPF_ENABLE;
-       msdp->work_obuf = stream_new(PIM_MSDP_MAX_PACKET_SIZE);
-       pim_msdp_sa_adv_timer_setup(true /* start */);
+       pim->msdp.flags |= PIM_MSDPF_ENABLE;
+       pim->msdp.work_obuf = stream_new(PIM_MSDP_MAX_PACKET_SIZE);
+       pim_msdp_sa_adv_timer_setup(pim, true /* start */);
        /* setup sa cache based on local sources */
-       pim_msdp_sa_local_setup();
+       pim_msdp_sa_local_setup(pim);
 }
 
 /* MSDP init */
-void pim_msdp_init(struct thread_master *master)
+void pim_msdp_init(struct pim_instance *pim, struct thread_master *master)
 {
-       msdp->master = master;
+       pim->msdp.master = master;
+       char hash_name[64];
 
-       msdp->peer_hash = hash_create(pim_msdp_peer_hash_key_make,
-                                     pim_msdp_peer_hash_eq, NULL);
-       msdp->peer_list = list_new();
-       msdp->peer_list->del = (void (*)(void *))pim_msdp_peer_free;
-       msdp->peer_list->cmp = (int (*)(void *, void *))pim_msdp_peer_comp;
+       snprintf(hash_name, 64, "PIM %s MSDP Peer Hash", pim->vrf->name);
+       pim->msdp.peer_hash = hash_create(pim_msdp_peer_hash_key_make,
+                                         pim_msdp_peer_hash_eq, hash_name);
+       pim->msdp.peer_list = list_new();
+       pim->msdp.peer_list->del = (void (*)(void *))pim_msdp_peer_free;
+       pim->msdp.peer_list->cmp = (int (*)(void *, void *))pim_msdp_peer_comp;
 
-       msdp->sa_hash = hash_create(pim_msdp_sa_hash_key_make,
-                                   pim_msdp_sa_hash_eq, NULL);
-       msdp->sa_list = list_new();
-       msdp->sa_list->del = (void (*)(void *))pim_msdp_sa_free;
-       msdp->sa_list->cmp = (int (*)(void *, void *))pim_msdp_sa_comp;
+       snprintf(hash_name, 64, "PIM %s MSDP SA Hash", pim->vrf->name);
+       pim->msdp.sa_hash = hash_create(pim_msdp_sa_hash_key_make,
+                                       pim_msdp_sa_hash_eq, hash_name);
+       pim->msdp.sa_list = list_new();
+       pim->msdp.sa_list->del = (void (*)(void *))pim_msdp_sa_free;
+       pim->msdp.sa_list->cmp = (int (*)(void *, void *))pim_msdp_sa_comp;
 }
 
 /* counterpart to MSDP init; XXX: unused currently */
-void pim_msdp_exit(void)
+void pim_msdp_exit(struct pim_instance *pim)
 {
        /* XXX: stop listener and delete all peer sessions */
 
-       if (msdp->peer_hash) {
-               hash_free(msdp->peer_hash);
-               msdp->peer_hash = NULL;
+       if (pim->msdp.peer_hash) {
+               hash_free(pim->msdp.peer_hash);
+               pim->msdp.peer_hash = NULL;
+       }
+
+       if (pim->msdp.peer_list) {
+               list_delete(pim->msdp.peer_list);
+               pim->msdp.peer_list = NULL;
+       }
+
+       if (pim->msdp.sa_hash) {
+               hash_free(pim->msdp.sa_hash);
+               pim->msdp.sa_hash = NULL;
        }
 
-       if (msdp->peer_list) {
-               list_free(msdp->peer_list);
-               msdp->peer_list = NULL;
+       if (pim->msdp.sa_list) {
+               list_delete(pim->msdp.sa_list);
+               pim->msdp.sa_list = NULL;
        }
 }
index 66e5457df443710243210e1cb6723ab07e660498..0627ee5f479e91671b69c050fc9c70ad8a7681fa 100644 (file)
@@ -69,11 +69,13 @@ enum pim_msdp_sa_flags {
        PIM_MSDP_SAF_PEER = (1 << 1),
        PIM_MSDP_SAF_REF = (PIM_MSDP_SAF_LOCAL | PIM_MSDP_SAF_PEER),
        PIM_MSDP_SAF_STALE = (1 << 2), /* local entries can get kicked out on
-                                      * misc pim events such as RP change */
+                                       * misc pim events such as RP change */
        PIM_MSDP_SAF_UP_DEL_IN_PROG = (1 << 3)
 };
 
 struct pim_msdp_sa {
+       struct pim_instance *pim;
+
        struct prefix_sg sg;
        char sg_str[PIM_SG_LEN];
        struct in_addr rp;   /* Last RP address associated with this SA */
@@ -97,6 +99,8 @@ enum pim_msdp_peer_flags {
 };
 
 struct pim_msdp_peer {
+       struct pim_instance *pim;
+
        /* configuration */
        struct in_addr local;
        struct in_addr peer;
@@ -203,24 +207,30 @@ struct pim_msdp {
 };
 
 #define PIM_MSDP_PEER_READ_ON(mp)                                              \
-       thread_add_read(msdp->master, pim_msdp_read, mp, mp->fd, &mp->t_read)
+       thread_add_read(mp->pim->msdp.master, pim_msdp_read, mp, mp->fd,       \
+                       &mp->t_read)
 
 #define PIM_MSDP_PEER_WRITE_ON(mp)                                             \
-       thread_add_write(msdp->master, pim_msdp_write, mp, mp->fd, &mp->t_write)
+       thread_add_write(mp->pim->msdp.master, pim_msdp_write, mp, mp->fd,     \
+                        &mp->t_write)
 
 #define PIM_MSDP_PEER_READ_OFF(mp) THREAD_READ_OFF(mp->t_read)
 #define PIM_MSDP_PEER_WRITE_OFF(mp) THREAD_WRITE_OFF(mp->t_write)
 
-extern struct pim_msdp *msdp;
-void pim_msdp_init(struct thread_master *master);
-void pim_msdp_exit(void);
-enum pim_msdp_err pim_msdp_peer_add(struct in_addr peer, struct in_addr local,
+// struct pim_msdp *msdp;
+struct pim_instance;
+void pim_msdp_init(struct pim_instance *pim, struct thread_master *master);
+void pim_msdp_exit(struct pim_instance *pim);
+enum pim_msdp_err pim_msdp_peer_add(struct pim_instance *pim,
+                                   struct in_addr peer, struct in_addr local,
                                    const char *mesh_group_name,
                                    struct pim_msdp_peer **mp_p);
-enum pim_msdp_err pim_msdp_peer_del(struct in_addr peer_addr);
+enum pim_msdp_err pim_msdp_peer_del(struct pim_instance *pim,
+                                   struct in_addr peer_addr);
 char *pim_msdp_state_dump(enum pim_msdp_peer_state state, char *buf,
                          int buf_size);
-struct pim_msdp_peer *pim_msdp_peer_find(struct in_addr peer_addr);
+struct pim_msdp_peer *pim_msdp_peer_find(struct pim_instance *pim,
+                                        struct in_addr peer_addr);
 void pim_msdp_peer_established(struct pim_msdp_peer *mp);
 void pim_msdp_peer_pkt_rxed(struct pim_msdp_peer *mp);
 void pim_msdp_peer_stop_tcp_conn(struct pim_msdp_peer *mp, bool chg_state);
@@ -229,21 +239,29 @@ int pim_msdp_write(struct thread *thread);
 char *pim_msdp_peer_key_dump(struct pim_msdp_peer *mp, char *buf, int buf_size,
                             bool long_format);
 int pim_msdp_config_write(struct vty *vty);
+int pim_msdp_config_write_helper(struct pim_instance *pim, struct vty *vty,
+                                const char *spaces);
 void pim_msdp_peer_pkt_txed(struct pim_msdp_peer *mp);
-void pim_msdp_sa_ref(struct pim_msdp_peer *mp, struct prefix_sg *sg,
-                    struct in_addr rp);
+void pim_msdp_sa_ref(struct pim_instance *pim, struct pim_msdp_peer *mp,
+                    struct prefix_sg *sg, struct in_addr rp);
 void pim_msdp_sa_local_update(struct pim_upstream *up);
-void pim_msdp_sa_local_del(struct prefix_sg *sg);
-void pim_msdp_i_am_rp_changed(void);
+void pim_msdp_sa_local_del(struct pim_instance *pim, struct prefix_sg *sg);
+void pim_msdp_i_am_rp_changed(struct pim_instance *pim);
 bool pim_msdp_peer_rpf_check(struct pim_msdp_peer *mp, struct in_addr rp);
-void pim_msdp_up_join_state_changed(struct pim_upstream *xg_up);
-void pim_msdp_up_del(struct prefix_sg *sg);
-enum pim_msdp_err pim_msdp_mg_mbr_add(const char *mesh_group_name,
+void pim_msdp_up_join_state_changed(struct pim_instance *pim,
+                                   struct pim_upstream *xg_up);
+void pim_msdp_up_del(struct pim_instance *pim, struct prefix_sg *sg);
+enum pim_msdp_err pim_msdp_mg_mbr_add(struct pim_instance *pim,
+                                     const char *mesh_group_name,
                                      struct in_addr mbr_ip);
-enum pim_msdp_err pim_msdp_mg_mbr_del(const char *mesh_group_name,
+enum pim_msdp_err pim_msdp_mg_mbr_del(struct pim_instance *pim,
+                                     const char *mesh_group_name,
                                      struct in_addr mbr_ip);
-enum pim_msdp_err pim_msdp_mg_src_del(const char *mesh_group_name);
-enum pim_msdp_err pim_msdp_mg_src_add(const char *mesh_group_name,
+enum pim_msdp_err pim_msdp_mg_src_del(struct pim_instance *pim,
+                                     const char *mesh_group_name);
+enum pim_msdp_err pim_msdp_mg_src_add(struct pim_instance *pim,
+                                     const char *mesh_group_name,
                                      struct in_addr src_ip);
-enum pim_msdp_err pim_msdp_mg_del(const char *mesh_group_name);
+enum pim_msdp_err pim_msdp_mg_del(struct pim_instance *pim,
+                                 const char *mesh_group_name);
 #endif
index 01ce293e36de6d557be227324b300f793e0a4e9f..11efc158e96778116b058c7aceb7e4f237d5567a 100644 (file)
@@ -310,7 +310,8 @@ void pim_msdp_pkt_ka_tx(struct pim_msdp_peer *mp)
        pim_msdp_pkt_send(mp, s);
 }
 
-static void pim_msdp_pkt_sa_push_to_one_peer(struct pim_msdp_peer *mp)
+static void pim_msdp_pkt_sa_push_to_one_peer(struct pim_instance *pim,
+                                            struct pim_msdp_peer *mp)
 {
        struct stream *s;
 
@@ -318,7 +319,7 @@ static void pim_msdp_pkt_sa_push_to_one_peer(struct pim_msdp_peer *mp)
                /* don't tx anything unless a session is established */
                return;
        }
-       s = stream_dup(msdp->work_obuf);
+       s = stream_dup(pim->msdp.work_obuf);
        if (s) {
                pim_msdp_pkt_send(mp, s);
                mp->flags |= PIM_MSDP_PEERF_SA_JUST_SENT;
@@ -326,63 +327,66 @@ static void pim_msdp_pkt_sa_push_to_one_peer(struct pim_msdp_peer *mp)
 }
 
 /* push the stream into the obuf fifo of all the peers */
-static void pim_msdp_pkt_sa_push(struct pim_msdp_peer *mp)
+static void pim_msdp_pkt_sa_push(struct pim_instance *pim,
+                                struct pim_msdp_peer *mp)
 {
        struct listnode *mpnode;
 
        if (mp) {
-               pim_msdp_pkt_sa_push_to_one_peer(mp);
+               pim_msdp_pkt_sa_push_to_one_peer(pim, mp);
        } else {
-               for (ALL_LIST_ELEMENTS_RO(msdp->peer_list, mpnode, mp)) {
+               for (ALL_LIST_ELEMENTS_RO(pim->msdp.peer_list, mpnode, mp)) {
                        if (PIM_DEBUG_MSDP_INTERNAL) {
                                zlog_debug("MSDP peer %s pim_msdp_pkt_sa_push",
                                           mp->key_str);
                        }
-                       pim_msdp_pkt_sa_push_to_one_peer(mp);
+                       pim_msdp_pkt_sa_push_to_one_peer(pim, mp);
                }
        }
 }
 
-static int pim_msdp_pkt_sa_fill_hdr(int local_cnt)
+static int pim_msdp_pkt_sa_fill_hdr(struct pim_instance *pim, int local_cnt)
 {
        int curr_tlv_ecnt;
 
-       stream_reset(msdp->work_obuf);
+       stream_reset(pim->msdp.work_obuf);
        curr_tlv_ecnt = local_cnt > PIM_MSDP_SA_MAX_ENTRY_CNT
                                ? PIM_MSDP_SA_MAX_ENTRY_CNT
                                : local_cnt;
        local_cnt -= curr_tlv_ecnt;
-       stream_putc(msdp->work_obuf, PIM_MSDP_V4_SOURCE_ACTIVE);
-       stream_putw(msdp->work_obuf, PIM_MSDP_SA_ENTRY_CNT2SIZE(curr_tlv_ecnt));
-       stream_putc(msdp->work_obuf, curr_tlv_ecnt);
-       stream_put_ipv4(msdp->work_obuf, msdp->originator_id.s_addr);
+       stream_putc(pim->msdp.work_obuf, PIM_MSDP_V4_SOURCE_ACTIVE);
+       stream_putw(pim->msdp.work_obuf,
+                   PIM_MSDP_SA_ENTRY_CNT2SIZE(curr_tlv_ecnt));
+       stream_putc(pim->msdp.work_obuf, curr_tlv_ecnt);
+       stream_put_ipv4(pim->msdp.work_obuf, pim->msdp.originator_id.s_addr);
 
        return local_cnt;
 }
 
 static void pim_msdp_pkt_sa_fill_one(struct pim_msdp_sa *sa)
 {
-       stream_put3(msdp->work_obuf, 0 /* reserved */);
-       stream_putc(msdp->work_obuf, 32 /* sprefix len */);
-       stream_put_ipv4(msdp->work_obuf, sa->sg.grp.s_addr);
-       stream_put_ipv4(msdp->work_obuf, sa->sg.src.s_addr);
+       stream_put3(sa->pim->msdp.work_obuf, 0 /* reserved */);
+       stream_putc(sa->pim->msdp.work_obuf, 32 /* sprefix len */);
+       stream_put_ipv4(sa->pim->msdp.work_obuf, sa->sg.grp.s_addr);
+       stream_put_ipv4(sa->pim->msdp.work_obuf, sa->sg.src.s_addr);
 }
 
-static void pim_msdp_pkt_sa_gen(struct pim_msdp_peer *mp)
+static void pim_msdp_pkt_sa_gen(struct pim_instance *pim,
+                               struct pim_msdp_peer *mp)
 {
        struct listnode *sanode;
        struct pim_msdp_sa *sa;
        int sa_count;
-       int local_cnt = msdp->local_cnt;
+       int local_cnt = pim->msdp.local_cnt;
 
        sa_count = 0;
        if (PIM_DEBUG_MSDP_INTERNAL) {
                zlog_debug("  sa gen  %d", local_cnt);
        }
 
-       local_cnt = pim_msdp_pkt_sa_fill_hdr(local_cnt);
+       local_cnt = pim_msdp_pkt_sa_fill_hdr(pim, local_cnt);
 
-       for (ALL_LIST_ELEMENTS_RO(msdp->sa_list, sanode, sa)) {
+       for (ALL_LIST_ELEMENTS_RO(pim->msdp.sa_list, sanode, sa)) {
                if (!(sa->flags & PIM_MSDP_SAF_LOCAL)) {
                        /* current implementation of MSDP is for anycast i.e.
                         * full mesh. so
@@ -394,31 +398,31 @@ static void pim_msdp_pkt_sa_gen(struct pim_msdp_peer *mp)
                pim_msdp_pkt_sa_fill_one(sa);
                ++sa_count;
                if (sa_count >= PIM_MSDP_SA_MAX_ENTRY_CNT) {
-                       pim_msdp_pkt_sa_push(mp);
+                       pim_msdp_pkt_sa_push(pim, mp);
                        /* reset headers */
                        sa_count = 0;
                        if (PIM_DEBUG_MSDP_INTERNAL) {
                                zlog_debug("  sa gen for remainder %d",
                                           local_cnt);
                        }
-                       local_cnt = pim_msdp_pkt_sa_fill_hdr(local_cnt);
+                       local_cnt = pim_msdp_pkt_sa_fill_hdr(pim, local_cnt);
                }
        }
 
        if (sa_count) {
-               pim_msdp_pkt_sa_push(mp);
+               pim_msdp_pkt_sa_push(pim, mp);
        }
        return;
 }
 
-static void pim_msdp_pkt_sa_tx_done(void)
+static void pim_msdp_pkt_sa_tx_done(struct pim_instance *pim)
 {
        struct listnode *mpnode;
        struct pim_msdp_peer *mp;
 
        /* if SA were sent to the peers we restart ka timer and avoid
         * unnecessary ka noise */
-       for (ALL_LIST_ELEMENTS_RO(msdp->peer_list, mpnode, mp)) {
+       for (ALL_LIST_ELEMENTS_RO(pim->msdp.peer_list, mpnode, mp)) {
                if (mp->flags & PIM_MSDP_PEERF_SA_JUST_SENT) {
                        mp->flags &= ~PIM_MSDP_PEERF_SA_JUST_SENT;
                        pim_msdp_peer_pkt_txed(mp);
@@ -426,25 +430,25 @@ static void pim_msdp_pkt_sa_tx_done(void)
        }
 }
 
-void pim_msdp_pkt_sa_tx(void)
+void pim_msdp_pkt_sa_tx(struct pim_instance *pim)
 {
-       pim_msdp_pkt_sa_gen(NULL /* mp */);
-       pim_msdp_pkt_sa_tx_done();
+       pim_msdp_pkt_sa_gen(pim, NULL /* mp */);
+       pim_msdp_pkt_sa_tx_done(pim);
 }
 
 void pim_msdp_pkt_sa_tx_one(struct pim_msdp_sa *sa)
 {
-       pim_msdp_pkt_sa_fill_hdr(1 /* cnt */);
+       pim_msdp_pkt_sa_fill_hdr(sa->pim, 1 /* cnt */);
        pim_msdp_pkt_sa_fill_one(sa);
-       pim_msdp_pkt_sa_push(NULL);
-       pim_msdp_pkt_sa_tx_done();
+       pim_msdp_pkt_sa_push(sa->pim, NULL);
+       pim_msdp_pkt_sa_tx_done(sa->pim);
 }
 
 /* when a connection is first established we push all SAs immediately */
 void pim_msdp_pkt_sa_tx_to_one_peer(struct pim_msdp_peer *mp)
 {
-       pim_msdp_pkt_sa_gen(mp);
-       pim_msdp_pkt_sa_tx_done();
+       pim_msdp_pkt_sa_gen(mp->pim, mp);
+       pim_msdp_pkt_sa_tx_done(mp->pim);
 }
 
 static void pim_msdp_pkt_rxed_with_fatal_error(struct pim_msdp_peer *mp)
@@ -484,7 +488,7 @@ static void pim_msdp_pkt_sa_rx_one(struct pim_msdp_peer *mp, struct in_addr rp)
        if (PIM_DEBUG_MSDP_PACKETS) {
                zlog_debug("  sg %s", pim_str_sg_dump(&sg));
        }
-       pim_msdp_sa_ref(mp, &sg, rp);
+       pim_msdp_sa_ref(mp->pim, mp, &sg, rp);
 }
 
 static void pim_msdp_pkt_sa_rx(struct pim_msdp_peer *mp, int len)
index 986fa3b32ae739fad6e3b1ac80c21a68f8a3c66d..d922fa50dfb8e059ea30480261c5e4d0dfd3c7a4 100644 (file)
@@ -64,7 +64,7 @@
 
 void pim_msdp_pkt_ka_tx(struct pim_msdp_peer *mp);
 int pim_msdp_read(struct thread *thread);
-void pim_msdp_pkt_sa_tx(void);
+void pim_msdp_pkt_sa_tx(struct pim_instance *pim);
 void pim_msdp_pkt_sa_tx_one(struct pim_msdp_sa *sa);
 void pim_msdp_pkt_sa_tx_to_one_peer(struct pim_msdp_peer *mp);
 
index 0ce09710122081e19de6d9224c3b43ec02a9424b..9473462e6325ed08db0400d4266b41f0e970e7bb 100644 (file)
 #include <lib/sockunion.h>
 #include <lib/thread.h>
 #include <lib/vty.h>
+#include <lib/if.h>
+#include <lib/vrf.h>
 
 #include "pimd.h"
+#include "pim_sock.h"
 
 #include "pim_msdp.h"
 #include "pim_msdp_socket.h"
@@ -56,7 +59,7 @@ static void pim_msdp_update_sock_send_buffer_size(int fd)
 static int pim_msdp_sock_accept(struct thread *thread)
 {
        union sockunion su;
-       struct pim_msdp_listener *listener = THREAD_ARG(thread);
+       struct pim_instance *pim = THREAD_ARG(thread);
        int accept_sock;
        int msdp_sock;
        struct pim_msdp_peer *mp;
@@ -70,9 +73,9 @@ static int pim_msdp_sock_accept(struct thread *thread)
                zlog_err("accept_sock is negative value %d", accept_sock);
                return -1;
        }
-       listener->thread = NULL;
-       thread_add_read(master, pim_msdp_sock_accept, listener, accept_sock,
-                       &listener->thread);
+       pim->msdp.listener.thread = NULL;
+       thread_add_read(master, pim_msdp_sock_accept, pim, accept_sock,
+                       &pim->msdp.listener.thread);
 
        /* accept client connection. */
        msdp_sock = sockunion_accept(accept_sock, &su);
@@ -83,9 +86,9 @@ static int pim_msdp_sock_accept(struct thread *thread)
        }
 
        /* see if have peer config for this */
-       mp = pim_msdp_peer_find(su.sin.sin_addr);
+       mp = pim_msdp_peer_find(pim, su.sin.sin_addr);
        if (!mp || !PIM_MSDP_PEER_IS_LISTENER(mp)) {
-               ++msdp->rejected_accepts;
+               ++pim->msdp.rejected_accepts;
                if (PIM_DEBUG_MSDP_EVENTS) {
                        zlog_err("msdp peer connection refused from %s",
                                 sockunion2str(&su, buf, SU_ADDRSTRLEN));
@@ -117,15 +120,15 @@ static int pim_msdp_sock_accept(struct thread *thread)
 }
 
 /* global listener for the MSDP well know TCP port */
-int pim_msdp_sock_listen(void)
+int pim_msdp_sock_listen(struct pim_instance *pim)
 {
        int sock;
        int socklen;
        struct sockaddr_in sin;
        int rc;
-       struct pim_msdp_listener *listener = &msdp->listener;
+       struct pim_msdp_listener *listener = &pim->msdp.listener;
 
-       if (msdp->flags & PIM_MSDPF_LISTENER) {
+       if (pim->msdp.flags & PIM_MSDPF_LISTENER) {
                /* listener already setup */
                return 0;
        }
@@ -147,6 +150,17 @@ int pim_msdp_sock_listen(void)
        sockopt_reuseaddr(sock);
        sockopt_reuseport(sock);
 
+       if (pim->vrf_id != VRF_DEFAULT) {
+               struct interface *ifp =
+                       if_lookup_by_name(pim->vrf->name, pim->vrf_id);
+               if (!ifp) {
+                       zlog_err("%s: Unable to lookup vrf interface: %s",
+                                __PRETTY_FUNCTION__, pim->vrf->name);
+                       return -1;
+               }
+               pim_socket_bind(sock, ifp);
+       }
+
        if (pimd_privs.change(ZPRIVS_RAISE)) {
                zlog_err("pim_msdp_socket: could not raise privs, %s",
                         safe_strerror(errno));
@@ -178,10 +192,10 @@ int pim_msdp_sock_listen(void)
        listener->fd = sock;
        memcpy(&listener->su, &sin, socklen);
        listener->thread = NULL;
-       thread_add_read(msdp->master, pim_msdp_sock_accept, listener, sock,
+       thread_add_read(pim->msdp.master, pim_msdp_sock_accept, pim, sock,
                        &listener->thread);
 
-       msdp->flags |= PIM_MSDPF_LISTENER;
+       pim->msdp.flags |= PIM_MSDPF_LISTENER;
        return 0;
 }
 
@@ -214,6 +228,17 @@ int pim_msdp_sock_connect(struct pim_msdp_peer *mp)
                return -1;
        }
 
+       if (mp->pim->vrf_id != VRF_DEFAULT) {
+               struct interface *ifp =
+                       if_lookup_by_name(mp->pim->vrf->name, mp->pim->vrf_id);
+               if (!ifp) {
+                       zlog_err("%s: Unable to lookup vrf interface: %s",
+                                __PRETTY_FUNCTION__, mp->pim->vrf->name);
+                       return -1;
+               }
+               pim_socket_bind(mp->fd, ifp);
+       }
+
        set_nonblocking(mp->fd);
 
        /* Set socket send buffer size */
index 0abcd57da021faa63afa3ea84cf3d20de409e253..8f46683dff94948c7b8bd7f54cc3c34ca1912f8d 100644 (file)
@@ -19,6 +19,6 @@
 #ifndef PIM_MSDP_SOCKET_H
 #define PIM_MSDP_SOCKET_H
 
-int pim_msdp_sock_listen(void);
+int pim_msdp_sock_listen(struct pim_instance *pim);
 int pim_msdp_sock_connect(struct pim_msdp_peer *mp);
 #endif
index 04f1f4846f89d667ea959fa3208831144600308e..5d4ddf14e84acfe20fecfb744986327d12ea55ad 100644 (file)
@@ -36,6 +36,7 @@
 #include "pim_rpf.h"
 #include "pim_register.h"
 #include "pim_jp_agg.h"
+#include "pim_oil.h"
 
 void pim_msg_build_header(uint8_t *pim_msg, size_t pim_msg_size,
                          uint8_t pim_msg_type)
@@ -104,6 +105,9 @@ size_t pim_msg_get_jp_group_size(struct list *sources)
        struct pim_jp_sources *js;
        size_t size = 0;
 
+       if (!sources)
+               return 0;
+
        size += sizeof(struct pim_encoded_group_ipv4);
        size += 4; // Joined sources (2) + Pruned Sources (2)
 
@@ -195,7 +199,8 @@ size_t pim_msg_build_jp_groups(struct pim_jp_groups *grp,
                        grp->prunes++;
 
                if (source->up->sg.src.s_addr == INADDR_ANY) {
-                       struct pim_rpf *rpf = pim_rp_g(source->up->sg.grp);
+                       struct pim_instance *pim = source->up->channel_oil->pim;
+                       struct pim_rpf *rpf = pim_rp_g(pim, source->up->sg.grp);
                        bits = PIM_ENCODE_SPARSE_BIT | PIM_ENCODE_WC_BIT
                               | PIM_ENCODE_RPT_BIT;
                        stosend = rpf->rpf_addr.u.prefix4;
index 70341a37541ba18d7a9695f1d84c98f6fe282972..04e3e10ff32a6b572295397f93b912db295684ae 100644 (file)
@@ -545,7 +545,7 @@ pim_neighbor_add(struct interface *ifp, struct in_addr source_addr,
        else
                pim_hello_restart_triggered(neigh->interface);
 
-       pim_upstream_find_new_rpf();
+       pim_upstream_find_new_rpf(pim_ifp->pim);
 
        /* RNH can send nexthop update prior to PIM neibhor UP
           in that case nexthop cache would not consider this neighbor
@@ -553,9 +553,9 @@ pim_neighbor_add(struct interface *ifp, struct in_addr source_addr,
           Upon PIM neighbor UP, iterate all RPs and update
           nexthop cache with this neighbor.
         */
-       pim_resolve_rp_nh();
+       pim_resolve_rp_nh(pim_ifp->pim);
 
-       pim_rp_setup();
+       pim_rp_setup(pim_ifp->pim);
 
        pim_neighbor_rpf_update();
        return neigh;
index f8bf2ac77c9bc38b344f0d735f6e0d8117aee92c..f7fa9993adb69b8bc52bf32dc68b9d8816d9e59d 100644 (file)
@@ -44,7 +44,7 @@
  * pim_sendmsg_zebra_rnh -- Format and send a nexthop register/Unregister
  *   command to Zebra.
  */
-void pim_sendmsg_zebra_rnh(struct zclient *zclient,
+void pim_sendmsg_zebra_rnh(struct pim_instance *pim, struct zclient *zclient,
                           struct pim_nexthop_cache *pnc, int command)
 {
        struct stream *s;
@@ -58,7 +58,7 @@ void pim_sendmsg_zebra_rnh(struct zclient *zclient,
        p = &(pnc->rpf.rpf_addr);
        s = zclient->obuf;
        stream_reset(s);
-       zclient_create_header(s, command, VRF_DEFAULT);
+       zclient_create_header(s, command, pim->vrf_id);
        /* get update for all routes for a prefix */
        stream_putc(s, 0);
 
@@ -81,19 +81,21 @@ void pim_sendmsg_zebra_rnh(struct zclient *zclient,
                zlog_warn("sendmsg_nexthop: zclient_send_message() failed");
 
 
-       if (PIM_DEBUG_TRACE) {
+       if (PIM_DEBUG_PIM_NHT) {
                char buf[PREFIX2STR_BUFFER];
                prefix2str(p, buf, sizeof(buf));
-               zlog_debug("%s: NHT %sregistered addr %s with Zebra ret:%d ",
-                          __PRETTY_FUNCTION__,
-                          (command == ZEBRA_NEXTHOP_REGISTER) ? " " : "de",
-                          buf, ret);
+               zlog_debug(
+                       "%s: NHT %sregistered addr %s(%s) with Zebra ret:%d ",
+                       __PRETTY_FUNCTION__,
+                       (command == ZEBRA_NEXTHOP_REGISTER) ? " " : "de", buf,
+                       pim->vrf->name, ret);
        }
 
        return;
 }
 
-struct pim_nexthop_cache *pim_nexthop_cache_find(struct pim_rpf *rpf)
+struct pim_nexthop_cache *pim_nexthop_cache_find(struct pim_instance *pim,
+                                                struct pim_rpf *rpf)
 {
        struct pim_nexthop_cache *pnc = NULL;
        struct pim_nexthop_cache lookup;
@@ -102,14 +104,17 @@ struct pim_nexthop_cache *pim_nexthop_cache_find(struct pim_rpf *rpf)
        lookup.rpf.rpf_addr.prefixlen = rpf->rpf_addr.prefixlen;
        lookup.rpf.rpf_addr.u.prefix4.s_addr = rpf->rpf_addr.u.prefix4.s_addr;
 
-       pnc = hash_lookup(pimg->rpf_hash, &lookup);
+       pnc = hash_lookup(pim->rpf_hash, &lookup);
 
        return pnc;
 }
 
-struct pim_nexthop_cache *pim_nexthop_cache_add(struct pim_rpf *rpf_addr)
+static struct pim_nexthop_cache *pim_nexthop_cache_add(struct pim_instance *pim,
+                                                      struct pim_rpf *rpf_addr)
 {
        struct pim_nexthop_cache *pnc;
+       char hash_name[64];
+       char buf1[64];
 
        pnc = XCALLOC(MTYPE_PIM_NEXTHOP_CACHE,
                      sizeof(struct pim_nexthop_cache));
@@ -122,31 +127,31 @@ struct pim_nexthop_cache *pim_nexthop_cache_add(struct pim_rpf *rpf_addr)
        pnc->rpf.rpf_addr.u.prefix4.s_addr =
                rpf_addr->rpf_addr.u.prefix4.s_addr;
 
-       pnc = hash_get(pimg->rpf_hash, pnc, hash_alloc_intern);
+       pnc = hash_get(pim->rpf_hash, pnc, hash_alloc_intern);
 
        pnc->rp_list = list_new();
        pnc->rp_list->cmp = pim_rp_list_cmp;
 
-       pnc->upstream_list = list_new();
-       pnc->upstream_list->cmp = pim_upstream_compare;
-
-       if (PIM_DEBUG_ZEBRA) {
-               char rpf_str[PREFIX_STRLEN];
-               pim_addr_dump("<nht?>", &rpf_addr->rpf_addr, rpf_str,
-                             sizeof(rpf_str));
-               zlog_debug(
-                       "%s: NHT hash node, RP and UP lists allocated for %s ",
-                       __PRETTY_FUNCTION__, rpf_str);
-       }
+       snprintf(hash_name, 64, "PNC %s(%s) Upstream Hash",
+                prefix2str(&pnc->rpf.rpf_addr, buf1, 64),
+                pim->vrf->name);
+       pnc->upstream_hash = hash_create_size(8192, pim_upstream_hash_key,
+                                             pim_upstream_equal,
+                                             hash_name);
 
        return pnc;
 }
 
-/* This API is used to Register an address with Zebra
-   ret 1 means nexthop cache is found.
-*/
-int pim_find_or_track_nexthop(struct prefix *addr, struct pim_upstream *up,
-                             struct rp_info *rp,
+/*
+ * pim_find_or_track_nexthop
+ *
+ * This API is used to Register an address with Zebra
+ *
+ * 1 -> Success
+ * 0 -> Failure
+ */
+int pim_find_or_track_nexthop(struct pim_instance *pim, struct prefix *addr,
+                             struct pim_upstream *up, struct rp_info *rp,
                              struct pim_nexthop_cache *out_pnc)
 {
        struct pim_nexthop_cache *pnc = NULL;
@@ -160,50 +165,36 @@ int pim_find_or_track_nexthop(struct prefix *addr, struct pim_upstream *up,
        rpf.rpf_addr.prefixlen = addr->prefixlen;
        rpf.rpf_addr.u.prefix4 = addr->u.prefix4;
 
-       pnc = pim_nexthop_cache_find(&rpf);
+       pnc = pim_nexthop_cache_find(pim, &rpf);
        if (!pnc) {
-               pnc = pim_nexthop_cache_add(&rpf);
-               if (pnc)
-                       pim_sendmsg_zebra_rnh(zclient, pnc,
-                                             ZEBRA_NEXTHOP_REGISTER);
-               else {
+               pnc = pim_nexthop_cache_add(pim, &rpf);
+               if (!pnc) {
                        char rpf_str[PREFIX_STRLEN];
                        pim_addr_dump("<nht-pnc?>", addr, rpf_str,
                                      sizeof(rpf_str));
                        zlog_warn("%s: pnc node allocation failed. addr %s ",
                                  __PRETTY_FUNCTION__, rpf_str);
-                       return -1;
+                       return 0;
+               }
+               pim_sendmsg_zebra_rnh(pim, zclient, pnc,
+                                     ZEBRA_NEXTHOP_REGISTER);
+               if (PIM_DEBUG_PIM_NHT) {
+                       char buf[PREFIX2STR_BUFFER];
+                       prefix2str(addr, buf, sizeof(buf));
+                       zlog_debug(
+                               "%s: NHT cache and zebra notification added for %s(%s)",
+                               __PRETTY_FUNCTION__, buf, pim->vrf->name);
                }
        }
 
        if (rp != NULL) {
                ch_node = listnode_lookup(pnc->rp_list, rp);
-               if (ch_node == NULL) {
-                       if (PIM_DEBUG_ZEBRA) {
-                               char rp_str[PREFIX_STRLEN];
-                               pim_addr_dump("<rp?>", &rp->rp.rpf_addr, rp_str,
-                                             sizeof(rp_str));
-                               zlog_debug(
-                                       "%s: Add RP %s node to pnc cached list",
-                                       __PRETTY_FUNCTION__, rp_str);
-                       }
+               if (ch_node == NULL)
                        listnode_add_sort(pnc->rp_list, rp);
-               }
        }
 
-       if (up != NULL) {
-               ch_node = listnode_lookup(pnc->upstream_list, up);
-               if (ch_node == NULL) {
-                       if (PIM_DEBUG_ZEBRA) {
-                               char buf[PREFIX2STR_BUFFER];
-                               prefix2str(addr, buf, sizeof(buf));
-                               zlog_debug(
-                                       "%s: Add upstream %s node to pnc cached list, rpf %s",
-                                       __PRETTY_FUNCTION__, up->sg_str, buf);
-                       }
-                       listnode_add_sort(pnc->upstream_list, up);
-               }
-       }
+       if (up != NULL)
+               up = hash_get(pnc->upstream_hash, up, hash_alloc_intern);
 
        if (pnc && CHECK_FLAG(pnc->flags, PIM_NEXTHOP_VALID)) {
                memcpy(out_pnc, pnc, sizeof(struct pim_nexthop_cache));
@@ -213,8 +204,8 @@ int pim_find_or_track_nexthop(struct prefix *addr, struct pim_upstream *up,
        return 0;
 }
 
-void pim_delete_tracked_nexthop(struct prefix *addr, struct pim_upstream *up,
-                               struct rp_info *rp)
+void pim_delete_tracked_nexthop(struct pim_instance *pim, struct prefix *addr,
+                               struct pim_upstream *up, struct rp_info *rp)
 {
        struct pim_nexthop_cache *pnc = NULL;
        struct pim_nexthop_cache lookup;
@@ -224,28 +215,31 @@ void pim_delete_tracked_nexthop(struct prefix *addr, struct pim_upstream *up,
 
        /* Remove from RPF hash if it is the last entry */
        lookup.rpf.rpf_addr = *addr;
-       pnc = hash_lookup(pimg->rpf_hash, &lookup);
+       pnc = hash_lookup(pim->rpf_hash, &lookup);
        if (pnc) {
                if (rp)
                        listnode_delete(pnc->rp_list, rp);
                if (up)
-                       listnode_delete(pnc->upstream_list, up);
+                       hash_release(pnc->upstream_hash, up);
 
-               if (PIM_DEBUG_ZEBRA)
+               if (PIM_DEBUG_PIM_NHT) {
+                       char buf[PREFIX_STRLEN];
+                       prefix2str(addr, buf, sizeof buf);
                        zlog_debug(
-                               "%s: NHT rp_list count:%d upstream_list count:%d ",
-                               __PRETTY_FUNCTION__, pnc->rp_list->count,
-                               pnc->upstream_list->count);
+                               "%s: NHT %s(%s) rp_list count:%d upstream count:%ld",
+                               __PRETTY_FUNCTION__, buf, pim->vrf->name,
+                               pnc->rp_list->count, pnc->upstream_hash->count);
+               }
 
                if (pnc->rp_list->count == 0
-                   && pnc->upstream_list->count == 0) {
-                       pim_sendmsg_zebra_rnh(zclient, pnc,
+                   && pnc->upstream_hash->count == 0) {
+                       pim_sendmsg_zebra_rnh(pim, zclient, pnc,
                                              ZEBRA_NEXTHOP_UNREGISTER);
 
                        list_delete(pnc->rp_list);
-                       list_delete(pnc->upstream_list);
+                       hash_free(pnc->upstream_hash);
 
-                       hash_release(pimg->rpf_hash, pnc);
+                       hash_release(pim->rpf_hash, pnc);
                        if (pnc->nexthop)
                                nexthops_free(pnc->nexthop);
                        XFREE(MTYPE_PIM_NEXTHOP_CACHE, pnc);
@@ -254,7 +248,8 @@ void pim_delete_tracked_nexthop(struct prefix *addr, struct pim_upstream *up,
 }
 
 /* Update RP nexthop info based on Nexthop update received from Zebra.*/
-int pim_update_rp_nh(struct pim_nexthop_cache *pnc)
+static int pim_update_rp_nh(struct pim_instance *pim,
+                           struct pim_nexthop_cache *pnc)
 {
        struct listnode *node = NULL;
        struct rp_info *rp_info = NULL;
@@ -266,25 +261,12 @@ int pim_update_rp_nh(struct pim_nexthop_cache *pnc)
                        continue;
 
                // Compute PIM RPF using cached nexthop
-               ret = pim_ecmp_nexthop_search(pnc, &rp_info->rp.source_nexthop,
-                                             &rp_info->rp.rpf_addr,
-                                             &rp_info->group, 1);
-
-               if (PIM_DEBUG_TRACE) {
-                       char rp_str[PREFIX_STRLEN];
-                       pim_addr_dump("<rp?>", &rp_info->rp.rpf_addr, rp_str,
-                                     sizeof(rp_str));
-                       zlog_debug(
-                               "%s: NHT update, nexthop for RP %s is interface %s ",
-                               __PRETTY_FUNCTION__, rp_str,
-                               rp_info->rp.source_nexthop.interface->name);
-               }
+               ret = pim_ecmp_nexthop_search(
+                       pim, pnc, &rp_info->rp.source_nexthop,
+                       &rp_info->rp.rpf_addr, &rp_info->group, 1);
        }
 
-       if (ret)
-               return 0;
-
-       return 1;
+       return !ret;
 }
 
 /* This API is used to traverse nexthop cache of RPF addr
@@ -292,152 +274,148 @@ int pim_update_rp_nh(struct pim_nexthop_cache *pnc)
    unresolved state and due to event like pim neighbor
    UP event if it can be resolved.
 */
-void pim_resolve_upstream_nh(struct prefix *nht_p)
+void pim_resolve_upstream_nh(struct pim_instance *pim, struct prefix *nht_p)
 {
        struct nexthop *nh_node = NULL;
        struct pim_nexthop_cache pnc;
        struct pim_neighbor *nbr = NULL;
 
        memset(&pnc, 0, sizeof(struct pim_nexthop_cache));
-       if ((pim_find_or_track_nexthop(nht_p, NULL, NULL, &pnc)) == 1) {
-               for (nh_node = pnc.nexthop; nh_node; nh_node = nh_node->next) {
-                       if (nh_node->gate.ipv4.s_addr == 0) {
-                               struct interface *ifp1 = if_lookup_by_index(
-                                       nh_node->ifindex, VRF_DEFAULT);
-                               nbr = pim_neighbor_find_if(ifp1);
-                               if (nbr) {
-                                       nh_node->gate.ipv4 = nbr->source_addr;
-                                       if (PIM_DEBUG_TRACE) {
-                                               char str[PREFIX_STRLEN];
-                                               char str1[INET_ADDRSTRLEN];
-                                               pim_inet4_dump("<nht_nbr?>",
-                                                              nbr->source_addr,
-                                                              str1,
-                                                              sizeof(str1));
-                                               pim_addr_dump("<nht_addr?>",
-                                                             nht_p, str,
-                                                             sizeof(str));
-                                               zlog_debug(
-                                                       "%s: addr %s new nexthop addr %s interface %s",
-                                                       __PRETTY_FUNCTION__,
-                                                       str, str1, ifp1->name);
-                                       }
-                               }
-                       }
+       if (!pim_find_or_track_nexthop(pim, nht_p, NULL, NULL, &pnc))
+               return;
+
+       for (nh_node = pnc.nexthop; nh_node; nh_node = nh_node->next) {
+               if (nh_node->gate.ipv4.s_addr != 0)
+                       continue;
+
+               struct interface *ifp1 =
+                       if_lookup_by_index(nh_node->ifindex, pim->vrf_id);
+               nbr = pim_neighbor_find_if(ifp1);
+               if (!nbr)
+                       continue;
+
+               nh_node->gate.ipv4 = nbr->source_addr;
+               if (PIM_DEBUG_PIM_NHT) {
+                       char str[PREFIX_STRLEN];
+                       char str1[INET_ADDRSTRLEN];
+                       pim_inet4_dump("<nht_nbr?>", nbr->source_addr, str1,
+                                      sizeof(str1));
+                       pim_addr_dump("<nht_addr?>", nht_p, str, sizeof(str));
+                       zlog_debug(
+                               "%s: addr %s new nexthop addr %s interface %s",
+                               __PRETTY_FUNCTION__, str, str1, ifp1->name);
                }
        }
 }
 
 /* Update Upstream nexthop info based on Nexthop update received from Zebra.*/
-static int pim_update_upstream_nh(struct pim_nexthop_cache *pnc)
+static int pim_update_upstream_nh_helper(struct hash_backet *backet, void *arg)
 {
-       struct listnode *up_node;
-       struct listnode *ifnode;
-       struct listnode *up_nextnode;
-       struct listnode *node;
-       struct pim_upstream *up = NULL;
-       struct interface *ifp = NULL;
+       struct pim_instance *pim = (struct pim_instance *)arg;
+       struct pim_upstream *up = (struct pim_upstream *)backet->data;
        int vif_index = 0;
 
-       for (ALL_LIST_ELEMENTS(pnc->upstream_list, up_node, up_nextnode, up)) {
-               enum pim_rpf_result rpf_result;
-               struct pim_rpf old;
+       enum pim_rpf_result rpf_result;
+       struct pim_rpf old;
 
-               old.source_nexthop.interface = up->rpf.source_nexthop.interface;
-               rpf_result = pim_rpf_update(up, &old, 0);
-               if (rpf_result == PIM_RPF_FAILURE)
-                       continue;
+       old.source_nexthop.interface = up->rpf.source_nexthop.interface;
+       rpf_result = pim_rpf_update(pim, up, &old, 0);
+       if (rpf_result == PIM_RPF_FAILURE)
+               return HASHWALK_CONTINUE;
 
-               /* update kernel multicast forwarding cache (MFC) */
-               if (up->channel_oil) {
-                       ifindex_t ifindex =
-                               up->rpf.source_nexthop.interface->ifindex;
-                       vif_index = pim_if_find_vifindex_by_ifindex(ifindex);
-                       /* Pass Current selected NH vif index to mroute download
-                        */
-                       if (vif_index)
-                               pim_scan_individual_oil(up->channel_oil,
-                                                       vif_index);
-                       else {
-                               if (PIM_DEBUG_ZEBRA)
-                                       zlog_debug(
-                                               "%s: NHT upstream %s channel_oil IIF %s vif_index is not valid",
-                                               __PRETTY_FUNCTION__, up->sg_str,
-                                               up->rpf.source_nexthop
-                                                       .interface->name);
-                       }
+       /* update kernel multicast forwarding cache (MFC) */
+       if (up->channel_oil) {
+               ifindex_t ifindex = up->rpf.source_nexthop.interface->ifindex;
+
+               vif_index = pim_if_find_vifindex_by_ifindex(pim, ifindex);
+               /* Pass Current selected NH vif index to mroute download
+                */
+               if (vif_index)
+                       pim_scan_individual_oil(up->channel_oil, vif_index);
+               else {
+                       if (PIM_DEBUG_PIM_NHT)
+                               zlog_debug(
+                                       "%s: NHT upstream %s channel_oil IIF %s vif_index is not valid",
+                                       __PRETTY_FUNCTION__, up->sg_str,
+                                       up->rpf.source_nexthop.interface->name);
                }
+       }
 
-               if (rpf_result == PIM_RPF_CHANGED) {
-                       struct pim_neighbor *nbr;
+       if (rpf_result == PIM_RPF_CHANGED) {
+               struct pim_neighbor *nbr;
 
-                       nbr = pim_neighbor_find(old.source_nexthop.interface,
-                                               old.rpf_addr.u.prefix4);
-                       if (nbr)
-                               pim_jp_agg_remove_group(nbr->upstream_jp_agg,
-                                                       up);
+               nbr = pim_neighbor_find(old.source_nexthop.interface,
+                                       old.rpf_addr.u.prefix4);
+               if (nbr)
+                       pim_jp_agg_remove_group(nbr->upstream_jp_agg, up);
 
+               /*
+                * We have detected a case where we might need to rescan
+                * the inherited o_list so do it.
+                */
+               if (up->channel_oil
+                   && up->channel_oil->oil_inherited_rescan) {
+                       pim_upstream_inherited_olist_decide(pim, up);
+                       up->channel_oil->oil_inherited_rescan = 0;
+               }
+
+               if (up->join_state == PIM_UPSTREAM_JOINED) {
                        /*
-                        * We have detected a case where we might need to rescan
-                        * the inherited o_list so do it.
+                        * If we come up real fast we can be here
+                        * where the mroute has not been installed
+                        * so install it.
                         */
                        if (up->channel_oil
-                           && up->channel_oil->oil_inherited_rescan) {
-                               pim_upstream_inherited_olist_decide(up);
-                               up->channel_oil->oil_inherited_rescan = 0;
-                       }
+                           && !up->channel_oil->installed)
+                               pim_mroute_add(up->channel_oil,
+                                              __PRETTY_FUNCTION__);
 
-                       if (up->join_state == PIM_UPSTREAM_JOINED) {
-                               /*
-                                * If we come up real fast we can be here
-                                * where the mroute has not been installed
-                                * so install it.
-                                */
-                               if (up->channel_oil
-                                   && !up->channel_oil->installed)
-                                       pim_mroute_add(up->channel_oil,
-                                                      __PRETTY_FUNCTION__);
-
-                               /*
-                                  RFC 4601: 4.5.7.  Sending (S,G) Join/Prune
-                                  Messages
-
-                                  Transitions from Joined State
-
-                                  RPF'(S,G) changes not due to an Assert
-
-                                  The upstream (S,G) state machine remains in
-                                  Joined
-                                  state. Send Join(S,G) to the new upstream
-                                  neighbor, which is
-                                  the new value of RPF'(S,G).  Send Prune(S,G)
-                                  to the old
-                                  upstream neighbor, which is the old value of
-                                  RPF'(S,G).  Set
-                                  the Join Timer (JT) to expire after
-                                  t_periodic seconds.
-                                */
-                               pim_jp_agg_switch_interface(&old, &up->rpf, up);
-
-                               pim_upstream_join_timer_restart(up, &old);
-                       } /* up->join_state == PIM_UPSTREAM_JOINED */
-
-                       /* FIXME can join_desired actually be changed by
-                          pim_rpf_update()
-                          returning PIM_RPF_CHANGED ? */
-                       pim_upstream_update_join_desired(up);
-
-               } /* PIM_RPF_CHANGED */
-
-               if (PIM_DEBUG_TRACE) {
-                       zlog_debug("%s: NHT upstream %s old ifp %s new ifp %s",
-                                  __PRETTY_FUNCTION__, up->sg_str,
-                                  old.source_nexthop.interface->name,
-                                  up->rpf.source_nexthop.interface->name);
-               }
-       } /* for (pnc->upstream_list) */
+                       /*
+                        * RFC 4601: 4.5.7.  Sending (S,G) Join/Prune Messages
+                        *
+                        * Transitions from Joined State
+                        *
+                        * RPF'(S,G) changes not due to an Assert
+                        *
+                        * The upstream (S,G) state machine remains in Joined
+                        * state. Send Join(S,G) to the new upstream
+                        * neighbor, which is the new value of RPF'(S,G).
+                        * Send Prune(S,G) to the old upstream neighbor, which
+                        * is the old value of RPF'(S,G).  Set the Join
+                        * Timer (JT) to expire after t_periodic seconds.
+                        */
+                       pim_jp_agg_switch_interface(&old, &up->rpf, up);
+
+                       pim_upstream_join_timer_restart(up, &old);
+               } /* up->join_state == PIM_UPSTREAM_JOINED */
+
+               /*
+                * FIXME can join_desired actually be changed by
+                * pim_rpf_update() returning PIM_RPF_CHANGED ?
+                */
+               pim_upstream_update_join_desired(pim, up);
+
+       } /* PIM_RPF_CHANGED */
+
+       if (PIM_DEBUG_PIM_NHT) {
+               zlog_debug("%s: NHT upstream %s(%s) old ifp %s new ifp %s",
+                          __PRETTY_FUNCTION__, up->sg_str, pim->vrf->name,
+                          old.source_nexthop.interface->name,
+                          up->rpf.source_nexthop.interface->name);
+       }
 
-       for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT), ifnode, ifp))
+       return HASHWALK_CONTINUE;
+}
+
+static int pim_update_upstream_nh(struct pim_instance *pim,
+                                 struct pim_nexthop_cache *pnc)
+{
+       struct listnode *node, *ifnode;
+       struct interface *ifp;
+
+       hash_walk(pnc->upstream_hash, pim_update_upstream_nh_helper, pim);
+
+       for (ALL_LIST_ELEMENTS_RO(vrf_iflist(pim->vrf_id), ifnode, ifp))
                if (ifp->info) {
                        struct pim_interface *pim_ifp = ifp->info;
                        struct pim_iface_upstream_switch *us;
@@ -475,19 +453,11 @@ uint32_t pim_compute_ecmp_hash(struct prefix *src, struct prefix *grp)
        }
 
        hash_val = jhash_2words(g, s, 101);
-       if (PIM_DEBUG_PIM_TRACE_DETAIL) {
-               char buf[PREFIX2STR_BUFFER];
-               char bufg[PREFIX2STR_BUFFER];
-               prefix2str(src, buf, sizeof(buf));
-               if (grp)
-                       prefix2str(grp, bufg, sizeof(bufg));
-               zlog_debug("%s: addr %s %s hash_val %u", __PRETTY_FUNCTION__,
-                          buf, grp ? bufg : "", hash_val);
-       }
        return hash_val;
 }
 
-int pim_ecmp_nexthop_search(struct pim_nexthop_cache *pnc,
+int pim_ecmp_nexthop_search(struct pim_instance *pim,
+                           struct pim_nexthop_cache *pnc,
                            struct pim_nexthop *nexthop, struct prefix *src,
                            struct prefix *grp, int neighbor_needed)
 {
@@ -499,7 +469,7 @@ int pim_ecmp_nexthop_search(struct pim_nexthop_cache *pnc,
        uint8_t nh_iter = 0, found = 0;
 
        if (!pnc || !pnc->nexthop_num || !nexthop)
-               return -1;
+               return 0;
 
        // Current Nexthop is VALID, check to stay on the current path.
        if (nexthop->interface && nexthop->interface->info
@@ -517,9 +487,12 @@ int pim_ecmp_nexthop_search(struct pim_nexthop_cache *pnc,
                        // If the current nexthop is not valid, candidate to
                        // choose new Nexthop.
                        for (nh_node = pnc->nexthop; nh_node;
-                            nh_node = nh_node->next)
+                            nh_node = nh_node->next) {
                                curr_route_valid = (nexthop->interface->ifindex
                                                    == nh_node->ifindex);
+                               if (curr_route_valid)
+                                       break;
+                       }
 
                        if (curr_route_valid
                            && !pim_if_connected_to_source(nexthop->interface,
@@ -529,12 +502,12 @@ int pim_ecmp_nexthop_search(struct pim_nexthop_cache *pnc,
                                        nexthop->mrib_nexthop_addr.u.prefix4);
                                if (!nbr
                                    && !if_is_loopback(nexthop->interface)) {
-                                       if (PIM_DEBUG_TRACE)
+                                       if (PIM_DEBUG_PIM_NHT)
                                                zlog_debug(
                                                        "%s: current nexthop does not have nbr ",
                                                        __PRETTY_FUNCTION__);
                                } else {
-                                       if (PIM_DEBUG_TRACE) {
+                                       if (PIM_DEBUG_PIM_NHT) {
                                                char src_str[INET_ADDRSTRLEN];
                                                pim_inet4_dump("<addr?>",
                                                               src->u.prefix4,
@@ -546,9 +519,10 @@ int pim_ecmp_nexthop_search(struct pim_nexthop_cache *pnc,
                                                               grp_str,
                                                               sizeof(grp_str));
                                                zlog_debug(
-                                                       "%s: (%s, %s) current nexthop %s is valid, skipping new path selection",
+                                                       "%s: (%s,%s)(%s) current nexthop %s is valid, skipping new path selection",
                                                        __PRETTY_FUNCTION__,
                                                        src_str, grp_str,
+                                                       pim->vrf->name,
                                                        nexthop->interface->name);
                                        }
                                        return 0;
@@ -560,24 +534,22 @@ int pim_ecmp_nexthop_search(struct pim_nexthop_cache *pnc,
                // PIM ECMP flag is enable then choose ECMP path.
                hash_val = pim_compute_ecmp_hash(src, grp);
                mod_val = hash_val % pnc->nexthop_num;
-               if (PIM_DEBUG_PIM_TRACE_DETAIL)
-                       zlog_debug("%s: hash_val %u mod_val %u ",
-                                  __PRETTY_FUNCTION__, hash_val, mod_val);
        }
 
        for (nh_node = pnc->nexthop; nh_node && (found == 0);
             nh_node = nh_node->next) {
                first_ifindex = nh_node->ifindex;
-               ifp = if_lookup_by_index(first_ifindex, VRF_DEFAULT);
+               ifp = if_lookup_by_index(first_ifindex, pim->vrf_id);
                if (!ifp) {
-                       if (PIM_DEBUG_ZEBRA) {
+                       if (PIM_DEBUG_PIM_NHT) {
                                char addr_str[INET_ADDRSTRLEN];
                                pim_inet4_dump("<addr?>", src->u.prefix4,
                                               addr_str, sizeof(addr_str));
                                zlog_debug(
-                                       "%s %s: could not find interface for ifindex %d (address %s)",
+                                       "%s %s: could not find interface for ifindex %d (address %s(%s))",
                                        __FILE__, __PRETTY_FUNCTION__,
-                                       first_ifindex, addr_str);
+                                       first_ifindex, addr_str,
+                                       pim->vrf->name);
                        }
                        if (nh_iter == mod_val)
                                mod_val++; // Select nexthpath
@@ -585,14 +557,15 @@ int pim_ecmp_nexthop_search(struct pim_nexthop_cache *pnc,
                        continue;
                }
                if (!ifp->info) {
-                       if (PIM_DEBUG_ZEBRA) {
+                       if (PIM_DEBUG_PIM_NHT) {
                                char addr_str[INET_ADDRSTRLEN];
                                pim_inet4_dump("<addr?>", src->u.prefix4,
                                               addr_str, sizeof(addr_str));
                                zlog_debug(
-                                       "%s: multicast not enabled on input interface %s (ifindex=%d, RPF for source %s)",
+                                       "%s: multicast not enabled on input interface %s(%s) (ifindex=%d, RPF for source %s)",
                                        __PRETTY_FUNCTION__, ifp->name,
-                                       first_ifindex, addr_str);
+                                       pim->vrf->name, first_ifindex,
+                                       addr_str);
                        }
                        if (nh_iter == mod_val)
                                mod_val++; // Select nexthpath
@@ -603,14 +576,12 @@ int pim_ecmp_nexthop_search(struct pim_nexthop_cache *pnc,
                if (neighbor_needed
                    && !pim_if_connected_to_source(ifp, src->u.prefix4)) {
                        nbr = pim_neighbor_find(ifp, nh_node->gate.ipv4);
-                       if (PIM_DEBUG_PIM_TRACE_DETAIL)
-                               zlog_debug("ifp name: %s, pim nbr: %p",
-                                          ifp->name, nbr);
                        if (!nbr && !if_is_loopback(ifp)) {
-                               if (PIM_DEBUG_ZEBRA)
+                               if (PIM_DEBUG_PIM_NHT)
                                        zlog_debug(
-                                               "%s: pim nbr not found on input interface %s",
-                                               __PRETTY_FUNCTION__, ifp->name);
+                                               "%s: pim nbr not found on input interface %s(%s)",
+                                               __PRETTY_FUNCTION__, ifp->name,
+                                               pim->vrf->name);
                                if (nh_iter == mod_val)
                                        mod_val++; // Select nexthpath
                                nh_iter++;
@@ -630,7 +601,7 @@ int pim_ecmp_nexthop_search(struct pim_nexthop_cache *pnc,
                        nexthop->last_lookup_time = pim_time_monotonic_usec();
                        nexthop->nbr = nbr;
                        found = 1;
-                       if (PIM_DEBUG_ZEBRA) {
+                       if (PIM_DEBUG_PIM_NHT) {
                                char buf[INET_ADDRSTRLEN];
                                char buf2[INET_ADDRSTRLEN];
                                char buf3[INET_ADDRSTRLEN];
@@ -643,19 +614,19 @@ int pim_ecmp_nexthop_search(struct pim_nexthop_cache *pnc,
                                        nexthop->mrib_nexthop_addr.u.prefix4,
                                        buf, sizeof(buf));
                                zlog_debug(
-                                       "%s: (%s, %s) selected nhop interface %s addr %s mod_val %u iter %d ecmp %d",
+                                       "%s: (%s,%s)(%s) selected nhop interface %s addr %s mod_val %u iter %d ecmp %d",
                                        __PRETTY_FUNCTION__, buf2, buf3,
-                                       ifp->name, buf, mod_val, nh_iter,
-                                       qpim_ecmp_enable);
+                                       pim->vrf->name, ifp->name, buf, mod_val,
+                                       nh_iter, qpim_ecmp_enable);
                        }
                }
                nh_iter++;
        }
 
        if (found)
-               return 0;
+               return 1;
        else
-               return -1;
+               return 0;
 }
 
 /* This API is used to parse Registered address nexthop update coming from Zebra
@@ -676,8 +647,8 @@ int pim_parse_nexthop_update(int command, struct zclient *zclient,
        struct pim_neighbor *nbr = NULL;
        struct interface *ifp = NULL;
        struct interface *ifp1 = NULL;
-       struct pim_interface *pim_ifp = NULL;
-       char str[INET_ADDRSTRLEN];
+       struct vrf *vrf = vrf_lookup_by_id(vrf_id);
+       struct pim_instance *pim = vrf->info;
 
        s = zclient->ibuf;
        memset(&p, 0, sizeof(struct prefix));
@@ -698,9 +669,9 @@ int pim_parse_nexthop_update(int command, struct zclient *zclient,
                rpf.rpf_addr.family = p.family;
                rpf.rpf_addr.prefixlen = p.prefixlen;
                rpf.rpf_addr.u.prefix4.s_addr = p.u.prefix4.s_addr;
-               pnc = pim_nexthop_cache_find(&rpf);
+               pnc = pim_nexthop_cache_find(pim, &rpf);
                if (!pnc) {
-                       if (PIM_DEBUG_TRACE) {
+                       if (PIM_DEBUG_PIM_NHT) {
                                char buf[PREFIX2STR_BUFFER];
                                prefix2str(&rpf.rpf_addr, buf, sizeof(buf));
                                zlog_debug(
@@ -746,31 +717,12 @@ int pim_parse_nexthop_update(int command, struct zclient *zclient,
                                stream_get(&nexthop->gate.ipv6, s, 16);
                                nexthop->ifindex = stream_getl(s);
                                ifp1 = if_lookup_by_index(nexthop->ifindex,
-                                                         VRF_DEFAULT);
+                                                         pim->vrf_id);
                                nbr = pim_neighbor_find_if(ifp1);
                                /* Overwrite with Nbr address as NH addr */
-                               if (nbr) {
+                               if (nbr)
                                        nexthop->gate.ipv4 = nbr->source_addr;
-                                       if (PIM_DEBUG_TRACE) {
-                                               pim_inet4_dump("<nht_nbr?>",
-                                                              nbr->source_addr,
-                                                              str,
-                                                              sizeof(str));
-                                               zlog_debug(
-                                                       "%s: NHT using pim nbr addr %s interface %s as rpf",
-                                                       __PRETTY_FUNCTION__,
-                                                       str, ifp1->name);
-                                       }
-                               } else {
-                                       if (PIM_DEBUG_TRACE) {
-                                               pim_ifp = ifp1->info;
-                                               zlog_debug(
-                                                       "%s: NHT pim nbr not found on interface %s nbr count:%d ",
-                                                       __PRETTY_FUNCTION__,
-                                                       ifp1->name,
-                                                       pim_ifp->pim_neighbor_list
-                                                               ->count);
-                                       }
+                               else {
                                        // Mark nexthop address to 0 until PIM
                                        // Nbr is resolved.
                                        nexthop->gate.ipv4.s_addr =
@@ -783,24 +735,15 @@ int pim_parse_nexthop_update(int command, struct zclient *zclient,
                                break;
                        }
 
-                       if (PIM_DEBUG_TRACE) {
-                               char p_str[PREFIX2STR_BUFFER];
-                               prefix2str(&p, p_str, sizeof(p_str));
-                               zlog_debug(
-                                       "%s: NHT addr %s %d-nhop via %s type %d distance:%u metric:%u ",
-                                       __PRETTY_FUNCTION__, p_str, i + 1,
-                                       inet_ntoa(nexthop->gate.ipv4),
-                                       nexthop->type, distance, metric);
-                       }
-
-                       ifp = if_lookup_by_index(nexthop->ifindex, VRF_DEFAULT);
+                       ifp = if_lookup_by_index(nexthop->ifindex, pim->vrf_id);
                        if (!ifp) {
-                               if (PIM_DEBUG_ZEBRA) {
+                               if (PIM_DEBUG_PIM_NHT) {
                                        char buf[NEXTHOP_STRLEN];
                                        zlog_debug(
-                                               "%s: could not find interface for ifindex %d (addr %s)",
+                                               "%s: could not find interface for ifindex %d(%s) (addr %s)",
                                                __PRETTY_FUNCTION__,
                                                nexthop->ifindex,
+                                               pim->vrf->name,
                                                nexthop2str(nexthop, buf,
                                                            sizeof(buf)));
                                }
@@ -808,12 +751,25 @@ int pim_parse_nexthop_update(int command, struct zclient *zclient,
                                continue;
                        }
 
+                       if (PIM_DEBUG_PIM_NHT) {
+                               char p_str[PREFIX2STR_BUFFER];
+                               prefix2str(&p, p_str, sizeof(p_str));
+                               zlog_debug(
+                                       "%s: NHT addr %s(%s) %d-nhop via %s(%s) type %d distance:%u metric:%u ",
+                                       __PRETTY_FUNCTION__, p_str,
+                                       pim->vrf->name, i + 1,
+                                       inet_ntoa(nexthop->gate.ipv4),
+                                       ifp->name, nexthop->type, distance,
+                                       metric);
+                       }
+
                        if (!ifp->info) {
-                               if (PIM_DEBUG_ZEBRA) {
+                               if (PIM_DEBUG_PIM_NHT) {
                                        char buf[NEXTHOP_STRLEN];
                                        zlog_debug(
-                                               "%s: multicast not enabled on input interface %s (ifindex=%d, addr %s)",
+                                               "%s: multicast not enabled on input interface %s(%s) (ifindex=%d, addr %s)",
                                                __PRETTY_FUNCTION__, ifp->name,
+                                               pim->vrf->name,
                                                nexthop->ifindex,
                                                nexthop2str(nexthop, buf,
                                                            sizeof(buf)));
@@ -847,27 +803,28 @@ int pim_parse_nexthop_update(int command, struct zclient *zclient,
                pnc->nexthop = NULL;
        }
 
-       if (PIM_DEBUG_TRACE) {
+       if (PIM_DEBUG_PIM_NHT) {
                char buf[PREFIX2STR_BUFFER];
                prefix2str(&p, buf, sizeof(buf));
                zlog_debug(
-                       "%s: NHT Update for %s num_nh %d num_pim_nh %d vrf:%d up %d rp %d",
-                       __PRETTY_FUNCTION__, buf, nexthop_num, pnc->nexthop_num,
-                       vrf_id, listcount(pnc->upstream_list),
+                       "%s: NHT Update for %s(%s) num_nh %d num_pim_nh %d vrf:%d up %ld rp %d",
+                       __PRETTY_FUNCTION__, buf, pim->vrf->name, nexthop_num,
+                       pnc->nexthop_num, vrf_id, pnc->upstream_hash->count,
                        listcount(pnc->rp_list));
        }
 
        pim_rpf_set_refresh_time();
 
        if (listcount(pnc->rp_list))
-               pim_update_rp_nh(pnc);
-       if (listcount(pnc->upstream_list))
-               pim_update_upstream_nh(pnc);
+               pim_update_rp_nh(pim, pnc);
+       if (pnc->upstream_hash->count)
+               pim_update_upstream_nh(pim, pnc);
 
        return 0;
 }
 
-int pim_ecmp_nexthop_lookup(struct pim_nexthop *nexthop, struct in_addr addr,
+int pim_ecmp_nexthop_lookup(struct pim_instance *pim,
+                           struct pim_nexthop *nexthop, struct in_addr addr,
                            struct prefix *src, struct prefix *grp,
                            int neighbor_needed)
 {
@@ -880,32 +837,35 @@ int pim_ecmp_nexthop_lookup(struct pim_nexthop *nexthop, struct in_addr addr,
        uint8_t i = 0;
        uint32_t hash_val = 0, mod_val = 0;
 
-       if (PIM_DEBUG_TRACE) {
+       if (PIM_DEBUG_PIM_NHT) {
                char addr_str[INET_ADDRSTRLEN];
                pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
-               zlog_debug("%s: Looking up: %s, last lookup time: %lld",
-                          __PRETTY_FUNCTION__, addr_str,
+               zlog_debug("%s: Looking up: %s(%s), last lookup time: %lld",
+                          __PRETTY_FUNCTION__, addr_str, pim->vrf->name,
                           nexthop->last_lookup_time);
        }
 
        memset(nexthop_tab, 0,
               sizeof(struct pim_zlookup_nexthop) * MULTIPATH_NUM);
-       num_ifindex = zclient_lookup_nexthop(nexthop_tab, MULTIPATH_NUM, addr,
-                                            PIM_NEXTHOP_LOOKUP_MAX);
+       num_ifindex = zclient_lookup_nexthop(pim, nexthop_tab, MULTIPATH_NUM,
+                                            addr, PIM_NEXTHOP_LOOKUP_MAX);
        if (num_ifindex < 1) {
-               char addr_str[INET_ADDRSTRLEN];
-               pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
-               zlog_warn(
-                       "%s %s: could not find nexthop ifindex for address %s",
-                       __FILE__, __PRETTY_FUNCTION__, addr_str);
-               return -1;
+               if (PIM_DEBUG_PIM_NHT) {
+                       char addr_str[INET_ADDRSTRLEN];
+                       pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
+                       zlog_warn(
+                               "%s: could not find nexthop ifindex for address %s(%s)",
+                               __PRETTY_FUNCTION__, addr_str,
+                               pim->vrf->name);
+               }
+               return 0;
        }
 
        // If PIM ECMP enable then choose ECMP path.
        if (qpim_ecmp_enable) {
                hash_val = pim_compute_ecmp_hash(src, grp);
                mod_val = hash_val % num_ifindex;
-               if (PIM_DEBUG_PIM_TRACE_DETAIL)
+               if (PIM_DEBUG_PIM_NHT_DETAIL)
                        zlog_debug("%s: hash_val %u mod_val %u",
                                   __PRETTY_FUNCTION__, hash_val, mod_val);
        }
@@ -913,16 +873,17 @@ int pim_ecmp_nexthop_lookup(struct pim_nexthop *nexthop, struct in_addr addr,
        while (!found && (i < num_ifindex)) {
                first_ifindex = nexthop_tab[i].ifindex;
 
-               ifp = if_lookup_by_index(first_ifindex, VRF_DEFAULT);
+               ifp = if_lookup_by_index(first_ifindex, pim->vrf_id);
                if (!ifp) {
-                       if (PIM_DEBUG_ZEBRA) {
+                       if (PIM_DEBUG_PIM_NHT) {
                                char addr_str[INET_ADDRSTRLEN];
                                pim_inet4_dump("<addr?>", addr, addr_str,
                                               sizeof(addr_str));
                                zlog_debug(
-                                       "%s %s: could not find interface for ifindex %d (address %s)",
+                                       "%s %s: could not find interface for ifindex %d (address %s(%s))",
                                        __FILE__, __PRETTY_FUNCTION__,
-                                       first_ifindex, addr_str);
+                                       first_ifindex, addr_str,
+                                       pim->vrf->name);
                        }
                        if (i == mod_val)
                                mod_val++;
@@ -931,14 +892,15 @@ int pim_ecmp_nexthop_lookup(struct pim_nexthop *nexthop, struct in_addr addr,
                }
 
                if (!ifp->info) {
-                       if (PIM_DEBUG_ZEBRA) {
+                       if (PIM_DEBUG_PIM_NHT) {
                                char addr_str[INET_ADDRSTRLEN];
                                pim_inet4_dump("<addr?>", addr, addr_str,
                                               sizeof(addr_str));
                                zlog_debug(
-                                       "%s: multicast not enabled on input interface %s (ifindex=%d, RPF for source %s)",
+                                       "%s: multicast not enabled on input interface %s(%s) (ifindex=%d, RPF for source %s)",
                                        __PRETTY_FUNCTION__, ifp->name,
-                                       first_ifindex, addr_str);
+                                       pim->vrf->name, first_ifindex,
+                                       addr_str);
                        }
                        if (i == mod_val)
                                mod_val++;
@@ -948,29 +910,29 @@ int pim_ecmp_nexthop_lookup(struct pim_nexthop *nexthop, struct in_addr addr,
                if (neighbor_needed && !pim_if_connected_to_source(ifp, addr)) {
                        nbr = pim_neighbor_find(
                                ifp, nexthop_tab[i].nexthop_addr.u.prefix4);
-                       if (PIM_DEBUG_PIM_TRACE_DETAIL)
-                               zlog_debug("ifp name: %s, pim nbr: %p",
-                                          ifp->name, nbr);
+                       if (PIM_DEBUG_PIM_NHT_DETAIL)
+                               zlog_debug("ifp name: %s(%s), pim nbr: %p",
+                                          ifp->name, pim->vrf->name, nbr);
                        if (!nbr && !if_is_loopback(ifp)) {
                                if (i == mod_val)
                                        mod_val++;
                                i++;
-                               if (PIM_DEBUG_ZEBRA) {
+                               if (PIM_DEBUG_PIM_NHT) {
                                        char addr_str[INET_ADDRSTRLEN];
                                        pim_inet4_dump("<addr?>", addr,
                                                       addr_str,
                                                       sizeof(addr_str));
                                        zlog_debug(
-                                               "%s: NBR not found on input interface %s (RPF for source %s)",
+                                               "%s: NBR not found on input interface %s(%s) (RPF for source %s)",
                                                __PRETTY_FUNCTION__, ifp->name,
-                                               addr_str);
+                                               pim->vrf->name, addr_str);
                                }
                                continue;
                        }
                }
 
                if (i == mod_val) {
-                       if (PIM_DEBUG_ZEBRA) {
+                       if (PIM_DEBUG_PIM_NHT) {
                                char nexthop_str[PREFIX_STRLEN];
                                char addr_str[INET_ADDRSTRLEN];
                                pim_addr_dump("<nexthop?>",
@@ -979,9 +941,9 @@ int pim_ecmp_nexthop_lookup(struct pim_nexthop *nexthop, struct in_addr addr,
                                pim_inet4_dump("<addr?>", addr, addr_str,
                                               sizeof(addr_str));
                                zlog_debug(
-                                       "%s %s: found nhop %s for addr %s interface %s metric %d dist %d",
-                                       __FILE__, __PRETTY_FUNCTION__,
-                                       nexthop_str, addr_str, ifp->name,
+                                       "%s: found nhop %s for addr %s interface %s(%s) metric %d dist %d",
+                                       __PRETTY_FUNCTION__, nexthop_str,
+                                       addr_str, ifp->name, pim->vrf->name,
                                        nexthop_tab[i].route_metric,
                                        nexthop_tab[i].protocol_distance);
                        }
@@ -1000,13 +962,15 @@ int pim_ecmp_nexthop_lookup(struct pim_nexthop *nexthop, struct in_addr addr,
                }
                i++;
        }
+
        if (found)
-               return 0;
+               return 1;
        else
-               return -1;
+               return 0;
 }
 
-int pim_ecmp_fib_lookup_if_vif_index(struct in_addr addr, struct prefix *src,
+int pim_ecmp_fib_lookup_if_vif_index(struct pim_instance *pim,
+                                    struct in_addr addr, struct prefix *src,
                                     struct prefix *grp)
 {
        struct pim_zlookup_nexthop nexthop_tab[MULTIPATH_NUM];
@@ -1017,16 +981,16 @@ int pim_ecmp_fib_lookup_if_vif_index(struct in_addr addr, struct prefix *src,
 
        memset(nexthop_tab, 0,
               sizeof(struct pim_zlookup_nexthop) * MULTIPATH_NUM);
-       num_ifindex = zclient_lookup_nexthop(nexthop_tab, MULTIPATH_NUM, addr,
-                                            PIM_NEXTHOP_LOOKUP_MAX);
+       num_ifindex = zclient_lookup_nexthop(pim, nexthop_tab, MULTIPATH_NUM,
+                                            addr, PIM_NEXTHOP_LOOKUP_MAX);
        if (num_ifindex < 1) {
-               if (PIM_DEBUG_ZEBRA) {
+               if (PIM_DEBUG_PIM_NHT) {
                        char addr_str[INET_ADDRSTRLEN];
                        pim_inet4_dump("<addr?>", addr, addr_str,
                                       sizeof(addr_str));
                        zlog_debug(
-                               "%s %s: could not find nexthop ifindex for address %s",
-                               __FILE__, __PRETTY_FUNCTION__, addr_str);
+                               "%s: could not find nexthop ifindex for address %s(%s)",
+                               __PRETTY_FUNCTION__, addr_str, pim->vrf->name);
                }
                return -1;
        }
@@ -1035,32 +999,33 @@ int pim_ecmp_fib_lookup_if_vif_index(struct in_addr addr, struct prefix *src,
        if (qpim_ecmp_enable) {
                hash_val = pim_compute_ecmp_hash(src, grp);
                mod_val = hash_val % num_ifindex;
-               if (PIM_DEBUG_PIM_TRACE_DETAIL)
+               if (PIM_DEBUG_PIM_NHT_DETAIL)
                        zlog_debug("%s: hash_val %u mod_val %u",
                                   __PRETTY_FUNCTION__, hash_val, mod_val);
        }
 
        first_ifindex = nexthop_tab[mod_val].ifindex;
 
-       if (PIM_DEBUG_ZEBRA) {
+       if (PIM_DEBUG_PIM_NHT) {
                char addr_str[INET_ADDRSTRLEN];
                pim_inet4_dump("<ifaddr?>", addr, addr_str, sizeof(addr_str));
                zlog_debug(
-                       "%s %s: found nexthop ifindex=%d (interface %s) for address %s",
-                       __FILE__, __PRETTY_FUNCTION__, first_ifindex,
-                       ifindex2ifname(first_ifindex, VRF_DEFAULT), addr_str);
+                       "%s: found nexthop ifindex=%d (interface %s(%s)) for address %s",
+                       __PRETTY_FUNCTION__, first_ifindex,
+                       ifindex2ifname(first_ifindex, pim->vrf_id),
+                       pim->vrf->name, addr_str);
        }
 
-       vif_index = pim_if_find_vifindex_by_ifindex(first_ifindex);
+       vif_index = pim_if_find_vifindex_by_ifindex(pim, first_ifindex);
 
        if (vif_index < 0) {
-               if (PIM_DEBUG_ZEBRA) {
+               if (PIM_DEBUG_PIM_NHT) {
                        char addr_str[INET_ADDRSTRLEN];
                        pim_inet4_dump("<addr?>", addr, addr_str,
                                       sizeof(addr_str));
                        zlog_debug(
-                               "%s %s: low vif_index=%d < 1 nexthop for address %s",
-                               __FILE__, __PRETTY_FUNCTION__, vif_index,
+                               "%s: low vif_index=%d(%s) < 1 nexthop for address %s",
+                               __PRETTY_FUNCTION__, vif_index, pim->vrf->name,
                                addr_str);
                }
                return -2;
index fb8d83623577508463175713f714f2807d115877..72ed777bf77ebeea4501011d1db2aa2684224fea 100644 (file)
@@ -43,29 +43,31 @@ struct pim_nexthop_cache {
 #define PIM_NEXTHOP_VALID             (1 << 0)
 
        struct list *rp_list;
-       struct list *upstream_list;
+       struct hash *upstream_hash;
 };
 
 int pim_parse_nexthop_update(int command, struct zclient *zclient,
                             zebra_size_t length, vrf_id_t vrf_id);
-int pim_find_or_track_nexthop(struct prefix *addr, struct pim_upstream *up,
-                             struct rp_info *rp,
+int pim_find_or_track_nexthop(struct pim_instance *pim, struct prefix *addr,
+                             struct pim_upstream *up, struct rp_info *rp,
                              struct pim_nexthop_cache *out_pnc);
-void pim_delete_tracked_nexthop(struct prefix *addr, struct pim_upstream *up,
-                               struct rp_info *rp);
-struct pim_nexthop_cache *pim_nexthop_cache_add(struct pim_rpf *rpf_addr);
-struct pim_nexthop_cache *pim_nexthop_cache_find(struct pim_rpf *rpf);
+void pim_delete_tracked_nexthop(struct pim_instance *pim, struct prefix *addr,
+                               struct pim_upstream *up, struct rp_info *rp);
+struct pim_nexthop_cache *pim_nexthop_cache_find(struct pim_instance *pim,
+                                                struct pim_rpf *rpf);
 uint32_t pim_compute_ecmp_hash(struct prefix *src, struct prefix *grp);
-int pim_ecmp_nexthop_search(struct pim_nexthop_cache *pnc,
+int pim_ecmp_nexthop_search(struct pim_instance *pim,
+                           struct pim_nexthop_cache *pnc,
                            struct pim_nexthop *nexthop, struct prefix *src,
                            struct prefix *grp, int neighbor_needed);
-int pim_ecmp_nexthop_lookup(struct pim_nexthop *nexthop, struct in_addr addr,
+int pim_ecmp_nexthop_lookup(struct pim_instance *pim,
+                           struct pim_nexthop *nexthop, struct in_addr addr,
                            struct prefix *src, struct prefix *grp,
                            int neighbor_needed);
-void pim_sendmsg_zebra_rnh(struct zclient *zclient,
+void pim_sendmsg_zebra_rnh(struct pim_instance *pim, struct zclient *zclient,
                           struct pim_nexthop_cache *pnc, int command);
-int pim_update_rp_nh(struct pim_nexthop_cache *pnc);
-void pim_resolve_upstream_nh(struct prefix *nht_p);
-int pim_ecmp_fib_lookup_if_vif_index(struct in_addr addr, struct prefix *src,
+void pim_resolve_upstream_nh(struct pim_instance *pim, struct prefix *nht_p);
+int pim_ecmp_fib_lookup_if_vif_index(struct pim_instance *pim,
+                                    struct in_addr addr, struct prefix *src,
                                     struct prefix *grp);
 #endif
index aeef0ff4ec60a7d9d8a546755bb6c1498cb9a2df..9ab0709d3e77d396a375a69ea6676a9fc6491b71 100644 (file)
@@ -32,8 +32,8 @@
 #include "pim_iface.h"
 #include "pim_time.h"
 
-struct list *pim_channel_oil_list = NULL;
-struct hash *pim_channel_oil_hash = NULL;
+// struct list *pim_channel_oil_list = NULL;
+// struct hash *pim_channel_oil_hash = NULL;
 
 char *pim_channel_oil_dump(struct channel_oil *c_oil, char *buf, size_t size)
 {
@@ -99,31 +99,36 @@ static unsigned int pim_oil_hash_key(void *arg)
                            oil->oil.mfcc_origin.s_addr, 0);
 }
 
-void pim_oil_init(void)
+void pim_oil_init(struct pim_instance *pim)
 {
-       pim_channel_oil_hash =
-               hash_create_size(8192, pim_oil_hash_key, pim_oil_equal, NULL);
+       char hash_name[64];
 
-       pim_channel_oil_list = list_new();
-       if (!pim_channel_oil_list) {
+       snprintf(hash_name, 64, "PIM %s Oil Hash", pim->vrf->name);
+       pim->channel_oil_hash = hash_create_size(8192,
+                                               pim_oil_hash_key,
+                                               pim_oil_equal,
+                                               hash_name);
+
+       pim->channel_oil_list = list_new();
+       if (!pim->channel_oil_list) {
                zlog_err("%s %s: failure: channel_oil_list=list_new()",
                         __FILE__, __PRETTY_FUNCTION__);
                return;
        }
-       pim_channel_oil_list->del = (void (*)(void *))pim_channel_oil_free;
-       pim_channel_oil_list->cmp =
+       pim->channel_oil_list->del = (void (*)(void *))pim_channel_oil_free;
+       pim->channel_oil_list->cmp =
                (int (*)(void *, void *))pim_channel_oil_compare;
 }
 
-void pim_oil_terminate(void)
+void pim_oil_terminate(struct pim_instance *pim)
 {
-       if (pim_channel_oil_list)
-               list_free(pim_channel_oil_list);
-       pim_channel_oil_list = NULL;
+       if (pim->channel_oil_list)
+               list_delete(pim->channel_oil_list);
+       pim->channel_oil_list = NULL;
 
-       if (pim_channel_oil_hash)
-               hash_free(pim_channel_oil_hash);
-       pim_channel_oil_hash = NULL;
+       if (pim->channel_oil_hash)
+               hash_free(pim->channel_oil_hash);
+       pim->channel_oil_hash = NULL;
 }
 
 void pim_channel_oil_free(struct channel_oil *c_oil)
@@ -131,7 +136,8 @@ void pim_channel_oil_free(struct channel_oil *c_oil)
        XFREE(MTYPE_PIM_CHANNEL_OIL, c_oil);
 }
 
-static struct channel_oil *pim_find_channel_oil(struct prefix_sg *sg)
+static struct channel_oil *pim_find_channel_oil(struct pim_instance *pim,
+                                               struct prefix_sg *sg)
 {
        struct channel_oil *c_oil = NULL;
        struct channel_oil lookup;
@@ -139,18 +145,19 @@ static struct channel_oil *pim_find_channel_oil(struct prefix_sg *sg)
        lookup.oil.mfcc_mcastgrp = sg->grp;
        lookup.oil.mfcc_origin = sg->src;
 
-       c_oil = hash_lookup(pim_channel_oil_hash, &lookup);
+       c_oil = hash_lookup(pim->channel_oil_hash, &lookup);
 
        return c_oil;
 }
 
-struct channel_oil *pim_channel_oil_add(struct prefix_sg *sg,
+struct channel_oil *pim_channel_oil_add(struct pim_instance *pim,
+                                       struct prefix_sg *sg,
                                        int input_vif_index)
 {
        struct channel_oil *c_oil;
        struct interface *ifp;
 
-       c_oil = pim_find_channel_oil(sg);
+       c_oil = pim_find_channel_oil(pim, sg);
        if (c_oil) {
                if (c_oil->oil.mfcc_parent != input_vif_index) {
                        c_oil->oil_inherited_rescan = 1;
@@ -165,11 +172,11 @@ struct channel_oil *pim_channel_oil_add(struct prefix_sg *sg,
                c_oil->oil.mfcc_parent = input_vif_index;
                ++c_oil->oil_ref_count;
                c_oil->up = pim_upstream_find(
-                       sg); // channel might be present prior to upstream
+                       pim, sg); // channel might be present prior to upstream
                return c_oil;
        }
 
-       ifp = pim_if_find_by_vif_index(input_vif_index);
+       ifp = pim_if_find_by_vif_index(pim, input_vif_index);
        if (!ifp) {
                /* warning only */
                zlog_warn(
@@ -186,14 +193,15 @@ struct channel_oil *pim_channel_oil_add(struct prefix_sg *sg,
 
        c_oil->oil.mfcc_mcastgrp = sg->grp;
        c_oil->oil.mfcc_origin = sg->src;
-       c_oil = hash_get(pim_channel_oil_hash, c_oil, hash_alloc_intern);
+       c_oil = hash_get(pim->channel_oil_hash, c_oil, hash_alloc_intern);
 
        c_oil->oil.mfcc_parent = input_vif_index;
        c_oil->oil_ref_count = 1;
        c_oil->installed = 0;
-       c_oil->up = pim_upstream_find(sg);
+       c_oil->up = pim_upstream_find(pim, sg);
+       c_oil->pim = pim;
 
-       listnode_add_sort(pim_channel_oil_list, c_oil);
+       listnode_add_sort(pim->channel_oil_list, c_oil);
 
        return c_oil;
 }
@@ -209,8 +217,8 @@ void pim_channel_oil_del(struct channel_oil *c_oil)
                 * called by list_delete_all_node()
                 */
                c_oil->up = NULL;
-               listnode_delete(pim_channel_oil_list, c_oil);
-               hash_release(pim_channel_oil_hash, c_oil);
+               listnode_delete(c_oil->pim->channel_oil_list, c_oil);
+               hash_release(c_oil->pim->channel_oil_hash, c_oil);
 
                pim_channel_oil_free(c_oil);
        }
index f537062c7a879bbd036ae5b8d852f98facc7a922..1168ba0a8fe9b8a5c3520a4dc00649e3c4027501 100644 (file)
@@ -67,6 +67,8 @@ struct channel_counts {
 */
 
 struct channel_oil {
+       struct pim_instance *pim;
+
        struct mfcctl oil;
        int installed;
        int oil_inherited_rescan;
@@ -80,11 +82,12 @@ struct channel_oil {
 
 extern struct list *pim_channel_oil_list;
 
-void pim_oil_init(void);
-void pim_oil_terminate(void);
+void pim_oil_init(struct pim_instance *pim);
+void pim_oil_terminate(struct pim_instance *pim);
 
 void pim_channel_oil_free(struct channel_oil *c_oil);
-struct channel_oil *pim_channel_oil_add(struct prefix_sg *sg,
+struct channel_oil *pim_channel_oil_add(struct pim_instance *pim,
+                                       struct prefix_sg *sg,
                                        int input_vif_index);
 void pim_channel_oil_del(struct channel_oil *c_oil);
 
index 21892f347767f963c9da4e5fe635d03fb11bed05..ffe5d52a156f052d7183da7c1ee85ba1a2fd454e 100644 (file)
@@ -238,7 +238,7 @@ int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len)
                                         pim_msg_len - PIM_MSG_HEADER_LEN);
                break;
        case PIM_MSG_TYPE_REG_STOP:
-               return pim_register_stop_recv(pim_msg + PIM_MSG_HEADER_LEN,
+               return pim_register_stop_recv(ifp, pim_msg + PIM_MSG_HEADER_LEN,
                                              pim_msg_len - PIM_MSG_HEADER_LEN);
                break;
        case PIM_MSG_TYPE_JOIN_PRUNE:
@@ -286,7 +286,7 @@ static void pim_sock_read_on(struct interface *ifp);
 
 static int pim_sock_read(struct thread *t)
 {
-       struct interface *ifp;
+       struct interface *ifp, *orig_ifp;
        struct pim_interface *pim_ifp;
        int fd;
        struct sockaddr_in from;
@@ -300,7 +300,7 @@ static int pim_sock_read(struct thread *t)
        static long long count = 0;
        int cont = 1;
 
-       ifp = THREAD_ARG(t);
+       orig_ifp = ifp = THREAD_ARG(t);
        fd = THREAD_FD(t);
 
        pim_ifp = ifp->info;
@@ -320,36 +320,20 @@ static int pim_sock_read(struct thread *t)
                        goto done;
                }
 
-#ifdef PIM_CHECK_RECV_IFINDEX_SANITY
-               /* ifindex sanity check */
-               if (ifindex != (int)ifp->ifindex) {
-                       char from_str[INET_ADDRSTRLEN];
-                       char to_str[INET_ADDRSTRLEN];
-                       struct interface *recv_ifp;
-
-                       if (!inet_ntop(AF_INET, &from.sin_addr, from_str,
-                                      sizeof(from_str)))
-                               sprintf(from_str, "<from?>");
-                       if (!inet_ntop(AF_INET, &to.sin_addr, to_str,
-                                      sizeof(to_str)))
-                               sprintf(to_str, "<to?>");
-
-                       recv_ifp = if_lookup_by_index(ifindex, VRF_DEFAULT);
-                       if (recv_ifp) {
-                               zassert(ifindex == (int)recv_ifp->ifindex);
-                       }
-
-#ifdef PIM_REPORT_RECV_IFINDEX_MISMATCH
-                       zlog_warn(
-                               "Interface mismatch: recv PIM pkt from %s to %s on fd=%d: recv_ifindex=%d (%s) sock_ifindex=%d (%s)",
-                               from_str, to_str, fd, ifindex,
-                               recv_ifp ? recv_ifp->name : "<if-notfound>",
-                               ifp->ifindex, ifp->name);
-#endif
+               /*
+                * What?  So with vrf's the incoming packet is received
+                * on the vrf interface but recvfromto above returns
+                * the right ifindex, so just use it.  We know
+                * it's the right interface because we bind to it
+                */
+               ifp = if_lookup_by_index(ifindex, pim_ifp->pim->vrf_id);
+               if (!ifp || !ifp->info) {
+                       if (PIM_DEBUG_PIM_PACKETS)
+                               zlog_debug(
+                                       "%s: Received incoming pim packet on interface not yet configured for pim",
+                                       __PRETTY_FUNCTION__);
                        goto done;
                }
-#endif
-
                int fail = pim_pim_packet(ifp, buf, len);
                if (fail) {
                        if (PIM_DEBUG_PIM_PACKETS)
@@ -366,7 +350,7 @@ static int pim_sock_read(struct thread *t)
        result = 0; /* good */
 
 done:
-       pim_sock_read_on(ifp);
+       pim_sock_read_on(orig_ifp);
 
        if (result) {
                ++pim_ifp->pim_ifstat_hello_recvfail;
@@ -667,13 +651,9 @@ static int hello_send(struct interface *ifp, uint16_t holdtime)
 
 static int pim_hello_send(struct interface *ifp, uint16_t holdtime)
 {
-       struct pim_interface *pim_ifp;
-
-       zassert(ifp);
-       pim_ifp = ifp->info;
-       zassert(pim_ifp);
+       struct pim_interface *pim_ifp = ifp->info;
 
-       if (if_is_loopback(ifp))
+       if (pim_if_is_loopback(pim_ifp->pim, ifp))
                return 0;
 
        if (hello_send(ifp, holdtime)) {
@@ -695,9 +675,7 @@ static void hello_resched(struct interface *ifp)
 {
        struct pim_interface *pim_ifp;
 
-       zassert(ifp);
        pim_ifp = ifp->info;
-       zassert(pim_ifp);
 
        if (PIM_DEBUG_PIM_HELLO) {
                zlog_debug("Rescheduling %d sec hello on interface %s",
@@ -718,7 +696,6 @@ static int on_pim_hello_send(struct thread *t)
        struct interface *ifp;
 
        ifp = THREAD_ARG(t);
-
        pim_ifp = ifp->info;
 
        /*
@@ -745,9 +722,7 @@ void pim_hello_restart_now(struct interface *ifp)
 {
        struct pim_interface *pim_ifp;
 
-       zassert(ifp);
        pim_ifp = ifp->info;
-       zassert(pim_ifp);
 
        /*
         * Reset next hello timer
@@ -775,9 +750,13 @@ void pim_hello_restart_triggered(struct interface *ifp)
        int triggered_hello_delay_msec;
        int random_msec;
 
-       zassert(ifp);
        pim_ifp = ifp->info;
-       zassert(pim_ifp);
+
+       /*
+        * No need to ever start loopback or vrf device hello's
+        */
+       if (pim_if_is_loopback(pim_ifp->pim, ifp))
+               return;
 
        /*
         * There exists situations where we have the a RPF out this
index 1cbe1dcf7ff00e78ccf866ccc639f838a36f6ed3..a393d0bbda8bacb4256d950e0f263145b8e41806 100644 (file)
@@ -48,14 +48,16 @@ struct thread *send_test_packet_timer = NULL;
 
 void pim_register_join(struct pim_upstream *up)
 {
-       if (pim_is_grp_ssm(up->sg.grp)) {
+       struct pim_instance *pim = up->channel_oil->pim;
+
+       if (pim_is_grp_ssm(pim, up->sg.grp)) {
                if (PIM_DEBUG_PIM_EVENTS)
                        zlog_debug("%s register setup skipped as group is SSM",
                                   up->sg_str);
                return;
        }
 
-       pim_channel_add_oif(up->channel_oil, pim_regiface,
+       pim_channel_add_oif(up->channel_oil, pim->regiface,
                            PIM_OIF_FLAG_PROTO_PIM);
        up->reg_state = PIM_REG_JOIN;
 }
@@ -109,8 +111,10 @@ void pim_register_stop_send(struct interface *ifp, struct prefix_sg *sg,
        ++pinfo->pim_ifstat_reg_stop_send;
 }
 
-int pim_register_stop_recv(uint8_t *buf, int buf_size)
+int pim_register_stop_recv(struct interface *ifp, uint8_t *buf, int buf_size)
 {
+       struct pim_interface *pim_ifp = ifp->info;
+       struct pim_instance *pim = pim_ifp->pim;
        struct pim_upstream *upstream = NULL;
        struct prefix source;
        struct prefix_sg sg;
@@ -123,7 +127,7 @@ int pim_register_stop_recv(uint8_t *buf, int buf_size)
        pim_parse_addr_ucast(&source, buf, buf_size);
        sg.src = source.u.prefix4;
 
-       upstream = pim_upstream_find(&sg);
+       upstream = pim_upstream_find(pim, &sg);
        if (!upstream) {
                return 0;
        }
@@ -138,7 +142,7 @@ int pim_register_stop_recv(uint8_t *buf, int buf_size)
                break;
        case PIM_REG_JOIN:
                upstream->reg_state = PIM_REG_PRUNE;
-               pim_channel_del_oif(upstream->channel_oil, pim_regiface,
+               pim_channel_del_oif(upstream->channel_oil, pim->regiface,
                                    PIM_OIF_FLAG_PROTO_PIM);
                pim_upstream_start_register_stop_timer(upstream, 0);
                break;
@@ -270,10 +274,13 @@ int pim_register_recv(struct interface *ifp, struct in_addr dest_addr,
        int i_am_rp = 0;
        struct pim_interface *pim_ifp = NULL;
 
+       pim_ifp = ifp->info;
+
 #define PIM_MSG_REGISTER_BIT_RESERVED_LEN 4
        ip_hdr = (struct ip *)(tlv_buf + PIM_MSG_REGISTER_BIT_RESERVED_LEN);
 
-       if (!pim_rp_check_is_my_ip_address(ip_hdr->ip_dst, dest_addr)) {
+       if (!pim_rp_check_is_my_ip_address(pim_ifp->pim, ip_hdr->ip_dst,
+                                          dest_addr)) {
                if (PIM_DEBUG_PIM_REG) {
                        char dest[INET_ADDRSTRLEN];
 
@@ -285,8 +292,6 @@ int pim_register_recv(struct interface *ifp, struct in_addr dest_addr,
                return 0;
        }
 
-       pim_ifp = ifp->info;
-       zassert(pim_ifp);
        ++pim_ifp->pim_ifstat_reg_recv;
 
        /*
@@ -319,7 +324,7 @@ int pim_register_recv(struct interface *ifp, struct in_addr dest_addr,
        sg.src = ip_hdr->ip_src;
        sg.grp = ip_hdr->ip_dst;
 
-       i_am_rp = I_am_RP(sg.grp);
+       i_am_rp = I_am_RP(pim_ifp->pim, sg.grp);
 
        if (PIM_DEBUG_PIM_REG) {
                char src_str[INET_ADDRSTRLEN];
@@ -330,8 +335,9 @@ int pim_register_recv(struct interface *ifp, struct in_addr dest_addr,
                        pim_str_sg_dump(&sg), src_str, ifp->name, i_am_rp);
        }
 
-       if (i_am_rp && (dest_addr.s_addr
-                       == ((RP(sg.grp))->rpf_addr.u.prefix4.s_addr))) {
+       if (i_am_rp
+           && (dest_addr.s_addr
+               == ((RP(pim_ifp->pim, sg.grp))->rpf_addr.u.prefix4.s_addr))) {
                sentRegisterStop = 0;
 
                if (*bits & PIM_REGISTER_BORDER_BIT) {
@@ -355,25 +361,50 @@ int pim_register_recv(struct interface *ifp, struct in_addr dest_addr,
                        }
                }
 
-               struct pim_upstream *upstream = pim_upstream_find(&sg);
+               struct pim_upstream *upstream =
+                       pim_upstream_find(pim_ifp->pim, &sg);
                /*
                 * If we don't have a place to send ignore the packet
                 */
                if (!upstream) {
                        upstream = pim_upstream_add(
-                               &sg, ifp, PIM_UPSTREAM_FLAG_MASK_SRC_STREAM,
-                               __PRETTY_FUNCTION__);
+                               pim_ifp->pim, &sg, ifp,
+                               PIM_UPSTREAM_FLAG_MASK_SRC_STREAM,
+                               __PRETTY_FUNCTION__, NULL);
                        if (!upstream) {
                                zlog_warn("Failure to create upstream state");
                                return 1;
                        }
 
                        upstream->upstream_register = src_addr;
+               } else {
+                       /*
+                        * If the FHR has set a very very fast register timer
+                        * there exists a possibility that the incoming NULL
+                        * register
+                        * is happening before we set the spt bit.  If so
+                        * Do a quick check to update the counters and
+                        * then set the spt bit as appropriate
+                        */
+                       if (upstream->sptbit != PIM_UPSTREAM_SPTBIT_TRUE) {
+                               pim_mroute_update_counters(
+                                       upstream->channel_oil);
+                               /*
+                                * Have we seen packets?
+                                */
+                               if (upstream->channel_oil->cc.oldpktcnt
+                                   < upstream->channel_oil->cc.pktcnt)
+                                       pim_upstream_set_sptbit(
+                                               upstream,
+                                               upstream->rpf.source_nexthop
+                                                       .interface);
+                       }
                }
 
                if ((upstream->sptbit == PIM_UPSTREAM_SPTBIT_TRUE)
-                   || ((SwitchToSptDesired(&sg))
-                       && pim_upstream_inherited_olist(upstream) == 0)) {
+                   || ((SwitchToSptDesired(pim_ifp->pim, &sg))
+                       && pim_upstream_inherited_olist(pim_ifp->pim, upstream)
+                                  == 0)) {
                        // pim_scan_individual_oil (upstream->channel_oil);
                        pim_register_stop_send(ifp, &sg, dest_addr, src_addr);
                        sentRegisterStop = 1;
@@ -383,13 +414,13 @@ int pim_register_recv(struct interface *ifp, struct in_addr dest_addr,
                                           upstream->sptbit);
                }
                if ((upstream->sptbit == PIM_UPSTREAM_SPTBIT_TRUE)
-                   || (SwitchToSptDesired(&sg))) {
+                   || (SwitchToSptDesired(pim_ifp->pim, &sg))) {
                        if (sentRegisterStop) {
                                pim_upstream_keep_alive_timer_start(
-                                       upstream, qpim_rp_keep_alive_time);
+                                       upstream, pim_ifp->pim->rp_keep_alive_time);
                        } else {
                                pim_upstream_keep_alive_timer_start(
-                                       upstream, qpim_keep_alive_time);
+                                       upstream, pim_ifp->pim->keep_alive_time);
                        }
                }
 
index ad3deb2b246439e708f1bbd0f3b2df2a028eca81..906d093bb76ba575562750403c205f616d4e50f4 100644 (file)
@@ -30,7 +30,7 @@
 #define PIM_MSG_REGISTER_LEN   (8)
 #define PIM_MSG_REGISTER_STOP_LEN (4)
 
-int pim_register_stop_recv(uint8_t *buf, int buf_size);
+int pim_register_stop_recv(struct interface *ifp, uint8_t *buf, int buf_size);
 
 int pim_register_recv(struct interface *ifp, struct in_addr dest_addr,
                      struct in_addr src_addr, uint8_t *tlv_buf,
index 2fe0143a87ef23443e0af6da7202babd9fa9bd8e..05592992a9515df25a56e794df8566cc45f8282e 100644 (file)
 #include "pim_nht.h"
 
 
-static struct list *qpim_rp_list = NULL;
-static struct rp_info *tail = NULL;
+/* Cleanup pim->rpf_hash each node data */
+void pim_rp_list_hash_clean(void *data)
+{
+       struct pim_nexthop_cache *pnc = (struct pim_nexthop_cache *)data;
+
+       list_delete(pnc->rp_list);
+       pnc->rp_list = NULL;
+
+       hash_clean(pnc->upstream_hash, NULL);
+       hash_free(pnc->upstream_hash);
+       pnc->upstream_hash = NULL;
+
+       XFREE(MTYPE_PIM_NEXTHOP_CACHE, pnc);
+}
 
 static void pim_rp_info_free(struct rp_info *rp_info)
 {
@@ -81,46 +93,49 @@ int pim_rp_list_cmp(void *v1, void *v2)
        return 0;
 }
 
-void pim_rp_init(void)
+void pim_rp_init(struct pim_instance *pim)
 {
        struct rp_info *rp_info;
 
-       qpim_rp_list = list_new();
-       qpim_rp_list->del = (void (*)(void *))pim_rp_info_free;
-       qpim_rp_list->cmp = pim_rp_list_cmp;
+       pim->rp_list = list_new();
+       pim->rp_list->del = (void (*)(void *))pim_rp_info_free;
+       pim->rp_list->cmp = pim_rp_list_cmp;
 
        rp_info = XCALLOC(MTYPE_PIM_RP, sizeof(*rp_info));
 
        if (!rp_info)
                return;
 
-       str2prefix("224.0.0.0/4", &rp_info->group);
+       if (!str2prefix("224.0.0.0/4", &rp_info->group)) {
+               XFREE(MTYPE_PIM_RP, rp_info);
+               return;
+       }
        rp_info->group.family = AF_INET;
        rp_info->rp.rpf_addr.family = AF_INET;
        rp_info->rp.rpf_addr.prefixlen = IPV4_MAX_PREFIXLEN;
        rp_info->rp.rpf_addr.u.prefix4.s_addr = INADDR_NONE;
-       tail = rp_info;
 
-       listnode_add(qpim_rp_list, rp_info);
+       listnode_add(pim->rp_list, rp_info);
 }
 
-void pim_rp_free(void)
+void pim_rp_free(struct pim_instance *pim)
 {
-       if (qpim_rp_list)
-               list_delete(qpim_rp_list);
-       qpim_rp_list = NULL;
+       if (pim->rp_list)
+               list_delete(pim->rp_list);
+       pim->rp_list = NULL;
 }
 
 /*
  * Given an RP's prefix-list, return the RP's rp_info for that prefix-list
  */
-static struct rp_info *pim_rp_find_prefix_list(struct in_addr rp,
+static struct rp_info *pim_rp_find_prefix_list(struct pim_instance *pim,
+                                              struct in_addr rp,
                                               const char *plist)
 {
        struct listnode *node;
        struct rp_info *rp_info;
 
-       for (ALL_LIST_ELEMENTS_RO(qpim_rp_list, node, rp_info)) {
+       for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) {
                if (rp.s_addr == rp_info->rp.rpf_addr.u.prefix4.s_addr
                    && rp_info->plist && strcmp(rp_info->plist, plist) == 0) {
                        return rp_info;
@@ -133,12 +148,12 @@ static struct rp_info *pim_rp_find_prefix_list(struct in_addr rp,
 /*
  * Return true if plist is used by any rp_info
  */
-static int pim_rp_prefix_list_used(const char *plist)
+static int pim_rp_prefix_list_used(struct pim_instance *pim, const char *plist)
 {
        struct listnode *node;
        struct rp_info *rp_info;
 
-       for (ALL_LIST_ELEMENTS_RO(qpim_rp_list, node, rp_info)) {
+       for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) {
                if (rp_info->plist && strcmp(rp_info->plist, plist) == 0) {
                        return 1;
                }
@@ -151,13 +166,14 @@ static int pim_rp_prefix_list_used(const char *plist)
  * Given an RP's address, return the RP's rp_info that is an exact match for
  * 'group'
  */
-static struct rp_info *pim_rp_find_exact(struct in_addr rp,
+static struct rp_info *pim_rp_find_exact(struct pim_instance *pim,
+                                        struct in_addr rp,
                                         struct prefix *group)
 {
        struct listnode *node;
        struct rp_info *rp_info;
 
-       for (ALL_LIST_ELEMENTS_RO(qpim_rp_list, node, rp_info)) {
+       for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) {
                if (rp.s_addr == rp_info->rp.rpf_addr.u.prefix4.s_addr
                    && prefix_same(&rp_info->group, group))
                        return rp_info;
@@ -169,13 +185,14 @@ static struct rp_info *pim_rp_find_exact(struct in_addr rp,
 /*
  * Given a group, return the rp_info for that group
  */
-static struct rp_info *pim_rp_find_match_group(struct prefix *group)
+static struct rp_info *pim_rp_find_match_group(struct pim_instance *pim,
+                                              struct prefix *group)
 {
        struct listnode *node;
        struct rp_info *rp_info;
        struct prefix_list *plist;
 
-       for (ALL_LIST_ELEMENTS_RO(qpim_rp_list, node, rp_info)) {
+       for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) {
                if (rp_info->plist) {
                        plist = prefix_list_lookup(AFI_IP, rp_info->plist);
 
@@ -198,18 +215,19 @@ static struct rp_info *pim_rp_find_match_group(struct prefix *group)
  *
  * This is a placeholder function for now.
  */
-static void pim_rp_refresh_group_to_rp_mapping()
+static void pim_rp_refresh_group_to_rp_mapping(struct pim_instance *pim)
 {
-       pim_msdp_i_am_rp_changed();
+       pim_msdp_i_am_rp_changed(pim);
 }
 
-void pim_rp_prefix_list_update(struct prefix_list *plist)
+void pim_rp_prefix_list_update(struct pim_instance *pim,
+                              struct prefix_list *plist)
 {
        struct listnode *node;
        struct rp_info *rp_info;
        int refresh_needed = 0;
 
-       for (ALL_LIST_ELEMENTS_RO(qpim_rp_list, node, rp_info)) {
+       for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) {
                if (rp_info->plist
                    && strcmp(rp_info->plist, prefix_list_name(plist)) == 0) {
                        refresh_needed = 1;
@@ -218,7 +236,7 @@ void pim_rp_prefix_list_update(struct prefix_list *plist)
        }
 
        if (refresh_needed)
-               pim_rp_refresh_group_to_rp_mapping();
+               pim_rp_refresh_group_to_rp_mapping(pim);
 }
 
 static int pim_rp_check_interface_addrs(struct rp_info *rp_info,
@@ -244,13 +262,14 @@ static int pim_rp_check_interface_addrs(struct rp_info *rp_info,
        return 0;
 }
 
-static void pim_rp_check_interfaces(struct rp_info *rp_info)
+static void pim_rp_check_interfaces(struct pim_instance *pim,
+                                   struct rp_info *rp_info)
 {
        struct listnode *node;
        struct interface *ifp;
 
        rp_info->i_am_rp = 0;
-       for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT), node, ifp)) {
+       for (ALL_LIST_ELEMENTS_RO(vrf_iflist(pim->vrf_id), node, ifp)) {
                struct pim_interface *pim_ifp = ifp->info;
 
                if (!pim_ifp)
@@ -262,7 +281,8 @@ static void pim_rp_check_interfaces(struct rp_info *rp_info)
        }
 }
 
-int pim_rp_new(const char *rp, const char *group_range, const char *plist)
+int pim_rp_new(struct pim_instance *pim, const char *rp,
+              const char *group_range, const char *plist)
 {
        int result = 0;
        struct rp_info *rp_info;
@@ -302,7 +322,7 @@ int pim_rp_new(const char *rp, const char *group_range, const char *plist)
                /*
                 * Return if the prefix-list is already configured for this RP
                 */
-               if (pim_rp_find_prefix_list(rp_info->rp.rpf_addr.u.prefix4,
+               if (pim_rp_find_prefix_list(pim, rp_info->rp.rpf_addr.u.prefix4,
                                            plist)) {
                        XFREE(MTYPE_PIM_RP, rp_info);
                        return PIM_SUCCESS;
@@ -311,7 +331,7 @@ int pim_rp_new(const char *rp, const char *group_range, const char *plist)
                /*
                 * Barf if the prefix-list is already configured for an RP
                 */
-               if (pim_rp_prefix_list_used(plist)) {
+               if (pim_rp_prefix_list_used(pim, plist)) {
                        XFREE(MTYPE_PIM_RP, rp_info);
                        return PIM_RP_PFXLIST_IN_USE;
                }
@@ -319,16 +339,16 @@ int pim_rp_new(const char *rp, const char *group_range, const char *plist)
                /*
                 * Free any existing rp_info entries for this RP
                 */
-               for (ALL_LIST_ELEMENTS(qpim_rp_list, node, nnode,
+               for (ALL_LIST_ELEMENTS(pim->rp_list, node, nnode,
                                       tmp_rp_info)) {
                        if (rp_info->rp.rpf_addr.u.prefix4.s_addr
                            == tmp_rp_info->rp.rpf_addr.u.prefix4.s_addr) {
                                if (tmp_rp_info->plist)
-                                       pim_rp_del(rp, NULL,
+                                       pim_rp_del(pim, rp, NULL,
                                                   tmp_rp_info->plist);
                                else
                                        pim_rp_del(
-                                               rp,
+                                               pim, rp,
                                                prefix2str(&tmp_rp_info->group,
                                                           buffer, BUFSIZ),
                                                NULL);
@@ -337,8 +357,11 @@ int pim_rp_new(const char *rp, const char *group_range, const char *plist)
 
                rp_info->plist = XSTRDUP(MTYPE_PIM_FILTER_NAME, plist);
        } else {
-               str2prefix("224.0.0.0/4", &group_all);
-               rp_all = pim_rp_find_match_group(&group_all);
+               if (!str2prefix("224.0.0.0/4", &group_all)) {
+                       XFREE(MTYPE_PIM_RP, rp_info);
+                       return PIM_GROUP_BAD_ADDRESS;
+               }
+               rp_all = pim_rp_find_match_group(pim, &group_all);
 
                /*
                 * Barf if group is a non-multicast subnet
@@ -351,13 +374,13 @@ int pim_rp_new(const char *rp, const char *group_range, const char *plist)
                /*
                 * Remove any prefix-list rp_info entries for this RP
                 */
-               for (ALL_LIST_ELEMENTS(qpim_rp_list, node, nnode,
+               for (ALL_LIST_ELEMENTS(pim->rp_list, node, nnode,
                                       tmp_rp_info)) {
                        if (tmp_rp_info->plist
                            && rp_info->rp.rpf_addr.u.prefix4.s_addr
                                       == tmp_rp_info->rp.rpf_addr.u.prefix4
                                                  .s_addr) {
-                               pim_rp_del(rp, NULL, tmp_rp_info->plist);
+                               pim_rp_del(pim, rp, NULL, tmp_rp_info->plist);
                        }
                }
 
@@ -384,31 +407,29 @@ int pim_rp_new(const char *rp, const char *group_range, const char *plist)
                                        __PRETTY_FUNCTION__, buf, buf1);
                        }
                        memset(&pnc, 0, sizeof(struct pim_nexthop_cache));
-                       if ((pim_find_or_track_nexthop(&nht_p, NULL, rp_all,
-                                                      &pnc))
-                           == 1) {
-                               // Compute PIM RPF using Cached nexthop
-                               if ((pim_ecmp_nexthop_search(
-                                           &pnc, &rp_all->rp.source_nexthop,
-                                           &nht_p, &rp_all->group, 1))
-                                   != 0)
+                       if (pim_find_or_track_nexthop(pim, &nht_p, NULL, rp_all,
+                                                     &pnc)) {
+                               if (!pim_ecmp_nexthop_search(
+                                           pim, &pnc,
+                                           &rp_all->rp.source_nexthop, &nht_p,
+                                           &rp_all->group, 1))
                                        return PIM_RP_NO_PATH;
                        } else {
                                if (pim_nexthop_lookup(
-                                           &rp_all->rp.source_nexthop,
+                                           pim, &rp_all->rp.source_nexthop,
                                            rp_all->rp.rpf_addr.u.prefix4, 1)
                                    != 0)
                                        return PIM_RP_NO_PATH;
                        }
-                       pim_rp_check_interfaces(rp_all);
-                       pim_rp_refresh_group_to_rp_mapping();
+                       pim_rp_check_interfaces(pim, rp_all);
+                       pim_rp_refresh_group_to_rp_mapping(pim);
                        return PIM_SUCCESS;
                }
 
                /*
                 * Return if the group is already configured for this RP
                 */
-               if (pim_rp_find_exact(rp_info->rp.rpf_addr.u.prefix4,
+               if (pim_rp_find_exact(pim, rp_info->rp.rpf_addr.u.prefix4,
                                      &rp_info->group)) {
                        XFREE(MTYPE_PIM_RP, rp_info);
                        return PIM_SUCCESS;
@@ -417,7 +438,7 @@ int pim_rp_new(const char *rp, const char *group_range, const char *plist)
                /*
                 * Barf if this group is already covered by some other RP
                 */
-               tmp_rp_info = pim_rp_find_match_group(&rp_info->group);
+               tmp_rp_info = pim_rp_find_match_group(pim, &rp_info->group);
 
                if (tmp_rp_info) {
                        if (tmp_rp_info->plist) {
@@ -440,7 +461,7 @@ int pim_rp_new(const char *rp, const char *group_range, const char *plist)
                }
        }
 
-       listnode_add_sort(qpim_rp_list, rp_info);
+       listnode_add_sort(pim->rp_list, rp_info);
 
        /* Register addr with Zebra NHT */
        nht_p.family = AF_INET;
@@ -456,25 +477,25 @@ int pim_rp_new(const char *rp, const char *group_range, const char *plist)
        }
 
        memset(&pnc, 0, sizeof(struct pim_nexthop_cache));
-       if ((pim_find_or_track_nexthop(&nht_p, NULL, rp_info, &pnc)) == 1) {
-               // Compute PIM RPF using Cached nexthop
-               if (pim_ecmp_nexthop_search(&pnc, &rp_info->rp.source_nexthop,
-                                           &nht_p, &rp_info->group, 1)
-                   != 0)
+       if (pim_find_or_track_nexthop(pim, &nht_p, NULL, rp_info, &pnc)) {
+               if (!pim_ecmp_nexthop_search(pim, &pnc,
+                                            &rp_info->rp.source_nexthop,
+                                            &nht_p, &rp_info->group, 1))
                        return PIM_RP_NO_PATH;
        } else {
-               if (pim_nexthop_lookup(&rp_info->rp.source_nexthop,
+               if (pim_nexthop_lookup(pim, &rp_info->rp.source_nexthop,
                                       rp_info->rp.rpf_addr.u.prefix4, 1)
                    != 0)
                        return PIM_RP_NO_PATH;
        }
 
-       pim_rp_check_interfaces(rp_info);
-       pim_rp_refresh_group_to_rp_mapping();
+       pim_rp_check_interfaces(pim, rp_info);
+       pim_rp_refresh_group_to_rp_mapping(pim);
        return PIM_SUCCESS;
 }
 
-int pim_rp_del(const char *rp, const char *group_range, const char *plist)
+int pim_rp_del(struct pim_instance *pim, const char *rp,
+              const char *group_range, const char *plist)
 {
        struct prefix group;
        struct in_addr rp_addr;
@@ -497,9 +518,9 @@ int pim_rp_del(const char *rp, const char *group_range, const char *plist)
                return PIM_RP_BAD_ADDRESS;
 
        if (plist)
-               rp_info = pim_rp_find_prefix_list(rp_addr, plist);
+               rp_info = pim_rp_find_prefix_list(pim, rp_addr, plist);
        else
-               rp_info = pim_rp_find_exact(rp_addr, &group);
+               rp_info = pim_rp_find_exact(pim, rp_addr, &group);
 
        if (!rp_info)
                return PIM_RP_NOT_FOUND;
@@ -519,10 +540,10 @@ int pim_rp_del(const char *rp, const char *group_range, const char *plist)
                zlog_debug("%s: Deregister RP addr %s with Zebra ",
                           __PRETTY_FUNCTION__, buf);
        }
-       pim_delete_tracked_nexthop(&nht_p, NULL, rp_info);
+       pim_delete_tracked_nexthop(pim, &nht_p, NULL, rp_info);
 
        str2prefix("224.0.0.0/4", &g_all);
-       rp_all = pim_rp_find_match_group(&g_all);
+       rp_all = pim_rp_find_match_group(pim, &g_all);
 
        if (rp_all == rp_info) {
                rp_all->rp.rpf_addr.family = AF_INET;
@@ -531,20 +552,19 @@ int pim_rp_del(const char *rp, const char *group_range, const char *plist)
                return PIM_SUCCESS;
        }
 
-       listnode_delete(qpim_rp_list, rp_info);
-       pim_rp_refresh_group_to_rp_mapping();
+       listnode_delete(pim->rp_list, rp_info);
+       pim_rp_refresh_group_to_rp_mapping(pim);
        return PIM_SUCCESS;
 }
 
-int pim_rp_setup(void)
+void pim_rp_setup(struct pim_instance *pim)
 {
        struct listnode *node;
        struct rp_info *rp_info;
-       int ret = 0;
        struct prefix nht_p;
        struct pim_nexthop_cache pnc;
 
-       for (ALL_LIST_ELEMENTS_RO(qpim_rp_list, node, rp_info)) {
+       for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) {
                if (rp_info->rp.rpf_addr.u.prefix4.s_addr == INADDR_NONE)
                        continue;
 
@@ -552,15 +572,11 @@ int pim_rp_setup(void)
                nht_p.prefixlen = IPV4_MAX_BITLEN;
                nht_p.u.prefix4 = rp_info->rp.rpf_addr.u.prefix4;
                memset(&pnc, 0, sizeof(struct pim_nexthop_cache));
-               if ((pim_find_or_track_nexthop(&nht_p, NULL, rp_info, &pnc))
-                   == 1) {
-                       // Compute PIM RPF using Cached nexthop
-                       if ((pim_ecmp_nexthop_search(
-                                   &pnc, &rp_info->rp.source_nexthop, &nht_p,
-                                   &rp_info->group, 1))
-                           != 0)
-                               ret++;
-               } else {
+               if (pim_find_or_track_nexthop(pim, &nht_p, NULL, rp_info, &pnc))
+                       pim_ecmp_nexthop_search(pim, &pnc,
+                                               &rp_info->rp.source_nexthop,
+                                               &nht_p, &rp_info->group, 1);
+               else {
                        if (PIM_DEBUG_ZEBRA) {
                                char buf[PREFIX2STR_BUFFER];
                                prefix2str(&nht_p, buf, sizeof(buf));
@@ -568,22 +584,14 @@ int pim_rp_setup(void)
                                        "%s: NHT Local Nexthop not found for RP %s ",
                                        __PRETTY_FUNCTION__, buf);
                        }
-                       if (pim_nexthop_lookup(&rp_info->rp.source_nexthop,
-                                              rp_info->rp.rpf_addr.u.prefix4,
-                                              1)
-                           != 0) {
+                       if (!pim_nexthop_lookup(
+                                   pim, &rp_info->rp.source_nexthop,
+                                   rp_info->rp.rpf_addr.u.prefix4, 1))
                                if (PIM_DEBUG_PIM_TRACE)
                                        zlog_debug(
                                                "Unable to lookup nexthop for rp specified");
-                               ret++;
-                       }
                }
        }
-
-       if (ret)
-               return 0;
-
-       return 1;
 }
 
 /*
@@ -595,11 +603,12 @@ void pim_rp_check_on_if_add(struct pim_interface *pim_ifp)
        struct listnode *node;
        struct rp_info *rp_info;
        bool i_am_rp_changed = false;
+       struct pim_instance *pim = pim_ifp->pim;
 
-       if (qpim_rp_list == NULL)
+       if (pim->rp_list == NULL)
                return;
 
-       for (ALL_LIST_ELEMENTS_RO(qpim_rp_list, node, rp_info)) {
+       for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) {
                if (pim_rpf_addr_is_inaddr_none(&rp_info->rp))
                        continue;
 
@@ -623,29 +632,29 @@ void pim_rp_check_on_if_add(struct pim_interface *pim_ifp)
        }
 
        if (i_am_rp_changed) {
-               pim_msdp_i_am_rp_changed();
+               pim_msdp_i_am_rp_changed(pim);
        }
 }
 
 /* up-optimized re-evaluation of "i_am_rp". this is used when ifaddresses
  * are removed. Removing numbers is an uncommon event in an active network
  * so I have made no attempt to optimize it. */
-void pim_i_am_rp_re_evaluate(void)
+void pim_i_am_rp_re_evaluate(struct pim_instance *pim)
 {
        struct listnode *node;
        struct rp_info *rp_info;
        bool i_am_rp_changed = false;
        int old_i_am_rp;
 
-       if (qpim_rp_list == NULL)
+       if (pim->rp_list == NULL)
                return;
 
-       for (ALL_LIST_ELEMENTS_RO(qpim_rp_list, node, rp_info)) {
+       for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) {
                if (pim_rpf_addr_is_inaddr_none(&rp_info->rp))
                        continue;
 
                old_i_am_rp = rp_info->i_am_rp;
-               pim_rp_check_interfaces(rp_info);
+               pim_rp_check_interfaces(pim, rp_info);
 
                if (old_i_am_rp != rp_info->i_am_rp) {
                        i_am_rp_changed = true;
@@ -665,7 +674,7 @@ void pim_i_am_rp_re_evaluate(void)
        }
 
        if (i_am_rp_changed) {
-               pim_msdp_i_am_rp_changed();
+               pim_msdp_i_am_rp_changed(pim);
        }
 }
 
@@ -675,7 +684,7 @@ void pim_i_am_rp_re_evaluate(void)
  *
  * Since we only have static RP, all groups are part of this RP
  */
-int pim_rp_i_am_rp(struct in_addr group)
+int pim_rp_i_am_rp(struct pim_instance *pim, struct in_addr group)
 {
        struct prefix g;
        struct rp_info *rp_info;
@@ -685,7 +694,7 @@ int pim_rp_i_am_rp(struct in_addr group)
        g.prefixlen = 32;
        g.u.prefix4 = group;
 
-       rp_info = pim_rp_find_match_group(&g);
+       rp_info = pim_rp_find_match_group(pim, &g);
 
        if (rp_info)
                return rp_info->i_am_rp;
@@ -698,7 +707,7 @@ int pim_rp_i_am_rp(struct in_addr group)
  *
  * Return the RP that the Group belongs too.
  */
-struct pim_rpf *pim_rp_g(struct in_addr group)
+struct pim_rpf *pim_rp_g(struct pim_instance *pim, struct in_addr group)
 {
        struct prefix g;
        struct rp_info *rp_info;
@@ -708,7 +717,7 @@ struct pim_rpf *pim_rp_g(struct in_addr group)
        g.prefixlen = 32;
        g.u.prefix4 = group;
 
-       rp_info = pim_rp_find_match_group(&g);
+       rp_info = pim_rp_find_match_group(pim, &g);
 
        if (rp_info) {
                struct prefix nht_p;
@@ -727,13 +736,11 @@ struct pim_rpf *pim_rp_g(struct in_addr group)
                                __PRETTY_FUNCTION__, buf, buf1);
                }
                memset(&pnc, 0, sizeof(struct pim_nexthop_cache));
-               if ((pim_find_or_track_nexthop(&nht_p, NULL, rp_info, &pnc))
-                   == 1) {
-                       // Compute PIM RPF using Cached nexthop
-                       pim_ecmp_nexthop_search(&pnc,
+               if (pim_find_or_track_nexthop(pim, &nht_p, NULL, rp_info, &pnc))
+                       pim_ecmp_nexthop_search(pim, &pnc,
                                                &rp_info->rp.source_nexthop,
                                                &nht_p, &rp_info->group, 1);
-               else {
+               else {
                        if (PIM_DEBUG_ZEBRA) {
                                char buf[PREFIX2STR_BUFFER];
                                char buf1[PREFIX2STR_BUFFER];
@@ -744,7 +751,7 @@ struct pim_rpf *pim_rp_g(struct in_addr group)
                                        __PRETTY_FUNCTION__, buf, buf1);
                        }
                        pim_rpf_set_refresh_time();
-                       pim_nexthop_lookup(&rp_info->rp.source_nexthop,
+                       pim_nexthop_lookup(pim, &rp_info->rp.source_nexthop,
                                           rp_info->rp.rpf_addr.u.prefix4, 1);
                }
                return (&rp_info->rp);
@@ -762,8 +769,8 @@ struct pim_rpf *pim_rp_g(struct in_addr group)
  * then return failure.
  *
  */
-int pim_rp_set_upstream_addr(struct in_addr *up, struct in_addr source,
-                            struct in_addr group)
+int pim_rp_set_upstream_addr(struct pim_instance *pim, struct in_addr *up,
+                            struct in_addr source, struct in_addr group)
 {
        struct rp_info *rp_info;
        struct prefix g;
@@ -773,7 +780,7 @@ int pim_rp_set_upstream_addr(struct in_addr *up, struct in_addr source,
        g.prefixlen = 32;
        g.u.prefix4 = group;
 
-       rp_info = pim_rp_find_match_group(&g);
+       rp_info = pim_rp_find_match_group(pim, &g);
 
        if ((pim_rpf_addr_is_inaddr_none(&rp_info->rp))
            && (source.s_addr == INADDR_ANY)) {
@@ -789,7 +796,8 @@ int pim_rp_set_upstream_addr(struct in_addr *up, struct in_addr source,
        return 1;
 }
 
-int pim_rp_config_write(struct vty *vty)
+int pim_rp_config_write(struct pim_instance *pim, struct vty *vty,
+                       const char *spaces)
 {
        struct listnode *node;
        struct rp_info *rp_info;
@@ -797,18 +805,18 @@ int pim_rp_config_write(struct vty *vty)
        char group_buffer[32];
        int count = 0;
 
-       for (ALL_LIST_ELEMENTS_RO(qpim_rp_list, node, rp_info)) {
+       for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) {
                if (pim_rpf_addr_is_inaddr_none(&rp_info->rp))
                        continue;
 
                if (rp_info->plist)
-                       vty_out(vty, "ip pim rp %s prefix-list %s\n",
+                       vty_out(vty, "%sip pim rp %s prefix-list %s\n", spaces,
                                inet_ntop(AF_INET,
                                          &rp_info->rp.rpf_addr.u.prefix4,
                                          rp_buffer, 32),
                                rp_info->plist);
                else
-                       vty_out(vty, "ip pim rp %s %s\n",
+                       vty_out(vty, "%sip pim rp %s %s\n", spaces,
                                inet_ntop(AF_INET,
                                          &rp_info->rp.rpf_addr.u.prefix4,
                                          rp_buffer, 32),
@@ -819,7 +827,8 @@ int pim_rp_config_write(struct vty *vty)
        return count;
 }
 
-int pim_rp_check_is_my_ip_address(struct in_addr group,
+int pim_rp_check_is_my_ip_address(struct pim_instance *pim,
+                                 struct in_addr group,
                                  struct in_addr dest_addr)
 {
        struct rp_info *rp_info;
@@ -830,25 +839,26 @@ int pim_rp_check_is_my_ip_address(struct in_addr group,
        g.prefixlen = 32;
        g.u.prefix4 = group;
 
-       rp_info = pim_rp_find_match_group(&g);
+       rp_info = pim_rp_find_match_group(pim, &g);
        /*
         * See if we can short-cut some?
         * This might not make sense if we ever leave a static RP
         * type of configuration.
         * Note - Premature optimization might bite our patooeys' here.
         */
-       if (I_am_RP(group)) {
+       if (I_am_RP(pim, group)) {
                if (dest_addr.s_addr == rp_info->rp.rpf_addr.u.prefix4.s_addr)
                        return 1;
        }
 
-       if (if_lookup_exact_address(&dest_addr, AF_INET, VRF_DEFAULT))
+       if (if_lookup_exact_address(&dest_addr, AF_INET, pim->vrf_id))
                return 1;
 
        return 0;
 }
 
-void pim_rp_show_information(struct vty *vty, u_char uj)
+void pim_rp_show_information(struct pim_instance *pim, struct vty *vty,
+                            u_char uj)
 {
        struct rp_info *rp_info;
        struct rp_info *prev_rp_info = NULL;
@@ -864,7 +874,7 @@ void pim_rp_show_information(struct vty *vty, u_char uj)
                vty_out(vty,
                        "RP address       group/prefix-list   OIF         I am RP\n");
 
-       for (ALL_LIST_ELEMENTS_RO(qpim_rp_list, node, rp_info)) {
+       for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) {
                if (!pim_rpf_addr_is_inaddr_none(&rp_info->rp)) {
                        char buf[48];
 
@@ -954,7 +964,7 @@ void pim_rp_show_information(struct vty *vty, u_char uj)
        }
 }
 
-void pim_resolve_rp_nh(void)
+void pim_resolve_rp_nh(struct pim_instance *pim)
 {
        struct listnode *node = NULL;
        struct rp_info *rp_info = NULL;
@@ -963,7 +973,7 @@ void pim_resolve_rp_nh(void)
        struct pim_nexthop_cache pnc;
        struct pim_neighbor *nbr = NULL;
 
-       for (ALL_LIST_ELEMENTS_RO(qpim_rp_list, node, rp_info)) {
+       for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) {
                if (rp_info->rp.rpf_addr.u.prefix4.s_addr == INADDR_NONE)
                        continue;
 
@@ -971,43 +981,32 @@ void pim_resolve_rp_nh(void)
                nht_p.prefixlen = IPV4_MAX_BITLEN;
                nht_p.u.prefix4 = rp_info->rp.rpf_addr.u.prefix4;
                memset(&pnc, 0, sizeof(struct pim_nexthop_cache));
-               if ((pim_find_or_track_nexthop(&nht_p, NULL, rp_info, &pnc))
-                   == 1) {
-                       for (nh_node = pnc.nexthop; nh_node;
-                            nh_node = nh_node->next) {
-                               if (nh_node->gate.ipv4.s_addr == 0) {
-                                       nbr = pim_neighbor_find_if(
-                                               if_lookup_by_index(
-                                                       nh_node->ifindex,
-                                                       VRF_DEFAULT));
-                                       if (nbr) {
-                                               nh_node->gate.ipv4 =
-                                                       nbr->source_addr;
-                                               if (PIM_DEBUG_TRACE) {
-                                                       char str[PREFIX_STRLEN];
-                                                       char str1
-                                                               [INET_ADDRSTRLEN];
-                                                       struct interface *ifp1 =
-                                                               if_lookup_by_index(
-                                                                       nh_node->ifindex,
-                                                                       VRF_DEFAULT);
-                                                       pim_inet4_dump(
-                                                               "<nht_nbr?>",
-                                                               nbr->source_addr,
-                                                               str1,
-                                                               sizeof(str1));
-                                                       pim_addr_dump(
-                                                               "<nht_addr?>",
-                                                               &nht_p, str,
-                                                               sizeof(str));
-                                                       zlog_debug(
-                                                               "%s: addr %s new nexthop addr %s interface %s",
-                                                               __PRETTY_FUNCTION__,
-                                                               str, str1,
-                                                               ifp1->name);
-                                               }
-                                       }
-                               }
+               if (!pim_find_or_track_nexthop(pim, &nht_p, NULL, rp_info,
+                                              &pnc))
+                       continue;
+
+               for (nh_node = pnc.nexthop; nh_node; nh_node = nh_node->next) {
+                       if (nh_node->gate.ipv4.s_addr != 0)
+                               continue;
+
+                       struct interface *ifp1 = if_lookup_by_index(
+                               nh_node->ifindex, pim->vrf_id);
+                       nbr = pim_neighbor_find_if(ifp1);
+                       if (!nbr)
+                               continue;
+
+                       nh_node->gate.ipv4 = nbr->source_addr;
+                       if (PIM_DEBUG_TRACE) {
+                               char str[PREFIX_STRLEN];
+                               char str1[INET_ADDRSTRLEN];
+                               pim_inet4_dump("<nht_nbr?>", nbr->source_addr,
+                                              str1, sizeof(str1));
+                               pim_addr_dump("<nht_addr?>", &nht_p, str,
+                                             sizeof(str));
+                               zlog_debug(
+                                       "%s: addr %s new nexthop addr %s interface %s",
+                                       __PRETTY_FUNCTION__, str, str1,
+                                       ifp1->name);
                        }
                }
        }
index 7a7c26593e76a9323cf929a450bf5c790470c7f3..e07d65137ff0d736a422a81e244d5e08d2f6be71 100644 (file)
@@ -34,33 +34,41 @@ struct rp_info {
        char *plist;
 };
 
-void pim_rp_init(void);
-void pim_rp_free(void);
+void pim_rp_init(struct pim_instance *pim);
+void pim_rp_free(struct pim_instance *pim);
 
-int pim_rp_new(const char *rp, const char *group, const char *plist);
-int pim_rp_del(const char *rp, const char *group, const char *plist);
-void pim_rp_prefix_list_update(struct prefix_list *plist);
+void pim_rp_list_hash_clean(void *data);
 
-int pim_rp_config_write(struct vty *vty);
+int pim_rp_new(struct pim_instance *pim, const char *rp, const char *group,
+              const char *plist);
+int pim_rp_del(struct pim_instance *pim, const char *rp, const char *group,
+              const char *plist);
+void pim_rp_prefix_list_update(struct pim_instance *pim,
+                              struct prefix_list *plist);
 
-int pim_rp_setup(void);
+int pim_rp_config_write(struct pim_instance *pim, struct vty *vty,
+                       const char *spaces);
 
-int pim_rp_i_am_rp(struct in_addr group);
+void pim_rp_setup(struct pim_instance *pim);
+
+int pim_rp_i_am_rp(struct pim_instance *pim, struct in_addr group);
 void pim_rp_check_on_if_add(struct pim_interface *pim_ifp);
-void pim_i_am_rp_re_evaluate(void);
+void pim_i_am_rp_re_evaluate(struct pim_instance *pim);
 
-int pim_rp_check_is_my_ip_address(struct in_addr group,
+int pim_rp_check_is_my_ip_address(struct pim_instance *pim,
+                                 struct in_addr group,
                                  struct in_addr dest_addr);
 
-int pim_rp_set_upstream_addr(struct in_addr *up, struct in_addr source,
-                            struct in_addr group);
+int pim_rp_set_upstream_addr(struct pim_instance *pim, struct in_addr *up,
+                            struct in_addr source, struct in_addr group);
 
-struct pim_rpf *pim_rp_g(struct in_addr group);
+struct pim_rpf *pim_rp_g(struct pim_instance *pim, struct in_addr group);
 
-#define I_am_RP(G)  pim_rp_i_am_rp ((G))
-#define RP(G)       pim_rp_g ((G))
+#define I_am_RP(P, G)  pim_rp_i_am_rp ((P), (G))
+#define RP(P, G)       pim_rp_g ((P), (G))
 
-void pim_rp_show_information(struct vty *vty, u_char uj);
-void pim_resolve_rp_nh(void);
+void pim_rp_show_information(struct pim_instance *pim, struct vty *vty,
+                            u_char uj);
+void pim_resolve_rp_nh(struct pim_instance *pim);
 int pim_rp_list_cmp(void *v1, void *v2);
 #endif
index 4d0652c27eb7d8a1e78d16a5e4f7b6b65c86fcdd..36c6c894ef04be6410865306876250b8b837b16d 100644 (file)
@@ -24,6 +24,7 @@
 #include "log.h"
 #include "prefix.h"
 #include "memory.h"
+#include "jhash.h"
 
 #include "pimd.h"
 #include "pim_rpf.h"
@@ -34,6 +35,7 @@
 #include "pim_ifchannel.h"
 #include "pim_time.h"
 #include "pim_nht.h"
+#include "pim_oil.h"
 
 static long long last_route_change_time = -1;
 long long nexthop_lookups_avoided = 0;
@@ -48,8 +50,8 @@ void pim_rpf_set_refresh_time(void)
                           __PRETTY_FUNCTION__, last_route_change_time);
 }
 
-int pim_nexthop_lookup(struct pim_nexthop *nexthop, struct in_addr addr,
-                      int neighbor_needed)
+int pim_nexthop_lookup(struct pim_instance *pim, struct pim_nexthop *nexthop,
+                      struct in_addr addr, int neighbor_needed)
 {
        struct pim_zlookup_nexthop nexthop_tab[MULTIPATH_NUM];
        struct pim_neighbor *nbr = NULL;
@@ -91,8 +93,8 @@ int pim_nexthop_lookup(struct pim_nexthop *nexthop, struct in_addr addr,
 
        memset(nexthop_tab, 0,
               sizeof(struct pim_zlookup_nexthop) * MULTIPATH_NUM);
-       num_ifindex = zclient_lookup_nexthop(nexthop_tab, MULTIPATH_NUM, addr,
-                                            PIM_NEXTHOP_LOOKUP_MAX);
+       num_ifindex = zclient_lookup_nexthop(pim, nexthop_tab, MULTIPATH_NUM,
+                                            addr, PIM_NEXTHOP_LOOKUP_MAX);
        if (num_ifindex < 1) {
                char addr_str[INET_ADDRSTRLEN];
                pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
@@ -105,7 +107,7 @@ int pim_nexthop_lookup(struct pim_nexthop *nexthop, struct in_addr addr,
        while (!found && (i < num_ifindex)) {
                first_ifindex = nexthop_tab[i].ifindex;
 
-               ifp = if_lookup_by_index(first_ifindex, VRF_DEFAULT);
+               ifp = if_lookup_by_index(first_ifindex, pim->vrf_id);
                if (!ifp) {
                        if (PIM_DEBUG_ZEBRA) {
                                char addr_str[INET_ADDRSTRLEN];
@@ -186,14 +188,14 @@ static int nexthop_mismatch(const struct pim_nexthop *nh1,
               || (nh1->mrib_route_metric != nh2->mrib_route_metric);
 }
 
-enum pim_rpf_result pim_rpf_update(struct pim_upstream *up, struct pim_rpf *old,
+enum pim_rpf_result pim_rpf_update(struct pim_instance *pim,
+                                  struct pim_upstream *up, struct pim_rpf *old,
                                   uint8_t is_new)
 {
        struct pim_rpf *rpf = &up->rpf;
        struct pim_rpf saved;
        struct prefix nht_p;
        struct pim_nexthop_cache pnc;
-       int ret = 0;
        struct prefix src, grp;
 
        saved.source_nexthop = rpf->source_nexthop;
@@ -218,27 +220,23 @@ enum pim_rpf_result pim_rpf_update(struct pim_upstream *up, struct pim_rpf *old,
        grp.prefixlen = IPV4_MAX_BITLEN;
        grp.u.prefix4 = up->sg.grp;
        memset(&pnc, 0, sizeof(struct pim_nexthop_cache));
-       if ((ret = pim_find_or_track_nexthop(&nht_p, up, NULL, &pnc)) == 1) {
+       if (pim_find_or_track_nexthop(pim, &nht_p, up, NULL, &pnc)) {
                if (pnc.nexthop_num) {
-                       // Compute PIM RPF using Cached nexthop
-                       if (pim_ecmp_nexthop_search(
-                                   &pnc, &up->rpf.source_nexthop, &src, &grp,
+                       if (!pim_ecmp_nexthop_search(
+                                   pim, &pnc, &up->rpf.source_nexthop, &src,
+                                   &grp,
                                    !PIM_UPSTREAM_FLAG_TEST_FHR(up->flags)
                                            && !PIM_UPSTREAM_FLAG_TEST_SRC_IGMP(
                                                       up->flags)))
-
-                       {
                                return PIM_RPF_FAILURE;
-                       }
                }
        } else {
-               if (pim_ecmp_nexthop_lookup(
-                           &rpf->source_nexthop, up->upstream_addr, &src, &grp,
-                           !PIM_UPSTREAM_FLAG_TEST_FHR(up->flags)
-                                   && !PIM_UPSTREAM_FLAG_TEST_SRC_IGMP(
-                                              up->flags))) {
+               if (!pim_ecmp_nexthop_lookup(
+                           pim, &rpf->source_nexthop, up->upstream_addr, &src,
+                           &grp, !PIM_UPSTREAM_FLAG_TEST_FHR(up->flags)
+                                         && !PIM_UPSTREAM_FLAG_TEST_SRC_IGMP(
+                                                    up->flags)))
                        return PIM_RPF_FAILURE;
-               }
        }
 
        rpf->rpf_addr.family = AF_INET;
@@ -267,7 +265,7 @@ enum pim_rpf_result pim_rpf_update(struct pim_upstream *up, struct pim_rpf *old,
                 rpf->source_nexthop.mrib_route_metric);
                }
 
-               pim_upstream_update_join_desired(up);
+               pim_upstream_update_join_desired(pim, up);
                pim_upstream_update_could_assert(up);
                pim_upstream_update_my_assert_metric(up);
        }
@@ -396,3 +394,20 @@ int pim_rpf_is_same(struct pim_rpf *rpf1, struct pim_rpf *rpf2)
 
        return 0;
 }
+
+unsigned int pim_rpf_hash_key(void *arg)
+{
+       struct pim_nexthop_cache *r = (struct pim_nexthop_cache *)arg;
+
+       return jhash_1word(r->rpf.rpf_addr.u.prefix4.s_addr, 0);
+}
+
+int pim_rpf_equal(const void *arg1, const void *arg2)
+{
+       const struct pim_nexthop_cache *r1 =
+               (const struct pim_nexthop_cache *)arg1;
+       const struct pim_nexthop_cache *r2 =
+               (const struct pim_nexthop_cache *)arg2;
+
+       return prefix_same(&r1->rpf.rpf_addr, &r2->rpf.rpf_addr);
+}
index 08331435634b39a777f14b4c90c13822c2345cdd..86032f1c29634eb066a811e5492491c597dea0c7 100644 (file)
@@ -58,9 +58,13 @@ struct pim_upstream;
 
 extern long long nexthop_lookups_avoided;
 
-int pim_nexthop_lookup(struct pim_nexthop *nexthop, struct in_addr addr,
-                      int neighbor_needed);
-enum pim_rpf_result pim_rpf_update(struct pim_upstream *up, struct pim_rpf *old,
+unsigned int pim_rpf_hash_key(void *arg);
+int pim_rpf_equal(const void *arg1, const void *arg2);
+
+int pim_nexthop_lookup(struct pim_instance *pim, struct pim_nexthop *nexthop,
+                      struct in_addr addr, int neighbor_needed);
+enum pim_rpf_result pim_rpf_update(struct pim_instance *pim,
+                                  struct pim_upstream *up, struct pim_rpf *old,
                                   uint8_t is_new);
 
 int pim_rpf_addr_is_inaddr_none(struct pim_rpf *rpf);
index 3046e9429965b340ea30c6f848e2d54c32b61a63..8d270e620563fc8fbb8d0d9e754ec65b54329d3e 100644 (file)
@@ -29,7 +29,7 @@
 #include "pim_ssm.h"
 #include "pim_zebra.h"
 
-static void pim_ssm_range_reevaluate(void)
+static void pim_ssm_range_reevaluate(struct pim_instance *pim)
 {
        /* 1. Setup register state for (S,G) entries if G has changed from SSM
         * to
@@ -47,13 +47,14 @@ static void pim_ssm_range_reevaluate(void)
         * will
         * disappear in time for SSM groups.
         */
-       pim_upstream_register_reevaluate();
+       pim_upstream_register_reevaluate(pim);
        igmp_source_forward_reevaluate_all();
 }
 
-void pim_ssm_prefix_list_update(struct prefix_list *plist)
+void pim_ssm_prefix_list_update(struct pim_instance *pim,
+                               struct prefix_list *plist)
 {
-       struct pim_ssm *ssm = pimg->ssm_info;
+       struct pim_ssm *ssm = pim->ssm_info;
 
        if (!ssm->plist_name
            || strcmp(ssm->plist_name, prefix_list_name(plist))) {
@@ -61,7 +62,7 @@ void pim_ssm_prefix_list_update(struct prefix_list *plist)
                return;
        }
 
-       pim_ssm_range_reevaluate();
+       pim_ssm_range_reevaluate(pim);
 }
 
 static int pim_is_grp_standard_ssm(struct prefix *group)
@@ -77,7 +78,7 @@ static int pim_is_grp_standard_ssm(struct prefix *group)
        return prefix_match(&group_ssm, group);
 }
 
-int pim_is_grp_ssm(struct in_addr group_addr)
+int pim_is_grp_ssm(struct pim_instance *pim, struct in_addr group_addr)
 {
        struct pim_ssm *ssm;
        struct prefix group;
@@ -88,7 +89,7 @@ int pim_is_grp_ssm(struct in_addr group_addr)
        group.u.prefix4 = group_addr;
        group.prefixlen = 32;
 
-       ssm = pimg->ssm_info;
+       ssm = pim->ssm_info;
        if (!ssm->plist_name) {
                return pim_is_grp_standard_ssm(&group);
        }
@@ -100,15 +101,16 @@ int pim_is_grp_ssm(struct in_addr group_addr)
        return (prefix_list_apply(plist, &group) == PREFIX_PERMIT);
 }
 
-int pim_ssm_range_set(vrf_id_t vrf_id, const char *plist_name)
+int pim_ssm_range_set(struct pim_instance *pim, vrf_id_t vrf_id,
+                     const char *plist_name)
 {
        struct pim_ssm *ssm;
        int change = 0;
 
-       if (vrf_id != VRF_DEFAULT)
+       if (vrf_id != pim->vrf_id)
                return PIM_SSM_ERR_NO_VRF;
 
-       ssm = pimg->ssm_info;
+       ssm = pim->ssm_info;
        if (plist_name) {
                if (ssm->plist_name) {
                        if (!strcmp(ssm->plist_name, plist_name))
@@ -125,17 +127,16 @@ int pim_ssm_range_set(vrf_id_t vrf_id, const char *plist_name)
        }
 
        if (change)
-               pim_ssm_range_reevaluate();
+               pim_ssm_range_reevaluate(pim);
 
        return PIM_SSM_ERR_NONE;
 }
 
-void *pim_ssm_init(vrf_id_t vrf_id)
+void *pim_ssm_init(void)
 {
        struct pim_ssm *ssm;
 
        ssm = XCALLOC(MTYPE_PIM_SSM_INFO, sizeof(*ssm));
-       ssm->vrf_id = vrf_id;
 
        return ssm;
 }
index 9e89d0c80ccc5a9f8327a7bfc14e7a2aec610023..7235ade8dc779a45400be89fb4e0b175edc3c677 100644 (file)
@@ -29,13 +29,14 @@ enum pim_ssm_err {
 };
 
 struct pim_ssm {
-       vrf_id_t vrf_id;
        char *plist_name; /* prefix list of group ranges */
 };
 
-void pim_ssm_prefix_list_update(struct prefix_list *plist);
-int pim_is_grp_ssm(struct in_addr group_addr);
-int pim_ssm_range_set(vrf_id_t vrf_id, const char *plist_name);
-void *pim_ssm_init(vrf_id_t vrf_id);
+void pim_ssm_prefix_list_update(struct pim_instance *pim,
+                               struct prefix_list *plist);
+int pim_is_grp_ssm(struct pim_instance *pim, struct in_addr group_addr);
+int pim_ssm_range_set(struct pim_instance *pim, vrf_id_t vrf_id,
+                     const char *plist_name);
+void *pim_ssm_init(void);
 void pim_ssm_terminate(struct pim_ssm *ssm);
 #endif
index 406183db86bda08036070da6bad46f937c7ffd47..9e90a34687098c34a2befc78b5ffb97d75552e68 100644 (file)
@@ -36,35 +36,36 @@ enum { PIM_SSMPINGD_REQUEST = 'Q', PIM_SSMPINGD_REPLY = 'A' };
 
 static void ssmpingd_read_on(struct ssmpingd_sock *ss);
 
-void pim_ssmpingd_init()
+void pim_ssmpingd_init(struct pim_instance *pim)
 {
        int result;
 
-       zassert(!qpim_ssmpingd_list);
+       zassert(!pim->ssmpingd_list);
 
        result = inet_pton(AF_INET, PIM_SSMPINGD_REPLY_GROUP,
-                          &qpim_ssmpingd_group_addr);
+                          &pim->ssmpingd_group_addr);
 
        zassert(result > 0);
 }
 
-void pim_ssmpingd_destroy()
+void pim_ssmpingd_destroy(struct pim_instance *pim)
 {
-       if (qpim_ssmpingd_list) {
-               list_free(qpim_ssmpingd_list);
-               qpim_ssmpingd_list = 0;
+       if (pim->ssmpingd_list) {
+               list_delete(pim->ssmpingd_list);
+               pim->ssmpingd_list = 0;
        }
 }
 
-static struct ssmpingd_sock *ssmpingd_find(struct in_addr source_addr)
+static struct ssmpingd_sock *ssmpingd_find(struct pim_instance *pim,
+                                          struct in_addr source_addr)
 {
        struct listnode *node;
        struct ssmpingd_sock *ss;
 
-       if (!qpim_ssmpingd_list)
+       if (!pim->ssmpingd_list)
                return 0;
 
-       for (ALL_LIST_ELEMENTS_RO(qpim_ssmpingd_list, node, ss))
+       for (ALL_LIST_ELEMENTS_RO(pim->ssmpingd_list, node, ss))
                if (source_addr.s_addr == ss->source_addr.s_addr)
                        return ss;
 
@@ -202,7 +203,6 @@ static int ssmpingd_socket(struct in_addr addr, int port, int mttl)
 static void ssmpingd_delete(struct ssmpingd_sock *ss)
 {
        zassert(ss);
-       zassert(qpim_ssmpingd_list);
 
        THREAD_OFF(ss->t_sock_read);
 
@@ -217,7 +217,7 @@ static void ssmpingd_delete(struct ssmpingd_sock *ss)
                /* warning only */
        }
 
-       listnode_delete(qpim_ssmpingd_list, ss);
+       listnode_delete(ss->pim->ssmpingd_list, ss);
        ssmpingd_free(ss);
 }
 
@@ -272,7 +272,7 @@ static int ssmpingd_read_msg(struct ssmpingd_sock *ss)
                return -1;
        }
 
-       ifp = if_lookup_by_index(ifindex, VRF_DEFAULT);
+       ifp = if_lookup_by_index(ifindex, ss->pim->vrf_id);
 
        if (buf[0] != PIM_SSMPINGD_REQUEST) {
                char source_str[INET_ADDRSTRLEN];
@@ -315,7 +315,7 @@ static int ssmpingd_read_msg(struct ssmpingd_sock *ss)
        ssmpingd_sendto(ss, buf, len, from);
 
        /* multicast reply */
-       from.sin_addr = qpim_ssmpingd_group_addr;
+       from.sin_addr = ss->pim->ssmpingd_group_addr;
        ssmpingd_sendto(ss, buf, len, from);
 
        return 0;
@@ -342,20 +342,21 @@ static void ssmpingd_read_on(struct ssmpingd_sock *ss)
                        &ss->t_sock_read);
 }
 
-static struct ssmpingd_sock *ssmpingd_new(struct in_addr source_addr)
+static struct ssmpingd_sock *ssmpingd_new(struct pim_instance *pim,
+                                         struct in_addr source_addr)
 {
        struct ssmpingd_sock *ss;
        int sock_fd;
 
-       if (!qpim_ssmpingd_list) {
-               qpim_ssmpingd_list = list_new();
-               if (!qpim_ssmpingd_list) {
+       if (!pim->ssmpingd_list) {
+               pim->ssmpingd_list = list_new();
+               if (!pim->ssmpingd_list) {
                        zlog_err(
                                "%s %s: failure: qpim_ssmpingd_list=list_new()",
                                __FILE__, __PRETTY_FUNCTION__);
                        return 0;
                }
-               qpim_ssmpingd_list->del = (void (*)(void *))ssmpingd_free;
+               pim->ssmpingd_list->del = (void (*)(void *))ssmpingd_free;
        }
 
        sock_fd =
@@ -380,24 +381,25 @@ static struct ssmpingd_sock *ssmpingd_new(struct in_addr source_addr)
                return 0;
        }
 
+       ss->pim = pim;
        ss->sock_fd = sock_fd;
        ss->t_sock_read = NULL;
        ss->source_addr = source_addr;
        ss->creation = pim_time_monotonic_sec();
        ss->requests = 0;
 
-       listnode_add(qpim_ssmpingd_list, ss);
+       listnode_add(pim->ssmpingd_list, ss);
 
        ssmpingd_read_on(ss);
 
        return ss;
 }
 
-int pim_ssmpingd_start(struct in_addr source_addr)
+int pim_ssmpingd_start(struct pim_instance *pim, struct in_addr source_addr)
 {
        struct ssmpingd_sock *ss;
 
-       ss = ssmpingd_find(source_addr);
+       ss = ssmpingd_find(pim, source_addr);
        if (ss) {
                /* silently ignore request to recreate entry */
                return 0;
@@ -411,7 +413,7 @@ int pim_ssmpingd_start(struct in_addr source_addr)
                          __PRETTY_FUNCTION__, source_str);
        }
 
-       ss = ssmpingd_new(source_addr);
+       ss = ssmpingd_new(pim, source_addr);
        if (!ss) {
                char source_str[INET_ADDRSTRLEN];
                pim_inet4_dump("<src?>", source_addr, source_str,
@@ -424,11 +426,11 @@ int pim_ssmpingd_start(struct in_addr source_addr)
        return 0;
 }
 
-int pim_ssmpingd_stop(struct in_addr source_addr)
+int pim_ssmpingd_stop(struct pim_instance *pim, struct in_addr source_addr)
 {
        struct ssmpingd_sock *ss;
 
-       ss = ssmpingd_find(source_addr);
+       ss = ssmpingd_find(pim, source_addr);
        if (!ss) {
                char source_str[INET_ADDRSTRLEN];
                pim_inet4_dump("<src?>", source_addr, source_str,
index 89fb320a76c1a2d72015211e4c079e44a2b15446..fafdd7ade128b1c555660f0793a8c4f19f21b7c5 100644 (file)
@@ -27,6 +27,8 @@
 #include "pim_iface.h"
 
 struct ssmpingd_sock {
+       struct pim_instance *pim;
+
        int sock_fd;                /* socket */
        struct thread *t_sock_read; /* thread for reading socket */
        struct in_addr source_addr; /* source address */
@@ -34,9 +36,9 @@ struct ssmpingd_sock {
        int64_t requests;          /* counter */
 };
 
-void pim_ssmpingd_init(void);
-void pim_ssmpingd_destroy(void);
-int pim_ssmpingd_start(struct in_addr source_addr);
-int pim_ssmpingd_stop(struct in_addr source_addr);
+void pim_ssmpingd_init(struct pim_instance *pim);
+void pim_ssmpingd_destroy(struct pim_instance *pim);
+int pim_ssmpingd_start(struct pim_instance *pim, struct in_addr source_addr);
+int pim_ssmpingd_stop(struct pim_instance *pim, struct in_addr source_addr);
 
 #endif /* PIM_SSMPINGD_H */
index 7c9aca47a72ca43273e83bcf897f789da16788f4..3d44a01c78803d09161a8ac7f029f2dc2008dc98 100644 (file)
@@ -74,8 +74,9 @@ static struct static_route *static_route_new(unsigned int iif, unsigned int oif,
 }
 
 
-int pim_static_add(struct interface *iif, struct interface *oif,
-                  struct in_addr group, struct in_addr source)
+int pim_static_add(struct pim_instance *pim, struct interface *iif,
+                  struct interface *oif, struct in_addr group,
+                  struct in_addr source)
 {
        struct listnode *node = NULL;
        struct static_route *s_route = NULL;
@@ -101,8 +102,11 @@ int pim_static_add(struct interface *iif, struct interface *oif,
                return -4;
        }
 #endif
+       if (iif->vrf_id != oif->vrf_id) {
+               return -3;
+       }
 
-       for (ALL_LIST_ELEMENTS_RO(qpim_static_route_list, node, s_route)) {
+       for (ALL_LIST_ELEMENTS_RO(pim->static_routes, node, s_route)) {
                if (s_route->group.s_addr == group.s_addr
                    && s_route->source.s_addr == source.s_addr) {
                        if (s_route->iif == iif_index
@@ -181,9 +185,11 @@ int pim_static_add(struct interface *iif, struct interface *oif,
         * match */
        if (!node) {
                s_route = static_route_new(iif_index, oif_index, group, source);
-               listnode_add(qpim_static_route_list, s_route);
+               listnode_add(pim->static_routes, s_route);
        }
 
+       s_route->c_oil.pim = pim;
+
        if (pim_mroute_add(&s_route->c_oil, __PRETTY_FUNCTION__)) {
                char gifaddr_str[INET_ADDRSTRLEN];
                char sifaddr_str[INET_ADDRSTRLEN];
@@ -203,7 +209,7 @@ int pim_static_add(struct interface *iif, struct interface *oif,
                } else {
                        /* we never stored off a copy, so it must have been a
                         * fresh new route */
-                       listnode_delete(qpim_static_route_list, s_route);
+                       listnode_delete(pim->static_routes, s_route);
                        pim_static_route_free(s_route);
                }
 
@@ -235,8 +241,9 @@ int pim_static_add(struct interface *iif, struct interface *oif,
        return 0;
 }
 
-int pim_static_del(struct interface *iif, struct interface *oif,
-                  struct in_addr group, struct in_addr source)
+int pim_static_del(struct pim_instance *pim, struct interface *iif,
+                  struct interface *oif, struct in_addr group,
+                  struct in_addr source)
 {
        struct listnode *node = NULL;
        struct listnode *nextnode = NULL;
@@ -253,8 +260,7 @@ int pim_static_del(struct interface *iif, struct interface *oif,
                return -2;
        }
 
-       for (ALL_LIST_ELEMENTS(qpim_static_route_list, node, nextnode,
-                              s_route)) {
+       for (ALL_LIST_ELEMENTS(pim->static_routes, node, nextnode, s_route)) {
                if (s_route->iif == iif_index
                    && s_route->group.s_addr == group.s_addr
                    && s_route->source.s_addr == source.s_addr
@@ -293,8 +299,7 @@ int pim_static_del(struct interface *iif, struct interface *oif,
                        s_route->c_oil.oif_creation[oif_index] = 0;
 
                        if (s_route->c_oil.oil_ref_count <= 0) {
-                               listnode_delete(qpim_static_route_list,
-                                               s_route);
+                               listnode_delete(pim->static_routes, s_route);
                                pim_static_route_free(s_route);
                        }
 
@@ -332,7 +337,8 @@ int pim_static_del(struct interface *iif, struct interface *oif,
        return 0;
 }
 
-int pim_static_write_mroute(struct vty *vty, struct interface *ifp)
+int pim_static_write_mroute(struct pim_instance *pim, struct vty *vty,
+                           struct interface *ifp)
 {
        struct pim_interface *pim_ifp = ifp->info;
        struct listnode *node;
@@ -344,7 +350,7 @@ int pim_static_write_mroute(struct vty *vty, struct interface *ifp)
        if (!pim_ifp)
                return 0;
 
-       for (ALL_LIST_ELEMENTS_RO(qpim_static_route_list, node, sroute)) {
+       for (ALL_LIST_ELEMENTS_RO(pim->static_routes, node, sroute)) {
                pim_inet4_dump("<ifaddr?>", sroute->group, gbuf, sizeof(gbuf));
                pim_inet4_dump("<ifaddr?>", sroute->source, sbuf, sizeof(sbuf));
                if (sroute->iif == pim_ifp->mroute_vif_index) {
@@ -352,7 +358,8 @@ int pim_static_write_mroute(struct vty *vty, struct interface *ifp)
                        for (i = 0; i < MAXVIFS; i++)
                                if (sroute->oif_ttls[i]) {
                                        struct interface *oifp =
-                                               pim_if_find_by_vif_index(i);
+                                               pim_if_find_by_vif_index(pim,
+                                                                        i);
                                        if (sroute->source.s_addr == 0)
                                                vty_out(vty,
                                                        " ip mroute %s %s\n",
index 1114f4b67b033543ad15aae0e65c7740c285dd80..953ec0a70ad0fa89656376162b08739b293e1b3b 100644 (file)
@@ -36,10 +36,13 @@ struct static_route {
 
 void pim_static_route_free(struct static_route *s_route);
 
-int pim_static_add(struct interface *iif, struct interface *oif,
-                  struct in_addr group, struct in_addr source);
-int pim_static_del(struct interface *iif, struct interface *oif,
-                  struct in_addr group, struct in_addr source);
-int pim_static_write_mroute(struct vty *vty, struct interface *ifp);
+int pim_static_add(struct pim_instance *pim, struct interface *iif,
+                  struct interface *oif, struct in_addr group,
+                  struct in_addr source);
+int pim_static_del(struct pim_instance *pim, struct interface *iif,
+                  struct interface *oif, struct in_addr group,
+                  struct in_addr source);
+int pim_static_write_mroute(struct pim_instance *pim, struct vty *vty,
+                           struct interface *ifp);
 
 #endif /* PIM_STATIC_H_ */
index 0ddd04c38c25eccf764126b0da170a52539ebb3c..95d1a840ff8eed0347f5d89716c45e035f2ecaf7 100644 (file)
 #include "pim_nht.h"
 #include "pim_ssm.h"
 
-struct hash *pim_upstream_hash = NULL;
-struct list *pim_upstream_list = NULL;
-struct timer_wheel *pim_upstream_sg_wheel = NULL;
-
 static void join_timer_stop(struct pim_upstream *up);
 static void
 pim_upstream_update_assert_tracking_desired(struct pim_upstream *up);
@@ -67,7 +63,8 @@ pim_upstream_update_assert_tracking_desired(struct pim_upstream *up);
  * remove the parent pointer from
  * those pointing at us
  */
-static void pim_upstream_remove_children(struct pim_upstream *up)
+static void pim_upstream_remove_children(struct pim_instance *pim,
+                                        struct pim_upstream *up)
 {
        struct pim_upstream *child;
 
@@ -79,7 +76,8 @@ static void pim_upstream_remove_children(struct pim_upstream *up)
                listnode_delete(up->sources, child);
                if (PIM_UPSTREAM_FLAG_TEST_SRC_LHR(child->flags)) {
                        PIM_UPSTREAM_FLAG_UNSET_SRC_LHR(child->flags);
-                       child = pim_upstream_del(child, __PRETTY_FUNCTION__);
+                       child = pim_upstream_del(pim, child,
+                                                __PRETTY_FUNCTION__);
                }
                if (child)
                        child->parent = NULL;
@@ -93,7 +91,8 @@ static void pim_upstream_remove_children(struct pim_upstream *up)
  * Find the children that would point
  * at us.
  */
-static void pim_upstream_find_new_children(struct pim_upstream *up)
+static void pim_upstream_find_new_children(struct pim_instance *pim,
+                                          struct pim_upstream *up)
 {
        struct pim_upstream *child;
        struct listnode *ch_node;
@@ -106,7 +105,7 @@ static void pim_upstream_find_new_children(struct pim_upstream *up)
            && (up->sg.grp.s_addr == INADDR_ANY))
                return;
 
-       for (ALL_LIST_ELEMENTS_RO(pim_upstream_list, ch_node, child)) {
+       for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, ch_node, child)) {
                if ((up->sg.grp.s_addr != INADDR_ANY)
                    && (child->sg.grp.s_addr == up->sg.grp.s_addr)
                    && (child != up)) {
@@ -121,7 +120,8 @@ static void pim_upstream_find_new_children(struct pim_upstream *up)
  * If we have a (S,G), find the (*,G)
  * If we have a (*,G), find the (*,*)
  */
-static struct pim_upstream *pim_upstream_find_parent(struct pim_upstream *child)
+static struct pim_upstream *pim_upstream_find_parent(struct pim_instance *pim,
+                                                    struct pim_upstream *child)
 {
        struct prefix_sg any = child->sg;
        struct pim_upstream *up = NULL;
@@ -130,7 +130,7 @@ static struct pim_upstream *pim_upstream_find_parent(struct pim_upstream *child)
        if ((child->sg.src.s_addr != INADDR_ANY)
            && (child->sg.grp.s_addr != INADDR_ANY)) {
                any.src.s_addr = INADDR_ANY;
-               up = pim_upstream_find(&any);
+               up = pim_upstream_find(pim, &any);
 
                if (up)
                        listnode_add(up->sources, child);
@@ -153,12 +153,14 @@ static void upstream_channel_oil_detach(struct pim_upstream *up)
                /* Detaching from channel_oil, channel_oil may exist post del,
                   but upstream would not keep reference of it
                 */
+               up->channel_oil->up = NULL;
                pim_channel_oil_del(up->channel_oil);
                up->channel_oil = NULL;
        }
 }
 
-struct pim_upstream *pim_upstream_del(struct pim_upstream *up, const char *name)
+struct pim_upstream *pim_upstream_del(struct pim_instance *pim,
+                                     struct pim_upstream *up, const char *name)
 {
        bool notify_msdp = false;
        struct prefix nht_p;
@@ -194,11 +196,11 @@ struct pim_upstream *pim_upstream_del(struct pim_upstream *up, const char *name)
        up->rpf.source_nexthop.interface = NULL;
 
        if (up->sg.src.s_addr != INADDR_ANY) {
-               wheel_remove_item(pim_upstream_sg_wheel, up);
+               wheel_remove_item(pim->upstream_sg_wheel, up);
                notify_msdp = true;
        }
 
-       pim_upstream_remove_children(up);
+       pim_upstream_remove_children(pim, up);
        if (up->sources)
                list_delete(up->sources);
        up->sources = NULL;
@@ -217,11 +219,11 @@ struct pim_upstream *pim_upstream_del(struct pim_upstream *up, const char *name)
                listnode_delete(up->parent->sources, up);
        up->parent = NULL;
 
-       listnode_delete(pim_upstream_list, up);
-       hash_release(pim_upstream_hash, up);
+       listnode_delete(pim->upstream_list, up);
+       hash_release(pim->upstream_hash, up);
 
        if (notify_msdp) {
-               pim_msdp_up_del(&up->sg);
+               pim_msdp_up_del(pim, &up->sg);
        }
 
        /* Deregister addr with Zebra NHT */
@@ -234,7 +236,7 @@ struct pim_upstream *pim_upstream_del(struct pim_upstream *up, const char *name)
                zlog_debug("%s: Deregister upstream %s addr %s with Zebra NHT",
                           __PRETTY_FUNCTION__, up->sg_str, buf);
        }
-       pim_delete_tracked_nexthop(&nht_p, up, NULL);
+       pim_delete_tracked_nexthop(pim, &nht_p, up, NULL);
 
        pim_upstream_free(up);
 
@@ -442,7 +444,7 @@ static void forward_off(struct pim_upstream *up)
        /* scan per-interface (S,G) state */
        for (ALL_LIST_ELEMENTS(up->ifchannels, chnode, chnextnode, ch)) {
 
-               pim_forward_stop(ch);
+               pim_forward_stop(ch, false);
 
        } /* scan iface channel list */
 }
@@ -469,12 +471,12 @@ static int pim_upstream_could_register(struct pim_upstream *up)
 
 /* Source registration is supressed for SSM groups. When the SSM range changes
  * we re-revaluate register setup for existing upstream entries */
-void pim_upstream_register_reevaluate(void)
+void pim_upstream_register_reevaluate(struct pim_instance *pim)
 {
        struct listnode *upnode;
        struct pim_upstream *up;
 
-       for (ALL_LIST_ELEMENTS_RO(pim_upstream_list, upnode, up)) {
+       for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, upnode, up)) {
                /* If FHR is set CouldRegister is True. Also check if the flow
                 * is actually active; if it is not kat setup will trigger
                 * source
@@ -482,7 +484,7 @@ void pim_upstream_register_reevaluate(void)
                if (!PIM_UPSTREAM_FLAG_TEST_FHR(up->flags) || !up->t_ka_timer)
                        continue;
 
-               if (pim_is_grp_ssm(up->sg.grp)) {
+               if (pim_is_grp_ssm(pim, up->sg.grp)) {
                        /* clear the register state  for SSM groups */
                        if (up->reg_state != PIM_REG_NOINFO) {
                                if (PIM_DEBUG_PIM_EVENTS)
@@ -491,7 +493,7 @@ void pim_upstream_register_reevaluate(void)
                                                up->sg_str);
                                /* remove regiface from the OIL if it is there*/
                                pim_channel_del_oif(up->channel_oil,
-                                                   pim_regiface,
+                                                   pim->regiface,
                                                    PIM_OIF_FLAG_PROTO_PIM);
                                up->reg_state = PIM_REG_NOINFO;
                        }
@@ -503,7 +505,7 @@ void pim_upstream_register_reevaluate(void)
                                                "Register %s as G is now ASM",
                                                up->sg_str);
                                pim_channel_add_oif(up->channel_oil,
-                                                   pim_regiface,
+                                                   pim->regiface,
                                                    PIM_OIF_FLAG_PROTO_PIM);
                                up->reg_state = PIM_REG_JOIN;
                        }
@@ -511,7 +513,7 @@ void pim_upstream_register_reevaluate(void)
        }
 }
 
-void pim_upstream_switch(struct pim_upstream *up,
+void pim_upstream_switch(struct pim_instance *pim, struct pim_upstream *up,
                         enum pim_upstream_state new_state)
 {
        enum pim_upstream_state old_state = up->join_state;
@@ -533,14 +535,14 @@ void pim_upstream_switch(struct pim_upstream *up,
                if (old_state != PIM_UPSTREAM_JOINED) {
                        int old_fhr = PIM_UPSTREAM_FLAG_TEST_FHR(up->flags);
                        forward_on(up);
-                       pim_msdp_up_join_state_changed(up);
+                       pim_msdp_up_join_state_changed(pim, up);
                        if (pim_upstream_could_register(up)) {
                                PIM_UPSTREAM_FLAG_SET_FHR(up->flags);
                                if (!old_fhr
                                    && PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(
                                               up->flags)) {
                                        pim_upstream_keep_alive_timer_start(
-                                               up, qpim_keep_alive_time);
+                                               up, pim->keep_alive_time);
                                        pim_register_join(up);
                                }
                        } else {
@@ -554,13 +556,13 @@ void pim_upstream_switch(struct pim_upstream *up,
 
                forward_off(up);
                if (old_state == PIM_UPSTREAM_JOINED)
-                       pim_msdp_up_join_state_changed(up);
+                       pim_msdp_up_join_state_changed(pim, up);
 
                /* IHR, Trigger SGRpt on *,G IIF to prune S,G from RPT towards
                   RP.
                   If I am RP for G then send S,G prune to its IIF. */
                if (pim_upstream_is_sg_rpt(up) && up->parent
-                   && !I_am_RP(up->sg.grp)) {
+                   && !I_am_RP(pim, up->sg.grp)) {
                        if (PIM_DEBUG_PIM_TRACE_DETAIL)
                                zlog_debug(
                                        "%s: *,G IIF %s S,G IIF %s ",
@@ -598,8 +600,11 @@ int pim_upstream_compare(void *arg1, void *arg2)
        return 0;
 }
 
-static struct pim_upstream *
-pim_upstream_new(struct prefix_sg *sg, struct interface *incoming, int flags)
+static struct pim_upstream *pim_upstream_new(struct pim_instance *pim,
+                                            struct prefix_sg *sg,
+                                            struct interface *incoming,
+                                            int flags,
+                                            struct pim_ifchannel *ch)
 {
        enum pim_rpf_result rpf_result;
        struct pim_interface *pim_ifp;
@@ -614,25 +619,29 @@ pim_upstream_new(struct prefix_sg *sg, struct interface *incoming, int flags)
 
        up->sg = *sg;
        pim_str_sg_set(sg, up->sg_str);
-       up = hash_get(pim_upstream_hash, up, hash_alloc_intern);
-       if (!pim_rp_set_upstream_addr(&up->upstream_addr, sg->src, sg->grp)) {
+       if (ch)
+               ch->upstream = up;
+
+       up = hash_get(pim->upstream_hash, up, hash_alloc_intern);
+       if (!pim_rp_set_upstream_addr(pim, &up->upstream_addr, sg->src,
+                                     sg->grp)) {
                if (PIM_DEBUG_TRACE)
                        zlog_debug("%s: Received a (*,G) with no RP configured",
                                   __PRETTY_FUNCTION__);
 
-               hash_release(pim_upstream_hash, up);
+               hash_release(pim->upstream_hash, up);
                XFREE(MTYPE_PIM_UPSTREAM, up);
                return NULL;
        }
 
-       up->parent = pim_upstream_find_parent(up);
+       up->parent = pim_upstream_find_parent(pim, up);
        if (up->sg.src.s_addr == INADDR_ANY) {
                up->sources = list_new();
                up->sources->cmp = pim_upstream_compare;
        } else
                up->sources = NULL;
 
-       pim_upstream_find_new_children(up);
+       pim_upstream_find_new_children(pim, up);
        up->flags = flags;
        up->ref_count = 1;
        up->t_join_timer = NULL;
@@ -660,9 +669,9 @@ pim_upstream_new(struct prefix_sg *sg, struct interface *incoming, int flags)
        up->ifchannels->cmp = (int (*)(void *, void *))pim_ifchannel_compare;
 
        if (up->sg.src.s_addr != INADDR_ANY)
-               wheel_add_item(pim_upstream_sg_wheel, up);
+               wheel_add_item(pim->upstream_sg_wheel, up);
 
-       rpf_result = pim_rpf_update(up, NULL, 1);
+       rpf_result = pim_rpf_update(pim, up, NULL, 1);
        if (rpf_result == PIM_RPF_FAILURE) {
                struct prefix nht_p;
 
@@ -674,7 +683,7 @@ pim_upstream_new(struct prefix_sg *sg, struct interface *incoming, int flags)
                nht_p.family = AF_INET;
                nht_p.prefixlen = IPV4_MAX_BITLEN;
                nht_p.u.prefix4 = up->upstream_addr;
-               pim_delete_tracked_nexthop(&nht_p, up, NULL);
+               pim_delete_tracked_nexthop(pim, &nht_p, up, NULL);
 
                if (up->parent) {
                        listnode_delete(up->parent->sources, up);
@@ -682,13 +691,13 @@ pim_upstream_new(struct prefix_sg *sg, struct interface *incoming, int flags)
                }
 
                if (up->sg.src.s_addr != INADDR_ANY)
-                       wheel_remove_item(pim_upstream_sg_wheel, up);
+                       wheel_remove_item(pim->upstream_sg_wheel, up);
 
-               pim_upstream_remove_children(up);
+               pim_upstream_remove_children(pim, up);
                if (up->sources)
                        list_delete(up->sources);
 
-               hash_release(pim_upstream_hash, up);
+               hash_release(pim->upstream_hash, up);
                XFREE(MTYPE_PIM_UPSTREAM, up);
                return NULL;
        }
@@ -697,9 +706,9 @@ pim_upstream_new(struct prefix_sg *sg, struct interface *incoming, int flags)
                pim_ifp = up->rpf.source_nexthop.interface->info;
                if (pim_ifp)
                        up->channel_oil = pim_channel_oil_add(
-                               &up->sg, pim_ifp->mroute_vif_index);
+                               pim, &up->sg, pim_ifp->mroute_vif_index);
        }
-       listnode_add_sort(pim_upstream_list, up);
+       listnode_add_sort(pim->upstream_list, up);
 
        if (PIM_DEBUG_TRACE) {
                zlog_debug(
@@ -711,13 +720,14 @@ pim_upstream_new(struct prefix_sg *sg, struct interface *incoming, int flags)
        return up;
 }
 
-struct pim_upstream *pim_upstream_find(struct prefix_sg *sg)
+struct pim_upstream *pim_upstream_find(struct pim_instance *pim,
+                                      struct prefix_sg *sg)
 {
        struct pim_upstream lookup;
        struct pim_upstream *up = NULL;
 
        lookup.sg = *sg;
-       up = hash_lookup(pim_upstream_hash, &lookup);
+       up = hash_lookup(pim->upstream_hash, &lookup);
        return up;
 }
 
@@ -726,8 +736,11 @@ struct pim_upstream *pim_upstream_find_or_add(struct prefix_sg *sg,
                                              int flags, const char *name)
 {
        struct pim_upstream *up;
+       struct pim_interface *pim_ifp;
+
+       pim_ifp = incoming->info;
 
-       up = pim_upstream_find(sg);
+       up = pim_upstream_find(pim_ifp->pim, sg);
 
        if (up) {
                if (!(up->flags & flags)) {
@@ -740,7 +753,8 @@ struct pim_upstream *pim_upstream_find_or_add(struct prefix_sg *sg,
                                        up->ref_count);
                }
        } else
-               up = pim_upstream_add(sg, incoming, flags, name);
+               up = pim_upstream_add(pim_ifp->pim, sg, incoming, flags, name,
+                                     NULL);
 
        return up;
 }
@@ -755,18 +769,21 @@ void pim_upstream_ref(struct pim_upstream *up, int flags, const char *name)
                           up->ref_count);
 }
 
-struct pim_upstream *pim_upstream_add(struct prefix_sg *sg,
+struct pim_upstream *pim_upstream_add(struct pim_instance *pim,
+                                     struct prefix_sg *sg,
                                      struct interface *incoming, int flags,
-                                     const char *name)
+                                     const char *name,
+                                     struct pim_ifchannel *ch)
 {
        struct pim_upstream *up = NULL;
        int found = 0;
-       up = pim_upstream_find(sg);
+
+       up = pim_upstream_find(pim, sg);
        if (up) {
                pim_upstream_ref(up, flags, name);
                found = 1;
        } else {
-               up = pim_upstream_new(sg, incoming, flags);
+               up = pim_upstream_new(pim, sg, incoming, flags, ch);
        }
 
        if (PIM_DEBUG_TRACE) {
@@ -842,7 +859,8 @@ int pim_upstream_evaluate_join_desired_interface(struct pim_upstream *up,
 
   See also pim_upstream_update_join_desired() below.
  */
-int pim_upstream_evaluate_join_desired(struct pim_upstream *up)
+int pim_upstream_evaluate_join_desired(struct pim_instance *pim,
+                                      struct pim_upstream *up)
 {
        struct interface *ifp;
        struct listnode *node;
@@ -850,7 +868,7 @@ int pim_upstream_evaluate_join_desired(struct pim_upstream *up)
        struct pim_upstream *starup = up->parent;
        int ret = 0;
 
-       for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT), node, ifp)) {
+       for (ALL_LIST_ELEMENTS_RO(vrf_iflist(pim->vrf_id), node, ifp)) {
                if (!ifp->info)
                        continue;
 
@@ -874,14 +892,15 @@ int pim_upstream_evaluate_join_desired(struct pim_upstream *up)
 /*
   See also pim_upstream_evaluate_join_desired() above.
 */
-void pim_upstream_update_join_desired(struct pim_upstream *up)
+void pim_upstream_update_join_desired(struct pim_instance *pim,
+                                     struct pim_upstream *up)
 {
        int was_join_desired; /* boolean */
        int is_join_desired;  /* boolean */
 
        was_join_desired = PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED(up->flags);
 
-       is_join_desired = pim_upstream_evaluate_join_desired(up);
+       is_join_desired = pim_upstream_evaluate_join_desired(pim, up);
        if (is_join_desired)
                PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED(up->flags);
        else
@@ -889,13 +908,13 @@ void pim_upstream_update_join_desired(struct pim_upstream *up)
 
        /* switched from false to true */
        if (is_join_desired && !was_join_desired) {
-               pim_upstream_switch(up, PIM_UPSTREAM_JOINED);
+               pim_upstream_switch(pim, up, PIM_UPSTREAM_JOINED);
                return;
        }
 
        /* switched from true to false */
        if (!is_join_desired && was_join_desired) {
-               pim_upstream_switch(up, PIM_UPSTREAM_NOTJOINED);
+               pim_upstream_switch(pim, up, PIM_UPSTREAM_NOTJOINED);
                return;
        }
 }
@@ -909,7 +928,8 @@ void pim_upstream_update_join_desired(struct pim_upstream *up)
   Join Timer is set to expire in more than t_override seconds, reset
   it so that it expires after t_override seconds.
 */
-void pim_upstream_rpf_genid_changed(struct in_addr neigh_addr)
+void pim_upstream_rpf_genid_changed(struct pim_instance *pim,
+                                   struct in_addr neigh_addr)
 {
        struct listnode *up_node;
        struct listnode *up_nextnode;
@@ -918,7 +938,7 @@ void pim_upstream_rpf_genid_changed(struct in_addr neigh_addr)
        /*
         * Scan all (S,G) upstreams searching for RPF'(S,G)=neigh_addr
         */
-       for (ALL_LIST_ELEMENTS(pim_upstream_list, up_node, up_nextnode, up)) {
+       for (ALL_LIST_ELEMENTS(pim->upstream_list, up_node, up_nextnode, up)) {
 
                if (PIM_DEBUG_TRACE) {
                        char neigh_str[INET_ADDRSTRLEN];
@@ -1020,7 +1040,8 @@ static void pim_upstream_update_assert_tracking_desired(struct pim_upstream *up)
 /* When kat is stopped CouldRegister goes to false so we need to
  * transition  the (S, G) on FHR to NI state and remove reg tunnel
  * from the OIL */
-static void pim_upstream_fhr_kat_expiry(struct pim_upstream *up)
+static void pim_upstream_fhr_kat_expiry(struct pim_instance *pim,
+                                       struct pim_upstream *up)
 {
        if (!PIM_UPSTREAM_FLAG_TEST_FHR(up->flags))
                return;
@@ -1032,7 +1053,7 @@ static void pim_upstream_fhr_kat_expiry(struct pim_upstream *up)
        /* stop reg-stop timer */
        THREAD_OFF(up->t_rs_timer);
        /* remove regiface from the OIL if it is there*/
-       pim_channel_del_oif(up->channel_oil, pim_regiface,
+       pim_channel_del_oif(up->channel_oil, pim->regiface,
                            PIM_OIF_FLAG_PROTO_PIM);
        /* clear the register state */
        up->reg_state = PIM_REG_NOINFO;
@@ -1065,10 +1086,12 @@ static void pim_upstream_fhr_kat_start(struct pim_upstream *up)
 static int pim_upstream_keep_alive_timer(struct thread *t)
 {
        struct pim_upstream *up;
+       struct pim_instance *pim;
 
        up = THREAD_ARG(t);
+       pim = up->channel_oil->pim;
 
-       if (I_am_RP(up->sg.grp)) {
+       if (I_am_RP(pim, up->sg.grp)) {
                pim_br_clear_pmbr(&up->sg);
                /*
                 * We need to do more here :)
@@ -1077,19 +1100,19 @@ static int pim_upstream_keep_alive_timer(struct thread *t)
        }
 
        /* source is no longer active - pull the SA from MSDP's cache */
-       pim_msdp_sa_local_del(&up->sg);
+       pim_msdp_sa_local_del(pim, &up->sg);
 
        /* if entry was created because of activity we need to deref it */
        if (PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up->flags)) {
-               pim_upstream_fhr_kat_expiry(up);
+               pim_upstream_fhr_kat_expiry(pim, up);
                if (PIM_DEBUG_TRACE)
                        zlog_debug("kat expired on %s; remove stream reference",
                                   up->sg_str);
                PIM_UPSTREAM_FLAG_UNSET_SRC_STREAM(up->flags);
-               pim_upstream_del(up, __PRETTY_FUNCTION__);
+               pim_upstream_del(pim, up, __PRETTY_FUNCTION__);
        } else if (PIM_UPSTREAM_FLAG_TEST_SRC_LHR(up->flags)) {
                PIM_UPSTREAM_FLAG_UNSET_SRC_LHR(up->flags);
-               pim_upstream_del(up, __PRETTY_FUNCTION__);
+               pim_upstream_del(pim, up, __PRETTY_FUNCTION__);
        }
 
        return 0;
@@ -1114,12 +1137,11 @@ void pim_upstream_keep_alive_timer_start(struct pim_upstream *up, uint32_t time)
 /* MSDP on RP needs to know if a source is registerable to this RP */
 static int pim_upstream_msdp_reg_timer(struct thread *t)
 {
-       struct pim_upstream *up;
-
-       up = THREAD_ARG(t);
+       struct pim_upstream *up = THREAD_ARG(t);
+       struct pim_instance *pim = up->channel_oil->pim;
 
        /* source is no longer active - pull the SA from MSDP's cache */
-       pim_msdp_sa_local_del(&up->sg);
+       pim_msdp_sa_local_del(pim, &up->sg);
        return 1;
 }
 void pim_upstream_msdp_reg_timer_start(struct pim_upstream *up)
@@ -1159,9 +1181,10 @@ void pim_upstream_msdp_reg_timer_start(struct pim_upstream *up)
  *  SwitchToSptDesired(S,G) return true once a single packet has been
  *  received for the source and group.
  */
-int pim_upstream_switch_to_spt_desired(struct prefix_sg *sg)
+int pim_upstream_switch_to_spt_desired(struct pim_instance *pim,
+                                      struct prefix_sg *sg)
 {
-       if (I_am_RP(sg->grp))
+       if (I_am_RP(pim, sg->grp))
                return 1;
 
        return 0;
@@ -1295,10 +1318,12 @@ const char *pim_reg_state2str(enum pim_reg_state reg_state, char *state_str)
 static int pim_upstream_register_stop_timer(struct thread *t)
 {
        struct pim_interface *pim_ifp;
+       struct pim_instance *pim;
        struct pim_upstream *up;
        struct pim_rpf *rpg;
        struct ip ip_hdr;
        up = THREAD_ARG(t);
+       pim = up->channel_oil->pim;
 
        if (PIM_DEBUG_TRACE) {
                char state_str[PIM_REG_STATE_STR_LEN];
@@ -1310,7 +1335,7 @@ static int pim_upstream_register_stop_timer(struct thread *t)
        switch (up->reg_state) {
        case PIM_REG_JOIN_PENDING:
                up->reg_state = PIM_REG_JOIN;
-               pim_channel_add_oif(up->channel_oil, pim_regiface,
+               pim_channel_add_oif(up->channel_oil, pim->regiface,
                                    PIM_OIF_FLAG_PROTO_PIM);
                break;
        case PIM_REG_JOIN:
@@ -1330,14 +1355,21 @@ static int pim_upstream_register_stop_timer(struct thread *t)
 
                if (((up->channel_oil->cc.lastused / 100)
                     > PIM_KEEPALIVE_PERIOD)
-                   && (I_am_RP(up->sg.grp))) {
+                   && (I_am_RP(pim_ifp->pim, up->sg.grp))) {
                        if (PIM_DEBUG_TRACE)
                                zlog_debug(
                                        "%s: Stop sending the register, because I am the RP and we haven't seen a packet in a while",
                                        __PRETTY_FUNCTION__);
                        return 0;
                }
-               rpg = RP(up->sg.grp);
+               rpg = RP(pim_ifp->pim, up->sg.grp);
+               if (!rpg) {
+                       if (PIM_DEBUG_TRACE)
+                               zlog_debug(
+                                       "%s: Cannot send register for %s no RPF to the RP",
+                                       __PRETTY_FUNCTION__, up->sg_str);
+                       return 0;
+               }
                memset(&ip_hdr, 0, sizeof(struct ip));
                ip_hdr.ip_p = PIM_IP_PROTO_PIM;
                ip_hdr.ip_hl = 5;
@@ -1380,7 +1412,8 @@ void pim_upstream_start_register_stop_timer(struct pim_upstream *up,
                         &up->t_rs_timer);
 }
 
-int pim_upstream_inherited_olist_decide(struct pim_upstream *up)
+int pim_upstream_inherited_olist_decide(struct pim_instance *pim,
+                                       struct pim_upstream *up)
 {
        struct interface *ifp;
        struct pim_interface *pim_ifp = NULL;
@@ -1397,10 +1430,10 @@ int pim_upstream_inherited_olist_decide(struct pim_upstream *up)
                                   __PRETTY_FUNCTION__, up->sg_str);
        }
        if (pim_ifp && !up->channel_oil)
-               up->channel_oil =
-                       pim_channel_oil_add(&up->sg, pim_ifp->mroute_vif_index);
+               up->channel_oil = pim_channel_oil_add(
+                       pim&up->sg, pim_ifp->mroute_vif_index);
 
-       for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT), node, ifp)) {
+       for (ALL_LIST_ELEMENTS_RO(vrf_iflist(pim->vrf_id), node, ifp)) {
                if (!ifp->info)
                        continue;
 
@@ -1445,9 +1478,10 @@ int pim_upstream_inherited_olist_decide(struct pim_upstream *up)
  * return 1 if there are any output interfaces
  * return 0 if there are not any output interfaces
  */
-int pim_upstream_inherited_olist(struct pim_upstream *up)
+int pim_upstream_inherited_olist(struct pim_instance *pim,
+                                struct pim_upstream *up)
 {
-       int output_intf = pim_upstream_inherited_olist_decide(up);
+       int output_intf = pim_upstream_inherited_olist_decide(pim, up);
 
        /*
         * If we have output_intf switch state to Join and work like normal
@@ -1456,7 +1490,7 @@ int pim_upstream_inherited_olist(struct pim_upstream *up)
         * incoming packets so we don't bother the other stuff!
         */
        if (output_intf)
-               pim_upstream_switch(up, PIM_UPSTREAM_JOINED);
+               pim_upstream_switch(pim, up, PIM_UPSTREAM_JOINED);
        else
                forward_on(up);
 
@@ -1474,7 +1508,7 @@ int pim_upstream_empty_inherited_olist(struct pim_upstream *up)
  * set and see if the new neighbor allows
  * the join to be sent
  */
-void pim_upstream_find_new_rpf(void)
+void pim_upstream_find_new_rpf(struct pim_instance *pim)
 {
        struct listnode *up_node;
        struct listnode *up_nextnode;
@@ -1483,36 +1517,36 @@ void pim_upstream_find_new_rpf(void)
        /*
         * Scan all (S,G) upstreams searching for RPF'(S,G)=neigh_addr
         */
-       for (ALL_LIST_ELEMENTS(pim_upstream_list, up_node, up_nextnode, up)) {
+       for (ALL_LIST_ELEMENTS(pim->upstream_list, up_node, up_nextnode, up)) {
                if (pim_rpf_addr_is_inaddr_any(&up->rpf)) {
                        if (PIM_DEBUG_TRACE)
                                zlog_debug(
                                        "Upstream %s without a path to send join, checking",
                                        up->sg_str);
-                       pim_rpf_update(up, NULL, 1);
+                       pim_rpf_update(pim, up, NULL, 1);
                }
        }
 }
 
-static unsigned int pim_upstream_hash_key(void *arg)
+unsigned int pim_upstream_hash_key(void *arg)
 {
        struct pim_upstream *up = (struct pim_upstream *)arg;
 
        return jhash_2words(up->sg.src.s_addr, up->sg.grp.s_addr, 0);
 }
 
-void pim_upstream_terminate(void)
+void pim_upstream_terminate(struct pim_instance *pim)
 {
-       if (pim_upstream_list)
-               list_delete(pim_upstream_list);
-       pim_upstream_list = NULL;
+       if (pim->upstream_list)
+               list_delete(pim->upstream_list);
+       pim->upstream_list = NULL;
 
-       if (pim_upstream_hash)
-               hash_free(pim_upstream_hash);
-       pim_upstream_hash = NULL;
+       if (pim->upstream_hash)
+               hash_free(pim->upstream_hash);
+       pim->upstream_hash = NULL;
 }
 
-static int pim_upstream_equal(const void *arg1, const void *arg2)
+int pim_upstream_equal(const void *arg1, const void *arg2)
 {
        const struct pim_upstream *up1 = (const struct pim_upstream *)arg1;
        const struct pim_upstream *up2 = (const struct pim_upstream *)arg2;
@@ -1540,6 +1574,8 @@ static int pim_upstream_equal(const void *arg1, const void *arg2)
  */
 static bool pim_upstream_kat_start_ok(struct pim_upstream *up)
 {
+       struct pim_instance *pim = up->channel_oil->pim;
+
        /* "iif == RPF_interface(S)" check has to be done by the kernel or hw
         * so we will skip that here */
        if (pim_if_connected_to_source(up->rpf.source_nexthop.interface,
@@ -1559,7 +1595,7 @@ static bool pim_upstream_kat_start_ok(struct pim_upstream *up)
                 * MUST be
                 * removed to handle spt turn-arounds correctly in a 3-tier clos
                 */
-               if (I_am_RP(up->sg.grp))
+               if (I_am_RP(pim, up->sg.grp))
                        return true;
        }
 
@@ -1573,9 +1609,10 @@ static bool pim_upstream_kat_start_ok(struct pim_upstream *up)
 static void pim_upstream_sg_running(void *arg)
 {
        struct pim_upstream *up = (struct pim_upstream *)arg;
+       struct pim_instance *pim = up->channel_oil->pim;
 
        // No packet can have arrived here if this is the case
-       if (!up->channel_oil || !up->channel_oil->installed) {
+       if (!up->channel_oil->installed) {
                if (PIM_DEBUG_TRACE)
                        zlog_debug("%s: %s is not installed in mroute",
                                   __PRETTY_FUNCTION__, up->sg_str);
@@ -1595,7 +1632,7 @@ static void pim_upstream_sg_running(void *arg)
                        zlog_debug(
                                "%s: Handling unscanned inherited_olist for %s",
                                __PRETTY_FUNCTION__, up->sg_str);
-               pim_upstream_inherited_olist_decide(up);
+               pim_upstream_inherited_olist_decide(pim, up);
                up->channel_oil->oil_inherited_rescan = 0;
        }
        pim_mroute_update_counters(up->channel_oil);
@@ -1628,9 +1665,9 @@ static void pim_upstream_sg_running(void *arg)
                        PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up->flags);
                        pim_upstream_fhr_kat_start(up);
                }
-               pim_upstream_keep_alive_timer_start(up, qpim_keep_alive_time);
+               pim_upstream_keep_alive_timer_start(up, pim->keep_alive_time);
        } else if (PIM_UPSTREAM_FLAG_TEST_SRC_LHR(up->flags))
-               pim_upstream_keep_alive_timer_start(up, qpim_keep_alive_time);
+               pim_upstream_keep_alive_timer_start(up, pim->keep_alive_time);
 
        if (up->sptbit != PIM_UPSTREAM_SPTBIT_TRUE) {
                pim_upstream_set_sptbit(up, up->rpf.source_nexthop.interface);
@@ -1638,29 +1675,30 @@ static void pim_upstream_sg_running(void *arg)
        return;
 }
 
-void pim_upstream_add_lhr_star_pimreg(void)
+void pim_upstream_add_lhr_star_pimreg(struct pim_instance *pim)
 {
        struct pim_upstream *up;
        struct listnode *node;
 
-       for (ALL_LIST_ELEMENTS_RO(pim_upstream_list, node, up)) {
+       for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, node, up)) {
                if (up->sg.src.s_addr != INADDR_ANY)
                        continue;
 
                if (!PIM_UPSTREAM_FLAG_TEST_SRC_IGMP(up->flags))
                        continue;
 
-               pim_channel_add_oif(up->channel_oil, pim_regiface,
+               pim_channel_add_oif(up->channel_oil, pim->regiface,
                                    PIM_OIF_FLAG_PROTO_IGMP);
        }
 }
 
-void pim_upstream_spt_prefix_list_update(struct prefix_list *pl)
+void pim_upstream_spt_prefix_list_update(struct pim_instance *pim,
+                                        struct prefix_list *pl)
 {
        const char *pname = prefix_list_name(pl);
 
-       if (pimg->spt.plist && strcmp(pimg->spt.plist, pname) == 0) {
-               pim_upstream_remove_lhr_star_pimreg(pname);
+       if (pim->spt.plist && strcmp(pim->spt.plist, pname) == 0) {
+               pim_upstream_remove_lhr_star_pimreg(pim, pname);
        }
 }
 
@@ -1676,7 +1714,8 @@ void pim_upstream_spt_prefix_list_update(struct prefix_list *pl)
  * the interface
  *
  */
-void pim_upstream_remove_lhr_star_pimreg(const char *nlist)
+void pim_upstream_remove_lhr_star_pimreg(struct pim_instance *pim,
+                                        const char *nlist)
 {
        struct pim_upstream *up;
        struct listnode *node;
@@ -1689,7 +1728,7 @@ void pim_upstream_remove_lhr_star_pimreg(const char *nlist)
        g.family = AF_INET;
        g.prefixlen = IPV4_MAX_PREFIXLEN;
 
-       for (ALL_LIST_ELEMENTS_RO(pim_upstream_list, node, up)) {
+       for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, node, up)) {
                if (up->sg.src.s_addr != INADDR_ANY)
                        continue;
 
@@ -1697,30 +1736,35 @@ void pim_upstream_remove_lhr_star_pimreg(const char *nlist)
                        continue;
 
                if (!nlist) {
-                       pim_channel_del_oif(up->channel_oil, pim_regiface,
+                       pim_channel_del_oif(up->channel_oil, pim->regiface,
                                            PIM_OIF_FLAG_PROTO_IGMP);
                        continue;
                }
                g.u.prefix4 = up->sg.grp;
                apply_new = prefix_list_apply(np, &g);
                if (apply_new == PREFIX_DENY)
-                       pim_channel_add_oif(up->channel_oil, pim_regiface,
+                       pim_channel_add_oif(up->channel_oil, pim->regiface,
                                            PIM_OIF_FLAG_PROTO_IGMP);
                else
-                       pim_channel_del_oif(up->channel_oil, pim_regiface,
+                       pim_channel_del_oif(up->channel_oil, pim->regiface,
                                            PIM_OIF_FLAG_PROTO_IGMP);
        }
 }
 
-void pim_upstream_init(void)
+void pim_upstream_init(struct pim_instance *pim)
 {
-       pim_upstream_sg_wheel =
+       char hash_name[64];
+
+       pim->upstream_sg_wheel =
                wheel_init(master, 31000, 100, pim_upstream_hash_key,
                           pim_upstream_sg_running);
-       pim_upstream_hash = hash_create_size(8192, pim_upstream_hash_key,
-                                            pim_upstream_equal, NULL);
 
-       pim_upstream_list = list_new();
-       pim_upstream_list->del = (void (*)(void *))pim_upstream_free;
-       pim_upstream_list->cmp = pim_upstream_compare;
+       snprintf(hash_name, 64, "PIM %s Upstream Hash",
+                pim->vrf->name);
+       pim->upstream_hash = hash_create_size(8192, pim_upstream_hash_key,
+                                             pim_upstream_equal, hash_name);
+
+       pim->upstream_list = list_new();
+       pim->upstream_list->del = (void (*)(void *))pim_upstream_free;
+       pim->upstream_list->cmp = pim_upstream_compare;
 }
index b6a9729f0f5680d548fc57a9ab187811be9cdeb6..b75a5b9df376e74cfaab7c02096f08008ea3864e 100644 (file)
@@ -119,7 +119,7 @@ struct pim_upstream {
         */
        struct thread *t_rs_timer;
 #define PIM_REGISTER_SUPPRESSION_PERIOD (60)
-#define PIM_REGISTER_PROBE_PERIOD       (15)
+#define PIM_REGISTER_PROBE_PERIOD        (5)
 
        /*
         * KAT(S,G)
@@ -137,26 +137,29 @@ struct pim_upstream {
        int64_t state_transition; /* Record current state uptime */
 };
 
-struct list *pim_upstream_list;
-struct hash *pim_upstream_hash;
-
 void pim_upstream_free(struct pim_upstream *up);
-struct pim_upstream *pim_upstream_find(struct prefix_sg *sg);
+struct pim_upstream *pim_upstream_find(struct pim_instance *pim,
+                                      struct prefix_sg *sg);
 struct pim_upstream *pim_upstream_find_or_add(struct prefix_sg *sg,
                                              struct interface *ifp, int flags,
                                              const char *name);
-struct pim_upstream *pim_upstream_add(struct prefix_sg *sg,
+struct pim_upstream *pim_upstream_add(struct pim_instance *pim,
+                                     struct prefix_sg *sg,
                                      struct interface *ifp, int flags,
-                                     const char *name);
+                                     const char *name,
+                                     struct pim_ifchannel *ch);
 void pim_upstream_ref(struct pim_upstream *up, int flags, const char *name);
-struct pim_upstream *pim_upstream_del(struct pim_upstream *up,
+struct pim_upstream *pim_upstream_del(struct pim_instance *pim,
+                                     struct pim_upstream *up,
                                      const char *name);
 
-int pim_upstream_evaluate_join_desired(struct pim_upstream *up);
+int pim_upstream_evaluate_join_desired(struct pim_instance *pim,
+                                      struct pim_upstream *up);
 int pim_upstream_evaluate_join_desired_interface(struct pim_upstream *up,
                                                 struct pim_ifchannel *ch,
                                                 struct pim_ifchannel *starch);
-void pim_upstream_update_join_desired(struct pim_upstream *up);
+void pim_upstream_update_join_desired(struct pim_instance *pim,
+                                     struct pim_upstream *up);
 
 void pim_upstream_join_suppress(struct pim_upstream *up,
                                struct in_addr rpf_addr, int holdtime);
@@ -166,7 +169,8 @@ void pim_upstream_join_timer_decrease_to_t_override(const char *debug_label,
 
 void pim_upstream_join_timer_restart(struct pim_upstream *up,
                                     struct pim_rpf *old);
-void pim_upstream_rpf_genid_changed(struct in_addr neigh_addr);
+void pim_upstream_rpf_genid_changed(struct pim_instance *pim,
+                                   struct in_addr neigh_addr);
 void pim_upstream_rpf_interface_changed(struct pim_upstream *up,
                                        struct interface *old_rpf_ifp);
 
@@ -176,8 +180,9 @@ void pim_upstream_update_my_assert_metric(struct pim_upstream *up);
 void pim_upstream_keep_alive_timer_start(struct pim_upstream *up,
                                         uint32_t time);
 
-int pim_upstream_switch_to_spt_desired(struct prefix_sg *sg);
-#define SwitchToSptDesired(sg) pim_upstream_switch_to_spt_desired (sg)
+int pim_upstream_switch_to_spt_desired(struct pim_instance *pim,
+                                      struct prefix_sg *sg);
+#define SwitchToSptDesired(pim, sg) pim_upstream_switch_to_spt_desired (pim, sg)
 int pim_upstream_is_sg_rpt(struct pim_upstream *up);
 
 void pim_upstream_set_sptbit(struct pim_upstream *up,
@@ -188,29 +193,36 @@ void pim_upstream_start_register_stop_timer(struct pim_upstream *up,
 
 void pim_upstream_send_join(struct pim_upstream *up);
 
-void pim_upstream_switch(struct pim_upstream *up,
+void pim_upstream_switch(struct pim_instance *pim, struct pim_upstream *up,
                         enum pim_upstream_state new_state);
 
 const char *pim_upstream_state2str(enum pim_upstream_state join_state);
 #define PIM_REG_STATE_STR_LEN 12
 const char *pim_reg_state2str(enum pim_reg_state state, char *state_str);
 
-int pim_upstream_inherited_olist_decide(struct pim_upstream *up);
-int pim_upstream_inherited_olist(struct pim_upstream *up);
+int pim_upstream_inherited_olist_decide(struct pim_instance *pim,
+                                       struct pim_upstream *up);
+int pim_upstream_inherited_olist(struct pim_instance *pim,
+                                struct pim_upstream *up);
 int pim_upstream_empty_inherited_olist(struct pim_upstream *up);
 
-void pim_upstream_find_new_rpf(void);
+void pim_upstream_find_new_rpf(struct pim_instance *pim);
 void pim_upstream_msdp_reg_timer_start(struct pim_upstream *up);
 
-void pim_upstream_init(void);
-void pim_upstream_terminate(void);
+void pim_upstream_init(struct pim_instance *pim);
+void pim_upstream_terminate(struct pim_instance *pim);
 
 void join_timer_start(struct pim_upstream *up);
 int pim_upstream_compare(void *arg1, void *arg2);
-void pim_upstream_register_reevaluate(void);
+void pim_upstream_register_reevaluate(struct pim_instance *pim);
+
+void pim_upstream_add_lhr_star_pimreg(struct pim_instance *pim);
+void pim_upstream_remove_lhr_star_pimreg(struct pim_instance *pim,
+                                        const char *nlist);
 
-void pim_upstream_add_lhr_star_pimreg(void);
-void pim_upstream_remove_lhr_star_pimreg(const char *nlist);
+void pim_upstream_spt_prefix_list_update(struct pim_instance *pim,
+                                        struct prefix_list *pl);
 
-void pim_upstream_spt_prefix_list_update(struct prefix_list *pl);
+unsigned int pim_upstream_hash_key(void *arg);
+int pim_upstream_equal(const void *arg1, const void *arg2);
 #endif /* PIM_UPSTREAM_H */
index c2e4b2a4625ff8f466226e7ce11641d096f764f7..820117a03a46ace6962bc47c452dd26d1de6bb7c 100644 (file)
@@ -107,7 +107,8 @@ int pim_is_group_224_0_0_0_24(struct in_addr group_addr)
        struct prefix group;
 
        if (first) {
-               str2prefix("224.0.0.0/24", &group_224);
+               if (!str2prefix("224.0.0.0/24", &group_224))
+                       return 0;
                first = 0;
        }
 
@@ -125,7 +126,8 @@ int pim_is_group_224_4(struct in_addr group_addr)
        struct prefix group;
 
        if (first) {
-               str2prefix("224.0.0.0/4", &group_all);
+               if (!str2prefix("224.0.0.0/4", &group_all))
+                       return 0;
                first = 0;
        }
 
index a787767911c8ad3036a3a025f02e0a4c0b7f1dba..8914f6eb00518107788dd9c8994136cf25b30856 100644 (file)
@@ -139,74 +139,92 @@ int pim_debug_config_write(struct vty *vty)
                ++writes;
        }
 
+       if (PIM_DEBUG_PIM_NHT) {
+               vty_out(vty, "debug pim nht\n");
+               ++writes;
+       }
+
        return writes;
 }
 
-int pim_global_config_write(struct vty *vty)
+int pim_global_config_write_worker(struct pim_instance *pim, struct vty *vty)
 {
        int writes = 0;
-       struct pim_ssm *ssm = pimg->ssm_info;
+       struct pim_ssm *ssm = pim->ssm_info;
+       char spaces[10];
+
+       if (pim->vrf_id == VRF_DEFAULT)
+               sprintf(spaces, "%s", "");
+       else
+               sprintf(spaces, "%s", " ");
 
-       writes += pim_msdp_config_write(vty);
+       writes += pim_msdp_config_write_helper(pim, vty, spaces);
 
-       if (!pimg->send_v6_secondary) {
-               vty_out(vty, "no ip pim send-v6-secondary\n");
+       if (!pim->send_v6_secondary) {
+               vty_out(vty, "%sno ip pim send-v6-secondary\n", spaces);
                ++writes;
        }
 
-       writes += pim_rp_config_write(vty);
+       writes += pim_rp_config_write(pim, vty, spaces);
 
        if (qpim_register_suppress_time
            != PIM_REGISTER_SUPPRESSION_TIME_DEFAULT) {
-               vty_out(vty, "ip pim register-suppress-time %d\n",
+               vty_out(vty, "%sip pim register-suppress-time %d\n", spaces,
                        qpim_register_suppress_time);
                ++writes;
        }
        if (qpim_t_periodic != PIM_DEFAULT_T_PERIODIC) {
-               vty_out(vty, "ip pim join-prune-interval %d\n",
+               vty_out(vty, "%sip pim join-prune-interval %d\n", spaces,
                        qpim_t_periodic);
                ++writes;
        }
-       if (qpim_keep_alive_time != PIM_KEEPALIVE_PERIOD) {
-               vty_out(vty, "ip pim keep-alive-timer %d\n",
-                       qpim_keep_alive_time);
+       if (pim->keep_alive_time != PIM_KEEPALIVE_PERIOD) {
+               vty_out(vty, "%sip pim keep-alive-timer %d\n", spaces,
+                       pim->keep_alive_time);
+               ++writes;
+       }
+       if (pim->rp_keep_alive_time != (unsigned int)PIM_RP_KEEPALIVE_PERIOD) {
+               vty_out(vty, "%sip pim rp keep-alive-timer %d\n", spaces,
+                       pim->rp_keep_alive_time);
                ++writes;
        }
        if (qpim_packet_process != PIM_DEFAULT_PACKET_PROCESS) {
-               vty_out(vty, "ip pim packets %d\n", qpim_packet_process);
+               vty_out(vty, "%sip pim packets %d\n", spaces,
+                       qpim_packet_process);
                ++writes;
        }
        if (ssm->plist_name) {
-               vty_out(vty, "ip pim ssm prefix-list %s\n", ssm->plist_name);
+               vty_out(vty, "%sip pim ssm prefix-list %s\n", spaces,
+                       ssm->plist_name);
                ++writes;
        }
-       if (pimg->spt.switchover == PIM_SPT_INFINITY) {
-               if (pimg->spt.plist)
+       if (pim->spt.switchover == PIM_SPT_INFINITY) {
+               if (pim->spt.plist)
                        vty_out(vty,
-                               "ip pim spt-switchover infinity-and-beyond prefix-list %s\n",
-                               pimg->spt.plist);
+                               "%sip pim spt-switchover infinity-and-beyond prefix-list %s\n",
+                               spaces, pim->spt.plist);
                else
                        vty_out(vty,
-                               "ip pim spt-switchover infinity-and-beyond\n");
+                               "%sip pim spt-switchover infinity-and-beyond\n",
+                               spaces);
                ++writes;
        }
        if (qpim_ecmp_rebalance_enable) {
-               vty_out(vty, "ip pim ecmp rebalance\n");
+               vty_out(vty, "%sip pim ecmp rebalance\n", spaces);
                ++writes;
        } else if (qpim_ecmp_enable) {
-               vty_out(vty, "ip pim ecmp\n");
+               vty_out(vty, "%sip pim ecmp\n", spaces);
                ++writes;
        }
-       if (qpim_ssmpingd_list) {
+       if (pim->ssmpingd_list) {
                struct listnode *node;
                struct ssmpingd_sock *ss;
-               vty_out(vty, "!\n");
                ++writes;
-               for (ALL_LIST_ELEMENTS_RO(qpim_ssmpingd_list, node, ss)) {
+               for (ALL_LIST_ELEMENTS_RO(pim->ssmpingd_list, node, ss)) {
                        char source_str[INET_ADDRSTRLEN];
                        pim_inet4_dump("<src?>", ss->source_addr, source_str,
                                       sizeof(source_str));
-                       vty_out(vty, "ip ssmpingd %s\n", source_str);
+                       vty_out(vty, "%sip ssmpingd %s\n", spaces, source_str);
                        ++writes;
                }
        }
@@ -214,112 +232,140 @@ int pim_global_config_write(struct vty *vty)
        return writes;
 }
 
+int pim_global_config_write(struct vty *vty)
+{
+       return pim_global_config_write_worker(pimg, vty);
+}
+
 int pim_interface_config_write(struct vty *vty)
 {
-       int writes = 0;
+       struct pim_instance *pim;
        struct listnode *node;
        struct interface *ifp;
+       struct vrf *vrf;
+       int writes = 0;
 
-       for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT), node, ifp)) {
+       RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name)
+       {
+               pim = vrf->info;
+               if (!pim)
+                       continue;
 
-               /* IF name */
-               vty_out(vty, "interface %s\n", ifp->name);
-               ++writes;
+               for (ALL_LIST_ELEMENTS_RO(vrf_iflist(pim->vrf_id), node, ifp)) {
 
-               if (ifp->info) {
-                       struct pim_interface *pim_ifp = ifp->info;
+                       /* IF name */
+                       if (vrf->vrf_id == VRF_DEFAULT)
+                               vty_out(vty, "interface %s\n", ifp->name);
+                       else
+                               vty_out(vty, "interface %s vrf %s\n", ifp->name,
+                                       vrf->name);
+                       ++writes;
 
-                       if (PIM_IF_TEST_PIM(pim_ifp->options)) {
-                               vty_out(vty, " ip pim sm\n");
-                               ++writes;
-                       }
+                       if (ifp->info) {
+                               struct pim_interface *pim_ifp = ifp->info;
 
-                       /* IF ip pim drpriority */
-                       if (pim_ifp->pim_dr_priority
-                           != PIM_DEFAULT_DR_PRIORITY) {
-                               vty_out(vty, " ip pim drpriority %u\n",
-                                       pim_ifp->pim_dr_priority);
-                               ++writes;
-                       }
+                               if (PIM_IF_TEST_PIM(pim_ifp->options)) {
+                                       vty_out(vty, " ip pim sm\n");
+                                       ++writes;
+                               }
 
-                       /* IF ip pim hello */
-                       if (pim_ifp->pim_hello_period
-                           != PIM_DEFAULT_HELLO_PERIOD) {
-                               vty_out(vty, " ip pim hello %d",
-                                       pim_ifp->pim_hello_period);
-                               if (pim_ifp->pim_default_holdtime != -1)
-                                       vty_out(vty, " %d",
-                                               pim_ifp->pim_default_holdtime);
-                               vty_out(vty, "\n");
-                       }
+                               /* IF ip pim drpriority */
+                               if (pim_ifp->pim_dr_priority
+                                   != PIM_DEFAULT_DR_PRIORITY) {
+                                       vty_out(vty, " ip pim drpriority %u\n",
+                                               pim_ifp->pim_dr_priority);
+                                       ++writes;
+                               }
 
-                       /* update source */
-                       if (PIM_INADDR_ISNOT_ANY(pim_ifp->update_source)) {
-                               char src_str[INET_ADDRSTRLEN];
-                               pim_inet4_dump("<src?>", pim_ifp->update_source,
-                                              src_str, sizeof(src_str));
-                               vty_out(vty, " ip pim use-source %s\n",
-                                       src_str);
-                               ++writes;
-                       }
+                               /* IF ip pim hello */
+                               if (pim_ifp->pim_hello_period
+                                   != PIM_DEFAULT_HELLO_PERIOD) {
+                                       vty_out(vty, " ip pim hello %d",
+                                               pim_ifp->pim_hello_period);
+                                       if (pim_ifp->pim_default_holdtime != -1)
+                                               vty_out(vty, " %d",
+                                                       pim_ifp->pim_default_holdtime);
+                                       vty_out(vty, "\n");
+                               }
 
-                       /* IF ip igmp */
-                       if (PIM_IF_TEST_IGMP(pim_ifp->options)) {
-                               vty_out(vty, " ip igmp\n");
-                               ++writes;
-                       }
+                               /* update source */
+                               if (PIM_INADDR_ISNOT_ANY(
+                                           pim_ifp->update_source)) {
+                                       char src_str[INET_ADDRSTRLEN];
+                                       pim_inet4_dump("<src?>",
+                                                      pim_ifp->update_source,
+                                                      src_str,
+                                                      sizeof(src_str));
+                                       vty_out(vty, " ip pim use-source %s\n",
+                                               src_str);
+                                       ++writes;
+                               }
 
-                       /* ip igmp version */
-                       if (pim_ifp->igmp_version != IGMP_DEFAULT_VERSION) {
-                               vty_out(vty, " ip igmp version %d\n",
-                                       pim_ifp->igmp_version);
-                               ++writes;
-                       }
+                               /* IF ip igmp */
+                               if (PIM_IF_TEST_IGMP(pim_ifp->options)) {
+                                       vty_out(vty, " ip igmp\n");
+                                       ++writes;
+                               }
 
-                       /* IF ip igmp query-interval */
-                       if (pim_ifp->igmp_default_query_interval
-                           != IGMP_GENERAL_QUERY_INTERVAL) {
-                               vty_out(vty, " ip igmp query-interval %d\n",
-                                       pim_ifp->igmp_default_query_interval);
-                               ++writes;
-                       }
+                               /* ip igmp version */
+                               if (pim_ifp->igmp_version
+                                   != IGMP_DEFAULT_VERSION) {
+                                       vty_out(vty, " ip igmp version %d\n",
+                                               pim_ifp->igmp_version);
+                                       ++writes;
+                               }
 
-                       /* IF ip igmp query-max-response-time */
-                       if (pim_ifp->igmp_query_max_response_time_dsec
-                           != IGMP_QUERY_MAX_RESPONSE_TIME_DSEC) {
-                               vty_out(vty,
-                                       " ip igmp query-max-response-time %d\n",
-                                       pim_ifp->igmp_query_max_response_time_dsec);
-                               ++writes;
-                       }
+                               /* IF ip igmp query-interval */
+                               if (pim_ifp->igmp_default_query_interval
+                                   != IGMP_GENERAL_QUERY_INTERVAL) {
+                                       vty_out(vty,
+                                               " ip igmp query-interval %d\n",
+                                               pim_ifp->igmp_default_query_interval);
+                                       ++writes;
+                               }
 
-                       /* IF ip igmp join */
-                       if (pim_ifp->igmp_join_list) {
-                               struct listnode *node;
-                               struct igmp_join *ij;
-                               for (ALL_LIST_ELEMENTS_RO(
-                                            pim_ifp->igmp_join_list, node,
-                                            ij)) {
-                                       char group_str[INET_ADDRSTRLEN];
-                                       char source_str[INET_ADDRSTRLEN];
-                                       pim_inet4_dump("<grp?>", ij->group_addr,
-                                                      group_str,
-                                                      sizeof(group_str));
-                                       inet_ntop(AF_INET, &ij->source_addr,
-                                                 source_str,
-                                                 sizeof(source_str));
-                                       vty_out(vty, " ip igmp join %s %s\n",
-                                               group_str, source_str);
+                               /* IF ip igmp query-max-response-time */
+                               if (pim_ifp->igmp_query_max_response_time_dsec
+                                   != IGMP_QUERY_MAX_RESPONSE_TIME_DSEC) {
+                                       vty_out(vty,
+                                               " ip igmp query-max-response-time %d\n",
+                                               pim_ifp->igmp_query_max_response_time_dsec);
                                        ++writes;
                                }
-                       }
 
-                       writes += pim_static_write_mroute(vty, ifp);
+                               /* IF ip igmp join */
+                               if (pim_ifp->igmp_join_list) {
+                                       struct listnode *node;
+                                       struct igmp_join *ij;
+                                       for (ALL_LIST_ELEMENTS_RO(
+                                                    pim_ifp->igmp_join_list,
+                                                    node, ij)) {
+                                               char group_str[INET_ADDRSTRLEN];
+                                               char source_str
+                                                       [INET_ADDRSTRLEN];
+                                               pim_inet4_dump(
+                                                       "<grp?>",
+                                                       ij->group_addr,
+                                                       group_str,
+                                                       sizeof(group_str));
+                                               inet_ntop(AF_INET,
+                                                         &ij->source_addr,
+                                                         source_str,
+                                                         sizeof(source_str));
+                                               vty_out(vty,
+                                                       " ip igmp join %s %s\n",
+                                                       group_str, source_str);
+                                               ++writes;
+                                       }
+                               }
+
+                               writes +=
+                                       pim_static_write_mroute(pim, vty, ifp);
+                               pim_bfd_write_config(vty, ifp);
+                       }
+                       vty_out(vty, "!\n");
+                       ++writes;
                }
-               vty_out(vty, "!\n");
-               ++writes;
-               /* PIM BFD write */
-               pim_bfd_write_config(vty, ifp);
        }
 
        return writes;
index 54bab623dcded72e5f559c8af1b1d76cf95ee781..aef90cacc39a0061d57e74546a8aef59b2b3db62 100644 (file)
@@ -24,6 +24,7 @@
 
 int pim_debug_config_write(struct vty *vty);
 int pim_global_config_write(struct vty *vty);
+int pim_global_config_write_worker(struct pim_instance *pim, struct vty *vty);
 int pim_interface_config_write(struct vty *vty);
 
 #endif /* PIM_VTY_H */
index c5cca7d1b48b743d8e08958ec3032a2cc9148063..7b060aef4b6d5e06fe6deec7b3af688188ad2867 100644 (file)
@@ -80,8 +80,8 @@ static int pim_zebra_if_add(int command, struct zclient *zclient,
 
        if (PIM_DEBUG_ZEBRA) {
                zlog_debug(
-                       "%s: %s index %d flags %ld metric %d mtu %d operative %d",
-                       __PRETTY_FUNCTION__, ifp->name, ifp->ifindex,
+                       "%s: %s index %d(%d) flags %ld metric %d mtu %d operative %d",
+                       __PRETTY_FUNCTION__, ifp->name, ifp->ifindex, vrf_id,
                        (long)ifp->flags, ifp->metric, ifp->mtu,
                        if_is_operative(ifp));
        }
@@ -89,6 +89,23 @@ static int pim_zebra_if_add(int command, struct zclient *zclient,
        if (if_is_operative(ifp))
                pim_if_addr_add_all(ifp);
 
+       /*
+        * If we are a vrf device that is up, open up the pim_socket for
+        * listening
+        * to incoming pim messages irrelevant if the user has configured us
+        * for pim or not.
+        */
+       if (pim_if_is_vrf_device(ifp)) {
+               struct pim_interface *pim_ifp;
+
+               if (!ifp->info) {
+                       pim_ifp = pim_if_new(ifp, 0, 0);
+                       ifp->info = pim_ifp;
+               }
+
+               pim_sock_add(ifp);
+       }
+
        return 0;
 }
 
@@ -113,8 +130,8 @@ static int pim_zebra_if_del(int command, struct zclient *zclient,
 
        if (PIM_DEBUG_ZEBRA) {
                zlog_debug(
-                       "%s: %s index %d flags %ld metric %d mtu %d operative %d",
-                       __PRETTY_FUNCTION__, ifp->name, ifp->ifindex,
+                       "%s: %s index %d(%d) flags %ld metric %d mtu %d operative %d",
+                       __PRETTY_FUNCTION__, ifp->name, ifp->ifindex, vrf_id,
                        (long)ifp->flags, ifp->metric, ifp->mtu,
                        if_is_operative(ifp));
        }
@@ -129,6 +146,7 @@ static int pim_zebra_if_state_up(int command, struct zclient *zclient,
                                 zebra_size_t length, vrf_id_t vrf_id)
 {
        struct interface *ifp;
+       uint32_t table_id;
 
        /*
          zebra api notifies interface up/down events by using the same call
@@ -140,8 +158,8 @@ static int pim_zebra_if_state_up(int command, struct zclient *zclient,
 
        if (PIM_DEBUG_ZEBRA) {
                zlog_debug(
-                       "%s: %s index %d flags %ld metric %d mtu %d operative %d",
-                       __PRETTY_FUNCTION__, ifp->name, ifp->ifindex,
+                       "%s: %s index %d(%d) flags %ld metric %d mtu %d operative %d",
+                       __PRETTY_FUNCTION__, ifp->name, ifp->ifindex, vrf_id,
                        (long)ifp->flags, ifp->metric, ifp->mtu,
                        if_is_operative(ifp));
        }
@@ -154,6 +172,23 @@ static int pim_zebra_if_state_up(int command, struct zclient *zclient,
                pim_if_addr_add_all(ifp);
        }
 
+       /*
+        * If we have a pimreg device callback and it's for a specific
+        * table set the master appropriately
+        */
+       if (sscanf(ifp->name, "pimreg%d", &table_id) == 1) {
+               struct vrf *vrf;
+               RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name)
+               {
+                       if ((table_id == vrf->data.l.table_id)
+                           && (ifp->vrf_id != vrf->vrf_id)) {
+                               struct interface *master = if_lookup_by_name(
+                                       vrf->name, vrf->vrf_id);
+                               zclient_interface_set_master(zclient, master,
+                                                            ifp);
+                       }
+               }
+       }
        return 0;
 }
 
@@ -172,8 +207,8 @@ static int pim_zebra_if_state_down(int command, struct zclient *zclient,
 
        if (PIM_DEBUG_ZEBRA) {
                zlog_debug(
-                       "%s: %s index %d flags %ld metric %d mtu %d operative %d",
-                       __PRETTY_FUNCTION__, ifp->name, ifp->ifindex,
+                       "%s: %s index %d(%d) flags %ld metric %d mtu %d operative %d",
+                       __PRETTY_FUNCTION__, ifp->name, ifp->ifindex, vrf_id,
                        (long)ifp->flags, ifp->metric, ifp->mtu,
                        if_is_operative(ifp));
        }
@@ -252,11 +287,11 @@ static int pim_zebra_if_address_add(int command, struct zclient *zclient,
        if (PIM_DEBUG_ZEBRA) {
                char buf[BUFSIZ];
                prefix2str(p, buf, BUFSIZ);
-               zlog_debug("%s: %s connected IP address %s flags %u %s",
-                          __PRETTY_FUNCTION__, c->ifp->name, buf, c->flags,
-                          CHECK_FLAG(c->flags, ZEBRA_IFA_SECONDARY)
-                                  ? "secondary"
-                                  : "primary");
+               zlog_debug("%s: %s(%d) connected IP address %s flags %u %s",
+                          __PRETTY_FUNCTION__, c->ifp->name, vrf_id, buf,
+                          c->flags, CHECK_FLAG(c->flags, ZEBRA_IFA_SECONDARY)
+                                            ? "secondary"
+                                            : "primary");
 
 #ifdef PIM_DEBUG_IFADDR_DUMP
                dump_if_address(c->ifp);
@@ -292,8 +327,7 @@ static int pim_zebra_if_address_add(int command, struct zclient *zclient,
                struct listnode *ifnode;
                struct interface *ifp;
 
-               for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT), ifnode,
-                                         ifp)) {
+               for (ALL_LIST_ELEMENTS_RO(vrf_iflist(vrf_id), ifnode, ifp)) {
                        if (!if_is_loopback(ifp) && if_is_operative(ifp))
                                pim_if_addr_add_all(ifp);
                }
@@ -307,6 +341,8 @@ static int pim_zebra_if_address_del(int command, struct zclient *client,
 {
        struct connected *c;
        struct prefix *p;
+       struct vrf *vrf = vrf_lookup_by_id(vrf_id);
+       struct pim_instance *pim = vrf->info;
 
        /*
          zebra api notifies address adds/dels events by using the same call
@@ -326,8 +362,8 @@ static int pim_zebra_if_address_del(int command, struct zclient *client,
                        char buf[BUFSIZ];
                        prefix2str(p, buf, BUFSIZ);
                        zlog_debug(
-                               "%s: %s disconnected IP address %s flags %u %s",
-                               __PRETTY_FUNCTION__, c->ifp->name, buf,
+                               "%s: %s(%d) disconnected IP address %s flags %u %s",
+                               __PRETTY_FUNCTION__, c->ifp->name, vrf_id, buf,
                                c->flags,
                                CHECK_FLAG(c->flags, ZEBRA_IFA_SECONDARY)
                                        ? "secondary"
@@ -339,8 +375,8 @@ static int pim_zebra_if_address_del(int command, struct zclient *client,
                }
 
                pim_if_addr_del(c, 0);
-               pim_rp_setup();
-               pim_i_am_rp_re_evaluate();
+               pim_rp_setup(pim);
+               pim_i_am_rp_re_evaluate(pim);
        }
 
        connected_free(c);
@@ -355,99 +391,128 @@ static void scan_upstream_rpf_cache()
        struct listnode *node;
        struct pim_upstream *up;
        struct interface *ifp;
+       struct vrf *vrf;
+       struct pim_instance *pim;
 
-       for (ALL_LIST_ELEMENTS(pim_upstream_list, up_node, up_nextnode, up)) {
-               enum pim_rpf_result rpf_result;
-               struct pim_rpf old;
-               struct prefix nht_p;
+       RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name)
+       {
+               pim = vrf->info;
+               if (!pim)
+                       continue;
 
-               nht_p.family = AF_INET;
-               nht_p.prefixlen = IPV4_MAX_BITLEN;
-               nht_p.u.prefix4.s_addr = up->upstream_addr.s_addr;
-               pim_resolve_upstream_nh(&nht_p);
+               for (ALL_LIST_ELEMENTS(pim->upstream_list, up_node, up_nextnode,
+                                      up)) {
+                       enum pim_rpf_result rpf_result;
+                       struct pim_rpf old;
+                       struct prefix nht_p;
 
-               old.source_nexthop.interface = up->rpf.source_nexthop.interface;
-               old.source_nexthop.nbr = up->rpf.source_nexthop.nbr;
-               rpf_result = pim_rpf_update(up, &old, 0);
+                       nht_p.family = AF_INET;
+                       nht_p.prefixlen = IPV4_MAX_BITLEN;
+                       nht_p.u.prefix4.s_addr = up->upstream_addr.s_addr;
+                       pim_resolve_upstream_nh(pim, &nht_p);
 
-               if (rpf_result == PIM_RPF_FAILURE)
-                       continue;
+                       old.source_nexthop.interface =
+                               up->rpf.source_nexthop.interface;
+                       old.source_nexthop.nbr = up->rpf.source_nexthop.nbr;
+                       rpf_result = pim_rpf_update(pim, up, &old, 0);
 
-               if (rpf_result == PIM_RPF_CHANGED) {
-                       struct pim_neighbor *nbr;
-
-                       nbr = pim_neighbor_find(old.source_nexthop.interface,
-                                               old.rpf_addr.u.prefix4);
-                       if (nbr)
-                               pim_jp_agg_remove_group(nbr->upstream_jp_agg,
-                                                       up);
-
-                       /*
-                        * We have detected a case where we might need to rescan
-                        * the inherited o_list so do it.
-                        */
-                       if (up->channel_oil->oil_inherited_rescan) {
-                               pim_upstream_inherited_olist_decide(up);
-                               up->channel_oil->oil_inherited_rescan = 0;
-                       }
+                       if (rpf_result == PIM_RPF_FAILURE)
+                               continue;
 
-                       if (up->join_state == PIM_UPSTREAM_JOINED) {
-                               /*
-                                * If we come up real fast we can be here
-                                * where the mroute has not been installed
-                                * so install it.
-                                */
-                               if (!up->channel_oil->installed)
-                                       pim_mroute_add(up->channel_oil,
-                                                      __PRETTY_FUNCTION__);
+                       if (rpf_result == PIM_RPF_CHANGED) {
+                               struct pim_neighbor *nbr;
+
+                               nbr = pim_neighbor_find(
+                                       old.source_nexthop.interface,
+                                       old.rpf_addr.u.prefix4);
+                               if (nbr)
+                                       pim_jp_agg_remove_group(
+                                               nbr->upstream_jp_agg, up);
 
                                /*
-                                * RFC 4601: 4.5.7.  Sending (S,G) Join/Prune
-                                * Messages
-                                *
-                                * Transitions from Joined State
-                                *
-                                * RPF'(S,G) changes not due to an Assert
-                                *
-                                * The upstream (S,G) state machine remains in
-                                * Joined
-                                * state. Send Join(S,G) to the new upstream
-                                * neighbor, which is
-                                * the new value of RPF'(S,G).  Send Prune(S,G)
-                                * to the old
-                                * upstream neighbor, which is the old value of
-                                * RPF'(S,G).  Set
-                                * the Join Timer (JT) to expire after
-                                * t_periodic seconds.
+                                * We have detected a case where we might need
+                                * to rescan
+                                * the inherited o_list so do it.
                                 */
-                               pim_jp_agg_switch_interface(&old, &up->rpf, up);
-
-                               pim_upstream_join_timer_restart(up, &old);
-                       } /* up->join_state == PIM_UPSTREAM_JOINED */
+                               if (up->channel_oil->oil_inherited_rescan) {
+                                       pim_upstream_inherited_olist_decide(pim,
+                                                                           up);
+                                       up->channel_oil->oil_inherited_rescan =
+                                               0;
+                               }
 
-                       /* FIXME can join_desired actually be changed by
-                          pim_rpf_update()
-                          returning PIM_RPF_CHANGED ? */
-                       pim_upstream_update_join_desired(up);
+                               if (up->join_state == PIM_UPSTREAM_JOINED) {
+                                       /*
+                                        * If we come up real fast we can be
+                                        * here
+                                        * where the mroute has not been
+                                        * installed
+                                        * so install it.
+                                        */
+                                       if (!up->channel_oil->installed)
+                                               pim_mroute_add(
+                                                       up->channel_oil,
+                                                       __PRETTY_FUNCTION__);
+
+                                       /*
+                                        * RFC 4601: 4.5.7.  Sending (S,G)
+                                        * Join/Prune Messages
+                                        *
+                                        * Transitions from Joined State
+                                        *
+                                        * RPF'(S,G) changes not due to an
+                                        * Assert
+                                        *
+                                        * The upstream (S,G) state machine
+                                        * remains in Joined
+                                        * state. Send Join(S,G) to the new
+                                        * upstream neighbor, which is
+                                        * the new value of RPF'(S,G).  Send
+                                        * Prune(S,G) to the old
+                                        * upstream neighbor, which is the old
+                                        * value of RPF'(S,G).  Set
+                                        * the Join Timer (JT) to expire after
+                                        * t_periodic seconds.
+                                        */
+                                       pim_jp_agg_switch_interface(
+                                               &old, &up->rpf, up);
+
+                                       pim_upstream_join_timer_restart(up,
+                                                                       &old);
+                               } /* up->join_state == PIM_UPSTREAM_JOINED */
+
+                               /* FIXME can join_desired actually be changed by
+                                  pim_rpf_update()
+                                  returning PIM_RPF_CHANGED ? */
+                               pim_upstream_update_join_desired(pim, up);
+
+                       } /* PIM_RPF_CHANGED */
+
+               } /* for (qpim_upstream_list) */
+       }
 
-               } /* PIM_RPF_CHANGED */
+       RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name)
+       {
+               pim = vrf->info;
+               if (!pim)
+                       continue;
 
-       } /* for (qpim_upstream_list) */
+               for (ALL_LIST_ELEMENTS_RO(vrf_iflist(pim->vrf_id), ifnode, ifp))
+                       if (ifp->info) {
+                               struct pim_interface *pim_ifp = ifp->info;
+                               struct pim_iface_upstream_switch *us;
 
-       for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT), ifnode, ifp))
-               if (ifp->info) {
-                       struct pim_interface *pim_ifp = ifp->info;
-                       struct pim_iface_upstream_switch *us;
-
-                       for (ALL_LIST_ELEMENTS_RO(pim_ifp->upstream_switch_list,
-                                                 node, us)) {
-                               struct pim_rpf rpf;
-                               rpf.source_nexthop.interface = ifp;
-                               rpf.rpf_addr.u.prefix4 = us->address;
-                               pim_joinprune_send(&rpf, us->us);
-                               pim_jp_agg_clear_group(us->us);
+                               for (ALL_LIST_ELEMENTS_RO(
+                                            pim_ifp->upstream_switch_list,
+                                            node, us)) {
+                                       struct pim_rpf rpf;
+                                       rpf.source_nexthop.interface = ifp;
+                                       rpf.rpf_addr.u.prefix4 = us->address;
+                                       pim_joinprune_send(&rpf, us->us);
+                                       pim_jp_agg_clear_group(us->us);
+                               }
                        }
-               }
+       }
 }
 
 void pim_scan_individual_oil(struct channel_oil *c_oil, int in_vif_index)
@@ -456,7 +521,8 @@ void pim_scan_individual_oil(struct channel_oil *c_oil, int in_vif_index)
        int input_iface_vif_index;
        int old_vif_index;
 
-       if (!pim_rp_set_upstream_addr(&vif_source, c_oil->oil.mfcc_origin,
+       if (!pim_rp_set_upstream_addr(c_oil->pim, &vif_source,
+                                     c_oil->oil.mfcc_origin,
                                      c_oil->oil.mfcc_mcastgrp))
                return;
 
@@ -480,11 +546,11 @@ void pim_scan_individual_oil(struct channel_oil *c_oil, int in_vif_index)
                        pim_inet4_dump("<group?>", c_oil->oil.mfcc_mcastgrp,
                                       group_str, sizeof(group_str));
                        zlog_debug(
-                               "%s: channel_oil (%s, %s) upstream info is not present.",
+                               "%s: channel_oil (%s,%s) upstream info is not present.",
                                __PRETTY_FUNCTION__, source_str, group_str);
                }
                input_iface_vif_index = pim_ecmp_fib_lookup_if_vif_index(
-                       vif_source, &src, &grp);
+                       c_oil->pim, vif_source, &src, &grp);
        }
 
        if (input_iface_vif_index < 1) {
@@ -513,10 +579,10 @@ void pim_scan_individual_oil(struct channel_oil *c_oil, int in_vif_index)
        }
 
        if (PIM_DEBUG_ZEBRA) {
-               struct interface *old_iif =
-                       pim_if_find_by_vif_index(c_oil->oil.mfcc_parent);
-               struct interface *new_iif =
-                       pim_if_find_by_vif_index(input_iface_vif_index);
+               struct interface *old_iif = pim_if_find_by_vif_index(
+                       c_oil->pim, c_oil->oil.mfcc_parent);
+               struct interface *new_iif = pim_if_find_by_vif_index(
+                       c_oil->pim, input_iface_vif_index);
                char source_str[INET_ADDRSTRLEN];
                char group_str[INET_ADDRSTRLEN];
                pim_inet4_dump("<source?>", c_oil->oil.mfcc_origin, source_str,
@@ -532,8 +598,8 @@ void pim_scan_individual_oil(struct channel_oil *c_oil, int in_vif_index)
 
        /* new iif loops to existing oif ? */
        if (c_oil->oil.mfcc_ttls[input_iface_vif_index]) {
-               struct interface *new_iif =
-                       pim_if_find_by_vif_index(input_iface_vif_index);
+               struct interface *new_iif = pim_if_find_by_vif_index(
+                       c_oil->pim, input_iface_vif_index);
 
                if (PIM_DEBUG_ZEBRA) {
                        char source_str[INET_ADDRSTRLEN];
@@ -558,10 +624,10 @@ void pim_scan_individual_oil(struct channel_oil *c_oil, int in_vif_index)
        if (pim_mroute_add(c_oil, __PRETTY_FUNCTION__)) {
                if (PIM_DEBUG_MROUTE) {
                        /* just log warning */
-                       struct interface *old_iif =
-                               pim_if_find_by_vif_index(old_vif_index);
-                       struct interface *new_iif =
-                               pim_if_find_by_vif_index(input_iface_vif_index);
+                       struct interface *old_iif = pim_if_find_by_vif_index(
+                               c_oil->pim, old_vif_index);
+                       struct interface *new_iif = pim_if_find_by_vif_index(
+                               c_oil->pim, input_iface_vif_index);
                        char source_str[INET_ADDRSTRLEN];
                        char group_str[INET_ADDRSTRLEN];
                        pim_inet4_dump("<source?>", c_oil->oil.mfcc_origin,
@@ -580,28 +646,44 @@ void pim_scan_individual_oil(struct channel_oil *c_oil, int in_vif_index)
        }
 }
 
-void pim_scan_oil()
+void pim_scan_oil(struct pim_instance *pim_matcher)
 {
        struct listnode *node;
        struct listnode *nextnode;
        struct channel_oil *c_oil;
        ifindex_t ifindex;
        int vif_index = 0;
+       struct vrf *vrf;
+       struct pim_instance *pim;
 
        qpim_scan_oil_last = pim_time_monotonic_sec();
        ++qpim_scan_oil_events;
 
-       for (ALL_LIST_ELEMENTS(pim_channel_oil_list, node, nextnode, c_oil)) {
-               if (c_oil->up && c_oil->up->rpf.source_nexthop.interface) {
-                       ifindex = c_oil->up->rpf.source_nexthop
-                                         .interface->ifindex;
-                       vif_index = pim_if_find_vifindex_by_ifindex(ifindex);
-                       /* Pass Current selected NH vif index to mroute download
-                        */
-                       if (vif_index)
-                               pim_scan_individual_oil(c_oil, vif_index);
-               } else
-                       pim_scan_individual_oil(c_oil, 0);
+       RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name)
+       {
+               pim = vrf->info;
+               if (!pim)
+                       continue;
+
+               if (pim_matcher && pim != pim_matcher)
+                       continue;
+
+               for (ALL_LIST_ELEMENTS(pim->channel_oil_list, node, nextnode,
+                                      c_oil)) {
+                       if (c_oil->up
+                           && c_oil->up->rpf.source_nexthop.interface) {
+                               ifindex = c_oil->up->rpf.source_nexthop
+                                                 .interface->ifindex;
+                               vif_index = pim_if_find_vifindex_by_ifindex(
+                                       pim, ifindex);
+                               /* Pass Current selected NH vif index to mroute
+                                * download */
+                               if (vif_index)
+                                       pim_scan_individual_oil(c_oil,
+                                                               vif_index);
+                       } else
+                               pim_scan_individual_oil(c_oil, 0);
+               }
        }
 }
 
@@ -611,7 +693,7 @@ static int on_rpf_cache_refresh(struct thread *t)
        scan_upstream_rpf_cache();
 
        /* update kernel multicast forwarding cache (MFC) */
-       pim_scan_oil();
+       pim_scan_oil(NULL);
 
        qpim_rpf_cache_refresh_last = pim_time_monotonic_sec();
        ++qpim_rpf_cache_refresh_events;
@@ -649,22 +731,13 @@ static void pim_zebra_connected(struct zclient *zclient)
        /* Send the client registration */
        bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER);
 
-       zclient_send_reg_requests(zclient, VRF_DEFAULT);
+       zclient_send_reg_requests(zclient, pimg->vrf_id);
 }
 
 void pim_zebra_init(void)
 {
        int i;
 
-#ifdef HAVE_TCP_ZEBRA
-       zlog_notice(
-               "zclient update contacting ZEBRA daemon at socket TCP %s,%d",
-               "127.0.0.1", ZEBRA_PORT);
-#else
-       zlog_notice("zclient update contacting ZEBRA daemon at socket UNIX %s",
-                   zclient_serv_path_get());
-#endif
-
        /* Socket for receiving updates from Zebra daemon */
        zclient = zclient_new(master);
 
@@ -689,7 +762,7 @@ void pim_zebra_init(void)
        for (i = 0; i < ZEBRA_ROUTE_MAX; i++) {
                if (i == zclient->redist_default)
                        continue;
-               vrf_bitmap_set(zclient->redist[AFI_IP][i], VRF_DEFAULT);
+               vrf_bitmap_set(zclient->redist[AFI_IP][i], pimg->vrf_id);
                ;
                if (PIM_DEBUG_PIM_TRACE) {
                        zlog_debug("%s: requesting redistribution for %s (%i)",
@@ -700,7 +773,7 @@ void pim_zebra_init(void)
 
        /* Request default information */
        zclient_redistribute_default(ZEBRA_REDISTRIBUTE_DEFAULT_ADD, zclient,
-                                    VRF_DEFAULT);
+                                    pimg->vrf_id);
 
        if (PIM_DEBUG_PIM_TRACE) {
                zlog_info("%s: requesting default information redistribution",
@@ -713,7 +786,8 @@ void pim_zebra_init(void)
        zclient_lookup_new();
 }
 
-void igmp_anysource_forward_start(struct igmp_group *group)
+void igmp_anysource_forward_start(struct pim_instance *pim,
+                                 struct igmp_group *group)
 {
        struct igmp_source *source;
        struct in_addr src_addr = {.s_addr = 0};
@@ -728,7 +802,7 @@ void igmp_anysource_forward_start(struct igmp_group *group)
                return;
        }
 
-       igmp_source_forward_start(source);
+       igmp_source_forward_start(pim, source);
 }
 
 void igmp_anysource_forward_stop(struct igmp_group *group)
@@ -741,7 +815,8 @@ void igmp_anysource_forward_stop(struct igmp_group *group)
                igmp_source_forward_stop(source);
 }
 
-static void igmp_source_forward_reevaluate_one(struct igmp_source *source)
+static void igmp_source_forward_reevaluate_one(struct pim_instance *pim,
+                                              struct igmp_source *source)
 {
        struct prefix_sg sg;
        struct igmp_group *group = source->source_group;
@@ -756,7 +831,7 @@ static void igmp_source_forward_reevaluate_one(struct igmp_source *source)
        sg.grp = group->group_addr;
 
        ch = pim_ifchannel_find(group->group_igmp_sock->interface, &sg);
-       if (pim_is_grp_ssm(group->group_addr)) {
+       if (pim_is_grp_ssm(pim, group->group_addr)) {
                /* If SSM group withdraw local membership */
                if (ch
                    && (ch->local_ifmembership == PIM_IFMEMBERSHIP_INCLUDE)) {
@@ -785,39 +860,51 @@ void igmp_source_forward_reevaluate_all(void)
 {
        struct listnode *ifnode;
        struct interface *ifp;
+       struct vrf *vrf;
+       struct pim_instance *pim;
 
-       for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT), ifnode, ifp)) {
-               struct pim_interface *pim_ifp = ifp->info;
-               struct listnode *sock_node;
-               struct igmp_sock *igmp;
-
-               if (!pim_ifp)
+       RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name)
+       {
+               pim = vrf->info;
+               if (!pim)
                        continue;
 
-               /* scan igmp sockets */
-               for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_socket_list, sock_node,
-                                         igmp)) {
-                       struct listnode *grpnode;
-                       struct igmp_group *grp;
-
-                       /* scan igmp groups */
-                       for (ALL_LIST_ELEMENTS_RO(igmp->igmp_group_list,
-                                                 grpnode, grp)) {
-                               struct listnode *srcnode;
-                               struct igmp_source *src;
-
-                               /* scan group sources */
-                               for (ALL_LIST_ELEMENTS_RO(
-                                            grp->group_source_list, srcnode,
-                                            src)) {
-                                       igmp_source_forward_reevaluate_one(src);
-                               } /* scan group sources */
-                       }        /* scan igmp groups */
-               }                 /* scan igmp sockets */
-       }                         /* scan interfaces */
+               for (ALL_LIST_ELEMENTS_RO(vrf_iflist(pim->vrf_id), ifnode,
+                                         ifp)) {
+                       struct pim_interface *pim_ifp = ifp->info;
+                       struct listnode *sock_node;
+                       struct igmp_sock *igmp;
+
+                       if (!pim_ifp)
+                               continue;
+
+                       /* scan igmp sockets */
+                       for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_socket_list,
+                                                 sock_node, igmp)) {
+                               struct listnode *grpnode;
+                               struct igmp_group *grp;
+
+                               /* scan igmp groups */
+                               for (ALL_LIST_ELEMENTS_RO(igmp->igmp_group_list,
+                                                         grpnode, grp)) {
+                                       struct listnode *srcnode;
+                                       struct igmp_source *src;
+
+                                       /* scan group sources */
+                                       for (ALL_LIST_ELEMENTS_RO(
+                                                    grp->group_source_list,
+                                                    srcnode, src)) {
+                                               igmp_source_forward_reevaluate_one(
+                                                       pim, src);
+                                       } /* scan group sources */
+                               }        /* scan igmp groups */
+                       }                 /* scan igmp sockets */
+               }                         /* scan interfaces */
+       }
 }
 
-void igmp_source_forward_start(struct igmp_source *source)
+void igmp_source_forward_start(struct pim_instance *pim,
+                              struct igmp_source *source)
 {
        struct igmp_group *group;
        struct prefix_sg sg;
@@ -849,13 +936,12 @@ void igmp_source_forward_start(struct igmp_source *source)
                struct in_addr vif_source;
                struct pim_interface *pim_oif;
                struct prefix nht_p, src, grp;
-               int ret = 0;
                struct pim_nexthop_cache out_pnc;
                struct pim_nexthop nexthop;
                struct pim_upstream *up = NULL;
 
-               if (!pim_rp_set_upstream_addr(&vif_source, source->source_addr,
-                                             sg.grp))
+               if (!pim_rp_set_upstream_addr(pim, &vif_source,
+                                             source->source_addr, sg.grp))
                        return;
 
                /* Register addr with Zebra NHT */
@@ -871,22 +957,21 @@ void igmp_source_forward_start(struct igmp_source *source)
                grp.prefixlen = IPV4_MAX_BITLEN;
                grp.u.prefix4 = sg.grp;
 
-               if ((ret = pim_find_or_track_nexthop(&nht_p, NULL, NULL,
-                                                    &out_pnc))
-                   == 1) {
+               if (pim_find_or_track_nexthop(pim, &nht_p, NULL, NULL,
+                                             &out_pnc)) {
                        if (out_pnc.nexthop_num) {
-                               up = pim_upstream_find(&sg);
-                               memset(&nexthop, 0, sizeof(struct pim_nexthop));
+                               up = pim_upstream_find(pim, &sg);
+                               memset(&nexthop, 0, sizeof(nexthop));
                                if (up)
                                        memcpy(&nexthop,
                                               &up->rpf.source_nexthop,
                                               sizeof(struct pim_nexthop));
-                               // Compute PIM RPF using Cached nexthop
-                               pim_ecmp_nexthop_search(&out_pnc, &nexthop,
+                               pim_ecmp_nexthop_search(pim, &out_pnc, &nexthop,
                                                        &src, &grp, 0);
                                if (nexthop.interface)
                                        input_iface_vif_index =
                                                pim_if_find_vifindex_by_ifindex(
+                                                       pim,
                                                        nexthop.interface->ifindex);
                        } else {
                                if (PIM_DEBUG_ZEBRA) {
@@ -906,8 +991,8 @@ void igmp_source_forward_start(struct igmp_source *source)
                        }
                } else
                        input_iface_vif_index =
-                               pim_ecmp_fib_lookup_if_vif_index(vif_source,
-                                                                &src, &grp);
+                               pim_ecmp_fib_lookup_if_vif_index(
+                                       pim, vif_source, &src, &grp);
 
                if (PIM_DEBUG_ZEBRA) {
                        char buf2[INET_ADDRSTRLEN];
@@ -966,7 +1051,7 @@ void igmp_source_forward_start(struct igmp_source *source)
                }
 
                source->source_channel_oil =
-                       pim_channel_oil_add(&sg, input_iface_vif_index);
+                       pim_channel_oil_add(pim, &sg, input_iface_vif_index);
                if (!source->source_channel_oil) {
                        if (PIM_DEBUG_IGMP_TRACE) {
                                zlog_debug(
@@ -1072,6 +1157,11 @@ void pim_forward_start(struct pim_ifchannel *ch)
        struct pim_upstream *up = ch->upstream;
        uint32_t mask = PIM_OIF_FLAG_PROTO_PIM;
        int input_iface_vif_index = 0;
+       struct pim_instance *pim;
+       struct pim_interface *pim_ifp;
+
+       pim_ifp = ch->interface->info;
+       pim = pim_ifp->pim;
 
        if (PIM_DEBUG_PIM_TRACE) {
                char source_str[INET_ADDRSTRLEN];
@@ -1096,7 +1186,6 @@ void pim_forward_start(struct pim_ifchannel *ch)
            || (up->channel_oil
                && up->channel_oil->oil.mfcc_parent >= MAXVIFS)) {
                struct prefix nht_p, src, grp;
-               int ret = 0;
                struct pim_nexthop_cache out_pnc;
 
                /* Register addr with Zebra NHT */
@@ -1108,9 +1197,8 @@ void pim_forward_start(struct pim_ifchannel *ch)
                grp.u.prefix4 = up->sg.grp;
                memset(&out_pnc, 0, sizeof(struct pim_nexthop_cache));
 
-               if ((ret = pim_find_or_track_nexthop(&nht_p, NULL, NULL,
-                                                    &out_pnc))
-                   == 1) {
+               if (pim_find_or_track_nexthop(pim, &nht_p, NULL, NULL,
+                                             &out_pnc)) {
                        if (out_pnc.nexthop_num) {
                                src.family = AF_INET;
                                src.prefixlen = IPV4_MAX_BITLEN;
@@ -1121,11 +1209,12 @@ void pim_forward_start(struct pim_ifchannel *ch)
                                grp.u.prefix4 = up->sg.grp;
                                // Compute PIM RPF using Cached nexthop
                                if (pim_ecmp_nexthop_search(
-                                           &out_pnc, &up->rpf.source_nexthop,
-                                           &src, &grp, 0)
-                                   == 0)
+                                           pim, &out_pnc,
+                                           &up->rpf.source_nexthop, &src, &grp,
+                                           0))
                                        input_iface_vif_index =
                                                pim_if_find_vifindex_by_ifindex(
+                                                       pim,
                                                        up->rpf.source_nexthop
                                                                .interface->ifindex);
                                else {
@@ -1154,7 +1243,7 @@ void pim_forward_start(struct pim_ifchannel *ch)
                } else
                        input_iface_vif_index =
                                pim_ecmp_fib_lookup_if_vif_index(
-                                       up->upstream_addr, &src, &grp);
+                                       pim, up->upstream_addr, &src, &grp);
 
                if (input_iface_vif_index < 1) {
                        if (PIM_DEBUG_PIM_TRACE) {
@@ -1169,16 +1258,16 @@ void pim_forward_start(struct pim_ifchannel *ch)
                        return;
                }
                if (PIM_DEBUG_TRACE) {
-                       struct interface *in_intf =
-                               pim_if_find_by_vif_index(input_iface_vif_index);
+                       struct interface *in_intf = pim_if_find_by_vif_index(
+                               piminput_iface_vif_index);
                        zlog_debug(
                                "%s: Update channel_oil IIF %s VIFI %d entry %s ",
                                __PRETTY_FUNCTION__,
                                in_intf ? in_intf->name : "NIL",
                                input_iface_vif_index, up->sg_str);
                }
-               up->channel_oil =
-                       pim_channel_oil_add(&up->sg, input_iface_vif_index);
+               up->channel_oil = pim_channel_oil_add(pim, &up->sg,
+                                                     input_iface_vif_index);
                if (!up->channel_oil) {
                        if (PIM_DEBUG_PIM_TRACE)
                                zlog_debug(
@@ -1195,17 +1284,21 @@ void pim_forward_start(struct pim_ifchannel *ch)
        pim_channel_add_oif(up->channel_oil, ch->interface, mask);
 }
 
-void pim_forward_stop(struct pim_ifchannel *ch)
+void pim_forward_stop(struct pim_ifchannel *ch, bool install_it)
 {
        struct pim_upstream *up = ch->upstream;
 
        if (PIM_DEBUG_PIM_TRACE) {
-               zlog_debug("%s: (S,G)=%s oif=%s", __PRETTY_FUNCTION__,
-                          ch->sg_str, ch->interface->name);
+               zlog_debug("%s: (S,G)=%s oif=%s install_it: %d installed: %d",
+                          __PRETTY_FUNCTION__, ch->sg_str, ch->interface->name,
+                          install_it, up->channel_oil->installed);
        }
 
        pim_channel_del_oif(up->channel_oil, ch->interface,
                            PIM_OIF_FLAG_PROTO_PIM);
+
+       if (install_it && !up->channel_oil->installed)
+               pim_mroute_add(up->channel_oil, __PRETTY_FUNCTION__);
 }
 
 void pim_zebra_zclient_update(struct vty *vty)
index 9b5450d66a929069098ca6c9761b3c7461468d95..d9b17cb82d00766db1f02f109a53aecda62952b7 100644 (file)
@@ -30,17 +30,19 @@ void pim_zebra_init(void);
 void pim_zebra_zclient_update(struct vty *vty);
 
 void pim_scan_individual_oil(struct channel_oil *c_oil, int in_vif_index);
-void pim_scan_oil(void);
+void pim_scan_oil(struct pim_instance *pim_matcher);
 
-void igmp_anysource_forward_start(struct igmp_group *group);
+void igmp_anysource_forward_start(struct pim_instance *pim,
+                                 struct igmp_group *group);
 void igmp_anysource_forward_stop(struct igmp_group *group);
 
-void igmp_source_forward_start(struct igmp_source *source);
+void igmp_source_forward_start(struct pim_instance *pim,
+                              struct igmp_source *source);
 void igmp_source_forward_stop(struct igmp_source *source);
 void igmp_source_forward_reevaluate_all(void);
 
 void pim_forward_start(struct pim_ifchannel *ch);
-void pim_forward_stop(struct pim_ifchannel *ch);
+void pim_forward_stop(struct pim_ifchannel *ch, bool install_it);
 
 void sched_rpf_cache_refresh(void);
 struct zclient *pim_zebra_zclient_get(void);
index 027b18e123bac6f5f0dd9bfed31f74c4ba140e00..df8ad4e428c1a5e0789f9cd61018a5f3e54d6206 100644 (file)
@@ -135,13 +135,13 @@ void zclient_lookup_new(void)
                    __PRETTY_FUNCTION__);
 }
 
-static int zclient_read_nexthop(struct zclient *zlookup,
+static int zclient_read_nexthop(struct pim_instance *pim,
+                               struct zclient *zlookup,
                                struct pim_zlookup_nexthop nexthop_tab[],
                                const int tab_size, struct in_addr addr)
 {
        int num_ifindex = 0;
        struct stream *s;
-       const uint16_t MIN_LEN = 10; /* getipv4=4 getc=1 getl=4 getc=1 */
        uint16_t length;
        u_char marker;
        u_char version;
@@ -153,10 +153,11 @@ static int zclient_read_nexthop(struct zclient *zlookup,
        int nexthop_num;
        int i, err;
 
-       if (PIM_DEBUG_PIM_TRACE_DETAIL) {
+       if (PIM_DEBUG_PIM_NHT_DETAIL) {
                char addr_str[INET_ADDRSTRLEN];
                pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
-               zlog_debug("%s: addr=%s", __PRETTY_FUNCTION__, addr_str);
+               zlog_debug("%s: addr=%s(%s)", __PRETTY_FUNCTION__, addr_str,
+                          pim->vrf->name);
        }
 
        s = zlookup->ibuf;
@@ -166,19 +167,11 @@ static int zclient_read_nexthop(struct zclient *zlookup,
                err = zclient_read_header(s, zlookup->sock, &length, &marker,
                                          &version, &vrf_id, &command);
                if (err < 0) {
-                       zlog_err("%s %s: zclient_read_header() failed",
-                                __FILE__, __PRETTY_FUNCTION__);
+                       zlog_err("%s: zclient_read_header() failed",
+                                __PRETTY_FUNCTION__);
                        zclient_lookup_failed(zlookup);
                        return -1;
                }
-
-               if (length < MIN_LEN) {
-                       zlog_err(
-                               "%s %s: failure reading zclient lookup socket: len=%d < MIN_LEN=%d",
-                               __FILE__, __PRETTY_FUNCTION__, length, MIN_LEN);
-                       zclient_lookup_failed(zlookup);
-                       return -2;
-               }
        }
 
        raddr.s_addr = stream_get_ipv4(s);
@@ -188,8 +181,9 @@ static int zclient_read_nexthop(struct zclient *zlookup,
                char raddr_str[INET_ADDRSTRLEN];
                pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
                pim_inet4_dump("<raddr?>", raddr, raddr_str, sizeof(raddr_str));
-               zlog_warn("%s: address mismatch: addr=%s raddr=%s",
-                         __PRETTY_FUNCTION__, addr_str, raddr_str);
+               zlog_warn("%s: address mismatch: addr=%s(%s) raddr=%s",
+                         __PRETTY_FUNCTION__, addr_str, pim->vrf->name,
+                         raddr_str);
                /* warning only */
        }
 
@@ -198,8 +192,9 @@ static int zclient_read_nexthop(struct zclient *zlookup,
        nexthop_num = stream_getc(s);
 
        if (nexthop_num < 1) {
-               zlog_err("%s: socket %d bad nexthop_num=%d", __func__,
-                        zlookup->sock, nexthop_num);
+               if (PIM_DEBUG_PIM_NHT_DETAIL)
+                       zlog_debug("%s: socket %d bad nexthop_num=%d", __func__,
+                                  zlookup->sock, nexthop_num);
                return -6;
        }
 
@@ -214,9 +209,9 @@ static int zclient_read_nexthop(struct zclient *zlookup,
                        pim_inet4_dump("<addr?>", addr, addr_str,
                                       sizeof(addr_str));
                        zlog_warn(
-                               "%s %s: found too many nexthop ifindexes (%d > %d) for address %s",
-                               __FILE__, __PRETTY_FUNCTION__,
-                               (num_ifindex + 1), tab_size, addr_str);
+                               "%s: found too many nexthop ifindexes (%d > %d) for address %s(%s)",
+                               __PRETTY_FUNCTION__, (num_ifindex + 1),
+                               tab_size, addr_str, pim->vrf->name);
                        return num_ifindex;
                }
                switch (nexthop_type) {
@@ -256,17 +251,17 @@ static int zclient_read_nexthop(struct zclient *zlookup,
                         * If we are sending v6 secondary assume we receive v6
                         * secondary
                         */
-                       if (pimg->send_v6_secondary)
+                       if (pim->send_v6_secondary)
                                nbr = pim_neighbor_find_by_secondary(
                                        if_lookup_by_index(
                                                nexthop_tab[num_ifindex]
                                                        .ifindex,
-                                               VRF_DEFAULT),
+                                               vrf_id),
                                        &p);
                        else
                                nbr = pim_neighbor_find_if(if_lookup_by_index(
                                        nexthop_tab[num_ifindex].ifindex,
-                                       VRF_DEFAULT));
+                                       vrf_id));
                        if (nbr) {
                                nexthop_tab[num_ifindex].nexthop_addr.family =
                                        AF_INET;
@@ -283,9 +278,9 @@ static int zclient_read_nexthop(struct zclient *zlookup,
                                pim_inet4_dump("<addr?>", addr, addr_str,
                                               sizeof(addr_str));
                                zlog_warn(
-                                       "%s %s: found non-ifindex nexthop type=%d for address %s",
-                                       __FILE__, __PRETTY_FUNCTION__,
-                                       nexthop_type, addr_str);
+                                       "%s: found non-ifindex nexthop type=%d for address %s(%s)",
+                                       __PRETTY_FUNCTION__, nexthop_type,
+                                       addr_str, pim->vrf->name);
                        }
                        break;
                }
@@ -294,51 +289,61 @@ static int zclient_read_nexthop(struct zclient *zlookup,
        return num_ifindex;
 }
 
-static int zclient_lookup_nexthop_once(struct pim_zlookup_nexthop nexthop_tab[],
+static int zclient_lookup_nexthop_once(struct pim_instance *pim,
+                                      struct pim_zlookup_nexthop nexthop_tab[],
                                       const int tab_size, struct in_addr addr)
 {
        struct stream *s;
        int ret;
 
-       if (PIM_DEBUG_PIM_TRACE_DETAIL) {
+       if (PIM_DEBUG_PIM_NHT_DETAIL) {
                char addr_str[INET_ADDRSTRLEN];
                pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
-               zlog_debug("%s: addr=%s", __PRETTY_FUNCTION__, addr_str);
+               zlog_debug("%s: addr=%s(%s)", __PRETTY_FUNCTION__, addr_str,
+                          pim->vrf->name);
        }
 
        /* Check socket. */
        if (zlookup->sock < 0) {
-               zlog_err("%s %s: zclient lookup socket is not connected",
-                        __FILE__, __PRETTY_FUNCTION__);
+               zlog_err("%s: zclient lookup socket is not connected",
+                        __PRETTY_FUNCTION__);
                zclient_lookup_failed(zlookup);
                return -1;
        }
 
+       if (pim->vrf->vrf_id == VRF_UNKNOWN) {
+               zlog_err(
+                       "%s: VRF: %s does not fully exist yet, delaying lookup",
+                       __PRETTY_FUNCTION__, pim->vrf->name);
+               return -1;
+       }
+
        s = zlookup->obuf;
        stream_reset(s);
-       zclient_create_header(s, ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB, VRF_DEFAULT);
+       zclient_create_header(s, ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB, pim->vrf_id);
        stream_put_in_addr(s, &addr);
        stream_putw_at(s, 0, stream_get_endp(s));
 
        ret = writen(zlookup->sock, s->data, stream_get_endp(s));
        if (ret < 0) {
                zlog_err(
-                       "%s %s: writen() failure: %d writing to zclient lookup socket",
-                       __FILE__, __PRETTY_FUNCTION__, errno);
+                       "%s: writen() failure: %d writing to zclient lookup socket",
+                       __PRETTY_FUNCTION__, errno);
                zclient_lookup_failed(zlookup);
                return -2;
        }
        if (ret == 0) {
-               zlog_err("%s %s: connection closed on zclient lookup socket",
-                        __FILE__, __PRETTY_FUNCTION__);
+               zlog_err("%s: connection closed on zclient lookup socket",
+                        __PRETTY_FUNCTION__);
                zclient_lookup_failed(zlookup);
                return -3;
        }
 
-       return zclient_read_nexthop(zlookup, nexthop_tab, tab_size, addr);
+       return zclient_read_nexthop(pim, zlookup, nexthop_tab, tab_size, addr);
 }
 
-int zclient_lookup_nexthop(struct pim_zlookup_nexthop nexthop_tab[],
+int zclient_lookup_nexthop(struct pim_instance *pim,
+                          struct pim_zlookup_nexthop nexthop_tab[],
                           const int tab_size, struct in_addr addr,
                           int max_lookup)
 {
@@ -353,17 +358,17 @@ int zclient_lookup_nexthop(struct pim_zlookup_nexthop nexthop_tab[],
                int first_ifindex;
                struct prefix nexthop_addr;
 
-               num_ifindex = zclient_lookup_nexthop_once(nexthop_tab, tab_size,
-                                                         addr);
+               num_ifindex = zclient_lookup_nexthop_once(pim, nexthop_tab,
+                                                         tab_size, addr);
                if (num_ifindex < 1) {
-                       if (PIM_DEBUG_ZEBRA) {
+                       if (PIM_DEBUG_PIM_NHT) {
                                char addr_str[INET_ADDRSTRLEN];
                                pim_inet4_dump("<addr?>", addr, addr_str,
                                               sizeof(addr_str));
                                zlog_debug(
-                                       "%s %s: lookup=%d/%d: could not find nexthop ifindex for address %s",
-                                       __FILE__, __PRETTY_FUNCTION__, lookup,
-                                       max_lookup, addr_str);
+                                       "%s: lookup=%d/%d: could not find nexthop ifindex for address %s(%s)",
+                                       __PRETTY_FUNCTION__, lookup, max_lookup,
+                                       addr_str, pim->vrf->name);
                        }
                        return -1;
                }
@@ -393,16 +398,16 @@ int zclient_lookup_nexthop(struct pim_zlookup_nexthop nexthop_tab[],
                        if (lookup > 0) {
                                /* Report non-recursive success after first
                                 * lookup */
-                               if (PIM_DEBUG_ZEBRA) {
+                               if (PIM_DEBUG_PIM_NHT) {
                                        char addr_str[INET_ADDRSTRLEN];
                                        pim_inet4_dump("<addr?>", addr,
                                                       addr_str,
                                                       sizeof(addr_str));
                                        zlog_debug(
-                                               "%s %s: lookup=%d/%d: found non-recursive ifindex=%d for address %s dist=%d met=%d",
-                                               __FILE__, __PRETTY_FUNCTION__,
-                                               lookup, max_lookup,
-                                               first_ifindex, addr_str,
+                                               "%s: lookup=%d/%d: found non-recursive ifindex=%d for address %s(%s) dist=%d met=%d",
+                                               __PRETTY_FUNCTION__, lookup,
+                                               max_lookup, first_ifindex,
+                                               addr_str, pim->vrf->name,
                                                nexthop_tab[0]
                                                        .protocol_distance,
                                                nexthop_tab[0].route_metric);
@@ -420,7 +425,7 @@ int zclient_lookup_nexthop(struct pim_zlookup_nexthop nexthop_tab[],
                        return num_ifindex;
                }
 
-               if (PIM_DEBUG_ZEBRA) {
+               if (PIM_DEBUG_PIM_NHT) {
                        char addr_str[INET_ADDRSTRLEN];
                        char nexthop_str[PREFIX_STRLEN];
                        pim_inet4_dump("<addr?>", addr, addr_str,
@@ -428,9 +433,9 @@ int zclient_lookup_nexthop(struct pim_zlookup_nexthop nexthop_tab[],
                        pim_addr_dump("<nexthop?>", &nexthop_addr, nexthop_str,
                                      sizeof(nexthop_str));
                        zlog_debug(
-                               "%s %s: lookup=%d/%d: zebra returned recursive nexthop %s for address %s dist=%d met=%d",
-                               __FILE__, __PRETTY_FUNCTION__, lookup,
-                               max_lookup, nexthop_str, addr_str,
+                               "%s: lookup=%d/%d: zebra returned recursive nexthop %s for address %s(%s) dist=%d met=%d",
+                               __PRETTY_FUNCTION__, lookup, max_lookup,
+                               nexthop_str, addr_str, pim->vrf->name,
                                nexthop_tab[0].protocol_distance,
                                nexthop_tab[0].route_metric);
                }
@@ -441,13 +446,13 @@ int zclient_lookup_nexthop(struct pim_zlookup_nexthop nexthop_tab[],
 
        } /* for (max_lookup) */
 
-       if (PIM_DEBUG_ZEBRA) {
+       if (PIM_DEBUG_PIM_NHT) {
                char addr_str[INET_ADDRSTRLEN];
                pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
                zlog_warn(
-                       "%s %s: lookup=%d/%d: failure searching recursive nexthop ifindex for address %s",
-                       __FILE__, __PRETTY_FUNCTION__, lookup, max_lookup,
-                       addr_str);
+                       "%s: lookup=%d/%d: failure searching recursive nexthop ifindex for address %s(%s)",
+                       __PRETTY_FUNCTION__, lookup, max_lookup, addr_str,
+                       pim->vrf->name);
        }
 
        return -2;
@@ -472,7 +477,7 @@ int pim_zlookup_sg_statistics(struct channel_oil *c_oil)
        int count = 0;
        int ret;
        struct interface *ifp =
-               pim_if_find_by_vif_index(c_oil->oil.mfcc_parent);
+               pim_if_find_by_vif_index(c_oil->pim, c_oil->oil.mfcc_parent);
 
        if (PIM_DEBUG_ZEBRA) {
                struct prefix_sg more;
@@ -480,15 +485,16 @@ int pim_zlookup_sg_statistics(struct channel_oil *c_oil)
                more.src = c_oil->oil.mfcc_origin;
                more.grp = c_oil->oil.mfcc_mcastgrp;
                zlog_debug(
-                       "Sending Request for New Channel Oil Information(%s) VIIF %d",
-                       pim_str_sg_dump(&more), c_oil->oil.mfcc_parent);
+                       "Sending Request for New Channel Oil Information(%s) VIIF %d(%s)",
+                       pim_str_sg_dump(&more), c_oil->oil.mfcc_parent,
+                       c_oil->pim->vrf->name);
        }
 
        if (!ifp)
                return -1;
 
        stream_reset(s);
-       zclient_create_header(s, ZEBRA_IPMR_ROUTE_STATS, VRF_DEFAULT);
+       zclient_create_header(s, ZEBRA_IPMR_ROUTE_STATS, c_oil->pim->vrf_id);
        stream_put_in_addr(s, &c_oil->oil.mfcc_origin);
        stream_put_in_addr(s, &c_oil->oil.mfcc_mcastgrp);
        stream_putl(s, ifp->ifindex);
@@ -498,8 +504,8 @@ int pim_zlookup_sg_statistics(struct channel_oil *c_oil)
        ret = writen(zlookup->sock, s->data, count);
        if (ret <= 0) {
                zlog_err(
-                       "%s %s: writen() failure: %d writing to zclient lookup socket",
-                       __FILE__, __PRETTY_FUNCTION__, errno);
+                       "%s: writen() failure: %d writing to zclient lookup socket",
+                       __PRETTY_FUNCTION__, errno);
                return -1;
        }
 
@@ -516,8 +522,8 @@ int pim_zlookup_sg_statistics(struct channel_oil *c_oil)
                err = zclient_read_header(s, zlookup->sock, &length, &marker,
                                          &version, &vrf_id, &command);
                if (err < 0) {
-                       zlog_err("%s %s: zclient_read_header() failed",
-                                __FILE__, __PRETTY_FUNCTION__);
+                       zlog_err("%s: zclient_read_header() failed",
+                                __PRETTY_FUNCTION__);
                        zclient_lookup_failed(zlookup);
                        return -1;
                }
@@ -527,18 +533,22 @@ int pim_zlookup_sg_statistics(struct channel_oil *c_oil)
        sg.grp.s_addr = stream_get_ipv4(s);
        if (sg.src.s_addr != c_oil->oil.mfcc_origin.s_addr
            || sg.grp.s_addr != c_oil->oil.mfcc_mcastgrp.s_addr) {
-               zlog_err("%s: Received wrong %s information",
-                        __PRETTY_FUNCTION__, pim_str_sg_dump(&sg));
+               if (PIM_DEBUG_ZEBRA) {
+                       struct prefix_sg more;
+
+                       more.src = c_oil->oil.mfcc_origin;
+                       more.grp = c_oil->oil.mfcc_mcastgrp;
+                       zlog_err(
+                               "%s: Received wrong %s(%s) information requested",
+                               __PRETTY_FUNCTION__, pim_str_sg_dump(&more),
+                               c_oil->pim->vrf->name);
+               }
                zclient_lookup_failed(zlookup);
                return -3;
        }
 
        stream_get(&lastused, s, sizeof(lastused));
-       ret = stream_getl(s);
-
-       if (PIM_DEBUG_ZEBRA)
-               zlog_debug("Received %lld for %s success: %d", lastused,
-                          pim_str_sg_dump(&sg), ret);
+       stream_getl(s);
 
        c_oil->cc.lastused = lastused;
 
index d168464ce5610c373e18f6e627950a95acdfca59..f8a2d59f68ea125252fe4554b6814455dd08eea4 100644 (file)
@@ -36,7 +36,8 @@ struct pim_zlookup_nexthop {
 void zclient_lookup_new(void);
 void zclient_lookup_free(void);
 
-int zclient_lookup_nexthop(struct pim_zlookup_nexthop nexthop_tab[],
+int zclient_lookup_nexthop(struct pim_instance *pim,
+                          struct pim_zlookup_nexthop nexthop_tab[],
                           const int tab_size, struct in_addr addr,
                           int max_lookup);
 
index 89b235bed1e8031e5f43cdc9e6575fe8268599d9..9a8e92cbb240cf562a8803703d8d75a177205cc9 100644 (file)
 
 #include "pimd.h"
 #include "pim_cmd.h"
-#include "pim_iface.h"
-#include "pim_zebra.h"
 #include "pim_str.h"
 #include "pim_oil.h"
 #include "pim_pim.h"
-#include "pim_upstream.h"
-#include "pim_rpf.h"
 #include "pim_ssmpingd.h"
 #include "pim_static.h"
 #include "pim_rp.h"
 #include "pim_ssm.h"
 #include "pim_zlookup.h"
-#include "pim_nht.h"
+#include "pim_zebra.h"
 
 const char *const PIM_ALL_SYSTEMS = MCAST_ALL_SYSTEMS;
 const char *const PIM_ALL_ROUTERS = MCAST_ALL_ROUTERS;
@@ -52,8 +48,6 @@ const char *const PIM_ALL_IGMP_ROUTERS = MCAST_ALL_IGMP_ROUTERS;
 
 struct thread_master *master = NULL;
 uint32_t qpim_debugs = 0;
-int qpim_mroute_socket_fd = -1;
-int64_t qpim_mroute_socket_creation = 0; /* timestamp of creation */
 int qpim_t_periodic =
        PIM_DEFAULT_T_PERIODIC; /* Period between Join/Prune Messages */
 struct pim_assert_metric qpim_infinite_assert_metric;
@@ -62,17 +56,8 @@ struct thread *qpim_rpf_cache_refresher = NULL;
 int64_t qpim_rpf_cache_refresh_requests = 0;
 int64_t qpim_rpf_cache_refresh_events = 0;
 int64_t qpim_rpf_cache_refresh_last = 0;
-struct list *qpim_ssmpingd_list = NULL;
-struct in_addr qpim_ssmpingd_group_addr;
 int64_t qpim_scan_oil_events = 0;
 int64_t qpim_scan_oil_last = 0;
-int64_t qpim_mroute_add_events = 0;
-int64_t qpim_mroute_add_last = 0;
-int64_t qpim_mroute_del_events = 0;
-int64_t qpim_mroute_del_last = 0;
-struct list *qpim_static_route_list = NULL;
-unsigned int qpim_keep_alive_time = PIM_KEEPALIVE_PERIOD;
-signed int qpim_rp_keep_alive_time = 0;
 int64_t qpim_nexthop_lookups = 0;
 int qpim_packet_process = PIM_DEFAULT_PACKET_PROCESS;
 uint8_t qpim_ecmp_enable = 0;
@@ -82,134 +67,25 @@ struct pim_instance *pimg = NULL;
 int32_t qpim_register_suppress_time = PIM_REGISTER_SUPPRESSION_TIME_DEFAULT;
 int32_t qpim_register_probe_time = PIM_REGISTER_PROBE_TIME_DEFAULT;
 
-static struct pim_instance *pim_instance_init(vrf_id_t vrf_id, afi_t afi);
-static void pim_instance_terminate(void);
-
-static int pim_vrf_new(struct vrf *vrf)
-{
-       zlog_debug("VRF Created: %s(%d)", vrf->name, vrf->vrf_id);
-       return 0;
-}
-
-static int pim_vrf_delete(struct vrf *vrf)
-{
-       zlog_debug("VRF Deletion: %s(%d)", vrf->name, vrf->vrf_id);
-       return 0;
-}
-
-static int pim_vrf_enable(struct vrf *vrf)
-{
-
-       if (!vrf) // unexpected
-               return -1;
-
-       if (vrf->vrf_id == VRF_DEFAULT) {
-               pimg = pim_instance_init(VRF_DEFAULT, AFI_IP);
-               if (pimg == NULL) {
-                       zlog_err("%s %s: pim class init failure ", __FILE__,
-                                __PRETTY_FUNCTION__);
-                       /*
-                        * We will crash and burn otherwise
-                        */
-                       exit(1);
-               }
-
-               pimg->send_v6_secondary = 1;
-       }
-       return 0;
-}
-
-static int pim_vrf_disable(struct vrf *vrf)
-{
-       if (vrf->vrf_id == VRF_DEFAULT)
-               return 0;
-
-       if (vrf->vrf_id == VRF_DEFAULT)
-               pim_instance_terminate();
-
-       /* Note: This is a callback, the VRF will be deleted by the caller. */
-       return 0;
-}
-
-void pim_vrf_init(void)
-{
-       vrf_init(pim_vrf_new, pim_vrf_enable, pim_vrf_disable, pim_vrf_delete);
-}
-
-static void pim_vrf_terminate(void)
-{
-       vrf_terminate();
-}
-
-/* Key generate for pim->rpf_hash */
-static unsigned int pim_rpf_hash_key(void *arg)
-{
-       struct pim_nexthop_cache *r = (struct pim_nexthop_cache *)arg;
-
-       return jhash_1word(r->rpf.rpf_addr.u.prefix4.s_addr, 0);
-}
-
-/* Compare pim->rpf_hash node data */
-static int pim_rpf_equal(const void *arg1, const void *arg2)
-{
-       const struct pim_nexthop_cache *r1 =
-               (const struct pim_nexthop_cache *)arg1;
-       const struct pim_nexthop_cache *r2 =
-               (const struct pim_nexthop_cache *)arg2;
-
-       return prefix_same(&r1->rpf.rpf_addr, &r2->rpf.rpf_addr);
-}
-
-/* Cleanup pim->rpf_hash each node data */
-static void pim_rp_list_hash_clean(void *data)
-{
-       struct pim_nexthop_cache *pnc;
-
-       pnc = (struct pim_nexthop_cache *)data;
-       if (pnc->rp_list->count)
-               list_delete_all_node(pnc->rp_list);
-       if (pnc->upstream_list->count)
-               list_delete_all_node(pnc->upstream_list);
-}
-
 void pim_prefix_list_update(struct prefix_list *plist)
 {
-       pim_rp_prefix_list_update(plist);
-       pim_ssm_prefix_list_update(plist);
-       pim_upstream_spt_prefix_list_update(plist);
-}
+       struct pim_instance *pim;
+       struct vrf *vrf;
 
-static void pim_instance_terminate(void)
-{
-       /* Traverse and cleanup rpf_hash */
-       if (pimg->rpf_hash) {
-               hash_clean(pimg->rpf_hash, (void *)pim_rp_list_hash_clean);
-               hash_free(pimg->rpf_hash);
-               pimg->rpf_hash = NULL;
-       }
+       RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name)
+       {
+               pim = vrf->info;
+               if (!pim)
+                       continue;
 
-       if (pimg->ssm_info) {
-               pim_ssm_terminate(pimg->ssm_info);
-               pimg->ssm_info = NULL;
+               pim_rp_prefix_list_update(pim, plist);
+               pim_ssm_prefix_list_update(pim, plist);
+               pim_upstream_spt_prefix_list_update(pim, plist);
        }
-
-       XFREE(MTYPE_PIM_PIM_INSTANCE, pimg);
 }
 
 static void pim_free()
 {
-       pim_ssmpingd_destroy();
-
-       pim_oil_terminate();
-
-       pim_upstream_terminate();
-
-       if (qpim_static_route_list)
-               list_free(qpim_static_route_list);
-
-       pim_if_terminate();
-       pim_rp_free();
-
        pim_route_map_terminate();
 
        zclient_lookup_free();
@@ -217,41 +93,8 @@ static void pim_free()
        zprivs_terminate(&pimd_privs);
 }
 
-static struct pim_instance *pim_instance_init(vrf_id_t vrf_id, afi_t afi)
-{
-       struct pim_instance *pim;
-
-       pim = XCALLOC(MTYPE_PIM_PIM_INSTANCE, sizeof(struct pim_instance));
-       if (!pim)
-               return NULL;
-
-       pim->vrf_id = vrf_id;
-       pim->afi = afi;
-
-       pim->spt.switchover = PIM_SPT_IMMEDIATE;
-       pim->spt.plist = NULL;
-
-       pim->rpf_hash =
-               hash_create_size(256, pim_rpf_hash_key, pim_rpf_equal, NULL);
-
-       if (PIM_DEBUG_ZEBRA)
-               zlog_debug("%s: NHT rpf hash init ", __PRETTY_FUNCTION__);
-
-       pim->ssm_info = pim_ssm_init(vrf_id);
-       if (!pim->ssm_info) {
-               pim_instance_terminate();
-               return NULL;
-       }
-
-       return pim;
-}
-
 void pim_init()
 {
-       qpim_rp_keep_alive_time = PIM_RP_KEEPALIVE_PERIOD;
-
-       pim_rp_init();
-
        if (!inet_aton(PIM_ALL_PIM_ROUTERS, &qpim_all_pim_routers_addr)) {
                zlog_err(
                        "%s %s: could not solve %s to group address: errno=%d: %s",
@@ -261,21 +104,6 @@ void pim_init()
                return;
        }
 
-       pim_oil_init();
-
-       pim_upstream_init();
-
-       qpim_static_route_list = list_new();
-       if (!qpim_static_route_list) {
-               zlog_err("%s %s: failure: static_route_list=list_new()",
-                        __FILE__, __PRETTY_FUNCTION__);
-               return;
-       }
-       qpim_static_route_list->del = (void (*)(void *))pim_static_route_free;
-
-       pim_mroute_socket_enable();
-
-
        /*
          RFC 4601: 4.6.3.  Assert Metrics
 
@@ -290,9 +118,7 @@ void pim_init()
        qpim_infinite_assert_metric.route_metric = PIM_ASSERT_ROUTE_METRIC_MAX;
        qpim_infinite_assert_metric.ip_address.s_addr = INADDR_ANY;
 
-       pim_if_init();
        pim_cmd_init();
-       pim_ssmpingd_init();
 }
 
 void pim_terminate()
index 7934bce2d4f24f413f07d36b74efc549cb2dbdd2..ed51db3dee33491cc7995d4f58efa213a0b518f9 100644 (file)
@@ -27,6 +27,7 @@
 #include "vty.h"
 #include "plist.h"
 
+#include "pim_instance.h"
 #include "pim_str.h"
 #include "pim_memory.h"
 #include "pim_assert.h"
 #define PIM_MASK_MSDP_EVENTS         (1 << 19)
 #define PIM_MASK_MSDP_PACKETS        (1 << 20)
 #define PIM_MASK_MSDP_INTERNAL       (1 << 21)
+#define PIM_MASK_PIM_NHT             (1 << 22)
+#define PIM_MASK_PIM_NHT_DETAIL      (1 << 23)
 
 /* PIM error codes */
 #define PIM_SUCCESS                0
@@ -128,8 +131,6 @@ const char *const PIM_ALL_IGMP_ROUTERS;
 extern struct thread_master *master;
 extern struct zebra_privs_t pimd_privs;
 uint32_t qpim_debugs;
-int qpim_mroute_socket_fd;
-int64_t qpim_mroute_socket_creation; /* timestamp of creation */
 struct in_addr qpim_all_pim_routers_addr;
 int qpim_t_periodic; /* Period between Join/Prune Messages */
 struct pim_assert_metric qpim_infinite_assert_metric;
@@ -138,18 +139,9 @@ struct thread *qpim_rpf_cache_refresher;
 int64_t qpim_rpf_cache_refresh_requests;
 int64_t qpim_rpf_cache_refresh_events;
 int64_t qpim_rpf_cache_refresh_last;
-struct list *qpim_ssmpingd_list; /* list of struct ssmpingd_sock */
-struct in_addr qpim_ssmpingd_group_addr;
 int64_t qpim_scan_oil_events;
 int64_t qpim_scan_oil_last;
-int64_t qpim_mroute_add_events;
-int64_t qpim_mroute_add_last;
-int64_t qpim_mroute_del_events;
-int64_t qpim_mroute_del_last;
 int64_t qpim_nexthop_lookups;
-struct list *qpim_static_route_list; /* list of routes added statically */
-extern unsigned int qpim_keep_alive_time;
-extern signed int qpim_rp_keep_alive_time;
 extern int qpim_packet_process;
 extern uint8_t qpim_ecmp_enable;
 extern uint8_t qpim_ecmp_rebalance_enable;
@@ -189,6 +181,8 @@ extern int32_t qpim_register_probe_time;
 #define PIM_DEBUG_MSDP_EVENTS         (qpim_debugs & PIM_MASK_MSDP_EVENTS)
 #define PIM_DEBUG_MSDP_PACKETS        (qpim_debugs & PIM_MASK_MSDP_PACKETS)
 #define PIM_DEBUG_MSDP_INTERNAL       (qpim_debugs & PIM_MASK_MSDP_INTERNAL)
+#define PIM_DEBUG_PIM_NHT             (qpim_debugs & PIM_MASK_PIM_NHT)
+#define PIM_DEBUG_PIM_NHT_DETAIL      (qpim_debugs & PIM_MASK_PIM_NHT_DETAIL)
 
 #define PIM_DEBUG_EVENTS       (qpim_debugs & (PIM_MASK_PIM_EVENTS | PIM_MASK_IGMP_EVENTS | PIM_MASK_MSDP_EVENTS))
 #define PIM_DEBUG_PACKETS      (qpim_debugs & (PIM_MASK_PIM_PACKETS | PIM_MASK_IGMP_PACKETS | PIM_MASK_MSDP_PACKETS))
@@ -199,6 +193,7 @@ extern int32_t qpim_register_probe_time;
 #define PIM_DO_DEBUG_PIM_PACKETDUMP_SEND (qpim_debugs |= PIM_MASK_PIM_PACKETDUMP_SEND)
 #define PIM_DO_DEBUG_PIM_PACKETDUMP_RECV (qpim_debugs |= PIM_MASK_PIM_PACKETDUMP_RECV)
 #define PIM_DO_DEBUG_PIM_TRACE           (qpim_debugs |= PIM_MASK_PIM_TRACE)
+#define PIM_DO_DEBUG_PIM_TRACE_DETAIL    (qpim_debugs |= PIM_MASK_PIM_TRACE_DETAIL)
 #define PIM_DO_DEBUG_IGMP_EVENTS         (qpim_debugs |= PIM_MASK_IGMP_EVENTS)
 #define PIM_DO_DEBUG_IGMP_PACKETS        (qpim_debugs |= PIM_MASK_IGMP_PACKETS)
 #define PIM_DO_DEBUG_IGMP_TRACE          (qpim_debugs |= PIM_MASK_IGMP_TRACE)
@@ -214,12 +209,14 @@ extern int32_t qpim_register_probe_time;
 #define PIM_DO_DEBUG_MSDP_EVENTS         (qpim_debugs |= PIM_MASK_MSDP_EVENTS)
 #define PIM_DO_DEBUG_MSDP_PACKETS        (qpim_debugs |= PIM_MASK_MSDP_PACKETS)
 #define PIM_DO_DEBUG_MSDP_INTERNAL       (qpim_debugs |= PIM_MASK_MSDP_INTERNAL)
+#define PIM_DO_DEBUG_PIM_NHT             (qpim_debugs |= PIM_MASK_PIM_NHT)
 
 #define PIM_DONT_DEBUG_PIM_EVENTS          (qpim_debugs &= ~PIM_MASK_PIM_EVENTS)
 #define PIM_DONT_DEBUG_PIM_PACKETS         (qpim_debugs &= ~PIM_MASK_PIM_PACKETS)
 #define PIM_DONT_DEBUG_PIM_PACKETDUMP_SEND (qpim_debugs &= ~PIM_MASK_PIM_PACKETDUMP_SEND)
 #define PIM_DONT_DEBUG_PIM_PACKETDUMP_RECV (qpim_debugs &= ~PIM_MASK_PIM_PACKETDUMP_RECV)
 #define PIM_DONT_DEBUG_PIM_TRACE           (qpim_debugs &= ~PIM_MASK_PIM_TRACE)
+#define PIM_DONT_DEBUG_PIM_TRACE_DETAIL    (qpim_debugs &= ~PIM_MASK_PIM_TRACE_DETAIL)
 #define PIM_DONT_DEBUG_IGMP_EVENTS         (qpim_debugs &= ~PIM_MASK_IGMP_EVENTS)
 #define PIM_DONT_DEBUG_IGMP_PACKETS        (qpim_debugs &= ~PIM_MASK_IGMP_PACKETS)
 #define PIM_DONT_DEBUG_IGMP_TRACE          (qpim_debugs &= ~PIM_MASK_IGMP_TRACE)
@@ -235,37 +232,13 @@ extern int32_t qpim_register_probe_time;
 #define PIM_DONT_DEBUG_MSDP_EVENTS         (qpim_debugs &= ~PIM_MASK_MSDP_EVENTS)
 #define PIM_DONT_DEBUG_MSDP_PACKETS        (qpim_debugs &= ~PIM_MASK_MSDP_PACKETS)
 #define PIM_DONT_DEBUG_MSDP_INTERNAL       (qpim_debugs &= ~PIM_MASK_MSDP_INTERNAL)
-
-enum pim_spt_switchover {
-       PIM_SPT_IMMEDIATE,
-       PIM_SPT_INFINITY,
-};
-
-/* Per VRF PIM DB */
-struct pim_instance {
-       afi_t afi;
-       vrf_id_t vrf_id;
-
-       struct {
-               enum pim_spt_switchover switchover;
-               char *plist;
-       } spt;
-
-       struct hash *rpf_hash;
-
-       void *ssm_info; /* per-vrf SSM configuration */
-
-       int send_v6_secondary;
-};
-
-extern struct pim_instance *pimg; // Pim Global Instance
+#define PIM_DONT_DEBUG_PIM_NHT             (qpim_debugs &= ~PIM_MASK_PIM_NHT)
 
 void pim_init(void);
 void pim_terminate(void);
 
 extern void pim_route_map_init(void);
 extern void pim_route_map_terminate(void);
-void pim_vrf_init(void);
 void pim_prefix_list_update(struct prefix_list *plist);
 
 #endif /* PIMD_H */
index 14ec9fb02b2036e4e10cc95597c60c7a7db555de..3d104e7c7c606f4f64aed295203a027f9a30a5b1 100644 (file)
@@ -138,7 +138,8 @@ int main(int argc, const char *argv[])
 
        printf("%s: waiting...\n", prog_name);
 
-       getchar();
+       if (getchar() == EOF)
+         fprintf(stderr, "getchar failure\n");
 
        close(fd);
 
diff --git a/pkgsrc/Makefile.am b/pkgsrc/Makefile.am
deleted file mode 100644 (file)
index 622fbf0..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-rcdir=@pkgsrcrcdir@
-
-rc_SCRIPTS = bgpd.sh ospf6d.sh ospfd.sh ripd.sh ripngd.sh zebra.sh
diff --git a/python/Makefile.am b/python/Makefile.am
deleted file mode 100644 (file)
index 4ad1e36..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-EXTRA_DIST = \
-       clidef.py \
-       clippy/__init__.py
index b133c52a42dc08638463b1250cf309691fbfee08..17e90443e977f113cea3a5a49954767ec7248d3e 100644 (file)
@@ -1,4 +1,4 @@
-Makefile
+!Makefile
 Makefile.in
 *.o
 tags
diff --git a/qpb/Makefile b/qpb/Makefile
new file mode 100644 (file)
index 0000000..2237def
--- /dev/null
@@ -0,0 +1,10 @@
+all: ALWAYS
+       @$(MAKE) -s -C .. fpm/libfrr_pb.la
+%: ALWAYS
+       @$(MAKE) -s -C .. fpm/$@
+
+Makefile:
+       #nothing
+ALWAYS:
+.PHONY: ALWAYS makefiles
+.SUFFIXES:
diff --git a/qpb/Makefile.am b/qpb/Makefile.am
deleted file mode 100644 (file)
index e5951b2..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-include ../common.am
-
-AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib $(Q_PROTOBUF_C_CLIENT_INCLUDES)
-
-PROTOBUF_INCLUDES=-I$(top_srcdir)
-PROTOBUF_PACKAGE = qpb
-
-lib_LTLIBRARIES = libfrr_pb.la
-libfrr_pb_la_LDFLAGS = -version-info 0:0:0
-
-if HAVE_PROTOBUF
-protobuf_srcs =                                        \
-       qpb_allocator.c
-
-protobuf_srcs_nodist =                         \
-       qpb.pb-c.c
-endif
-
-libfrr_pb_la_SOURCES =                 \
-       linear_allocator.h                      \
-       qpb.h                                   \
-       qpb.c                                   \
-       qpb_allocator.h                         \
-       $(protobuf_srcs)
-
-nodist_libfrr_pb_la_SOURCES = $(protobuf_srcs_nodist)
-
-CLEANFILES = $(Q_CLEANFILES)
-BUILT_SOURCES = $(Q_PROTOBUF_SRCS)
-EXTRA_DIST = qpb.proto
index a1595a9abd1b65f26337943f519bb3dc52e1710d..c06debb954d08c9cde9daa622498dbf826eecc47 100644 (file)
@@ -20,6 +20,8 @@
  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
+syntax = "proto2";
+
 /*
  * Protobuf definitions pertaining to the Quagga/FRR Protobuf component.
  */
@@ -87,4 +89,4 @@ enum Protocol {
   ISIS = 8;
   BGP = 9;
   OTHER = 10;
-}
\ No newline at end of file
+}
index 8b0ee941a5a858c8bb1f8b9798035bfcfbb5dbf7..7e5ba5b0ce40fb9e56edfe8f521674d25d05b053 100644 (file)
@@ -42,8 +42,7 @@ static void _qpb_free(void *allocator_data, void *ptr)
        linear_allocator_free(allocator_data, ptr);
 }
 
-static ProtobufCAllocator allocator_template = {_qpb_alloc, _qpb_free, NULL,
-                                               8192, NULL};
+static ProtobufCAllocator allocator_template = {_qpb_alloc, _qpb_free, NULL};
 
 /*
  * qpb_allocator_init_linear
diff --git a/qpb/subdir.am b/qpb/subdir.am
new file mode 100644 (file)
index 0000000..71e501b
--- /dev/null
@@ -0,0 +1,26 @@
+if HAVE_PROTOBUF
+lib_LTLIBRARIES += qpb/libfrr_pb.la
+endif
+
+qpb_libfrr_pb_la_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir) -I$(top_builddir)/lib \
+       $(Q_PROTOBUF_C_CLIENT_INCLUDES)
+qpb_libfrr_pb_la_LDFLAGS = -version-info 0:0:0
+
+qpb_libfrr_pb_la_SOURCES = \
+       qpb/linear_allocator.h \
+       qpb/qpb.h \
+       qpb/qpb.c \
+       qpb/qpb_allocator.h \
+       # end
+
+if HAVE_PROTOBUF
+qpb_libfrr_pb_la_SOURCES += qpb/qpb_allocator.c
+nodist_qpb_libfrr_pb_la_SOURCES = qpb/qpb.pb-c.c
+BUILT_SOURCES += qpb/qpb.pb-c.c
+CLEANFILES += \
+       qpb/qpb.pb-c.c \
+       qpb/qpb.pb-c.h \
+       # end
+endif
+
+EXTRA_DIST += qpb/qpb.proto
diff --git a/redhat/Makefile.am b/redhat/Makefile.am
deleted file mode 100644 (file)
index 74856cf..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-
-EXTRA_DIST = frr.init frr.service daemons \
-       frr.logrotate frr.pam frr.spec \
-       README.rpm_build.md
-
index 674ccb2d6fed6048e3f88ad9f48c3ba5c7f7d571..b23249e04ec4256b8a73fc6de7d3932bacb78272 100644 (file)
@@ -168,7 +168,8 @@ Requires(pre):      initscripts >= 5.60
 %endif
 Provides:           routingdaemon = %{version}-%{release}
 BuildRoot:          %{_tmppath}/%{name}-%{version}-root
-Obsoletes:          bird gated mrt zebra frr-sysvinit
+Obsoletes:          gated mrt zebra frr-sysvinit
+Conflicts:          bird
 
 %description
 FRRouting is a free software that manages TCP/IP based routing
index 763bfc142cf5e0eba0aa1d2c91eacf531e1f06e0..0a6337bf76e5cabb720185377caf968eb74f9686 100644 (file)
@@ -143,10 +143,6 @@ static char *rip_peer_uptime(struct rip_peer *peer, char *buf, size_t len)
        uptime -= peer->uptime;
        tm = gmtime(&uptime);
 
-/* Making formatted timer strings. */
-#define ONE_DAY_SECOND 60*60*24
-#define ONE_WEEK_SECOND 60*60*24*7
-
        if (uptime < ONE_DAY_SECOND)
                snprintf(buf, len, "%02d:%02d:%02d", tm->tm_hour, tm->tm_min,
                         tm->tm_sec);
index 2a412f9b646d3176a265b7549e50a902cb9ecb4b..cd46d97402ee44113cc6a050c3bb78ab84a88892 100644 (file)
@@ -151,10 +151,6 @@ static char *ripng_peer_uptime(struct ripng_peer *peer, char *buf, size_t len)
        uptime -= peer->uptime;
        tm = gmtime(&uptime);
 
-/* Making formatted timer strings. */
-#define ONE_DAY_SECOND 60*60*24
-#define ONE_WEEK_SECOND 60*60*24*7
-
        if (uptime < ONE_DAY_SECOND)
                snprintf(buf, len, "%02d:%02d:%02d", tm->tm_hour, tm->tm_min,
                         tm->tm_sec);
diff --git a/snapcraft/Makefile.am b/snapcraft/Makefile.am
deleted file mode 100644 (file)
index a822067..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-EXTRA_DIST = snapcraft.yaml \
-       README.snap_build.md \
-       README.usage.md \
-       extra_version_info.txt \
-       scripts \
-       defaults \
-       helpers \
-       snap
index 6d54ae155b43132088bc0e1975ebac0275712b44..113bdea098f9c60302891e8a6ebf5acc8e665ebf 100644 (file)
@@ -25,6 +25,8 @@ __pycache__
 /bgpd/test_ecommunity
 /bgpd/test_mp_attr
 /bgpd/test_mpath
+/isisd/test_fuzz_isis_tlv
+/isisd/test_fuzz_isis_tlv_tests.h
 /lib/cli/test_cli
 /lib/cli/test_commands
 /lib/cli/test_commands_defun.c
index 43003e707592699139aeb57caeafd82873d6f82b..0c31c0441ad96a9a31626b567b7811d397312251 100644 (file)
@@ -24,6 +24,13 @@ else
 TESTS_BGPD =
 endif
 
+if ISISD
+TESTS_ISISD = \
+       isisd/test_fuzz_isis_tlv
+else
+TESTS_ISISD =
+endif
+
 if OSPF6D
 TESTS_OSPF6D = \
        ospf6d/test_lsdb \
@@ -61,6 +68,7 @@ check_PROGRAMS = \
        lib/cli/test_cli \
        lib/cli/test_commands \
        $(TESTS_BGPD) \
+       $(TESTS_ISISD) \
        $(TESTS_OSPF6D) \
        # end
 
@@ -75,7 +83,12 @@ lib/cli/test_commands_defun.c: ../vtysh/vtysh_cmd.c
                < ../vtysh/vtysh_cmd.c \
                > "$@"
 
-BUILT_SOURCES = lib/cli/test_commands_defun.c
+isisd/test_fuzz_isis_tlv_tests.h: $(top_srcdir)/tests/isisd/test_fuzz_isis_tlv_tests.h.gz
+       gzip -d < $(top_srcdir)/tests/isisd/test_fuzz_isis_tlv_tests.h.gz > "$@"
+
+BUILT_SOURCES = \
+       lib/cli/test_commands_defun.c \
+       isisd/test_fuzz_isis_tlv_tests.h
 
 noinst_HEADERS = \
        ./helpers/c/prng.h \
@@ -110,11 +123,14 @@ bgpd_test_capability_SOURCES = bgpd/test_capability.c
 bgpd_test_ecommunity_SOURCES = bgpd/test_ecommunity.c
 bgpd_test_mp_attr_SOURCES = bgpd/test_mp_attr.c
 bgpd_test_mpath_SOURCES = bgpd/test_mpath.c
+isisd_test_fuzz_isis_tlv_SOURCES = isisd/test_fuzz_isis_tlv.c
+isisd_test_fuzz_isis_tlv_CPPFLAGS = $(AM_CPPFLAGS) -I$(top_builddir)/tests/isisd
 
 ospf6d_test_lsdb_SOURCES = ospf6d/test_lsdb.c lib/cli/common_cli.c
 
 ALL_TESTS_LDADD = ../lib/libfrr.la @LIBCAP@
 BGP_TEST_LDADD = ../bgpd/libbgp.a $(BGP_VNC_RFP_LIB) $(ALL_TESTS_LDADD) -lm
+ISISD_TEST_LDADD = ../isisd/libisis.a $(ALL_TESTS_LDADD)
 OSPF6_TEST_LDADD = ../ospf6d/libospf6.a $(ALL_TESTS_LDADD)
 
 lib_test_buffer_LDADD = $(ALL_TESTS_LDADD)
@@ -140,6 +156,7 @@ bgpd_test_capability_LDADD = $(BGP_TEST_LDADD)
 bgpd_test_ecommunity_LDADD = $(BGP_TEST_LDADD)
 bgpd_test_mp_attr_LDADD = $(BGP_TEST_LDADD)
 bgpd_test_mpath_LDADD = $(BGP_TEST_LDADD)
+isisd_test_fuzz_isis_tlv_LDADD = $(ISISD_TEST_LDADD)
 ospf6d_test_lsdb_LDADD = $(OSPF6_TEST_LDADD)
 
 EXTRA_DIST = \
@@ -151,6 +168,8 @@ EXTRA_DIST = \
     bgpd/test_mpath.py \
     helpers/python/frrsix.py \
     helpers/python/frrtest.py \
+    isisd/test_fuzz_isis_tlv.py \
+    isisd/test_fuzz_isis_tlv_tests.h.gz \
     lib/cli/test_commands.in \
     lib/cli/test_commands.py \
     lib/cli/test_commands.refout \
index 9ec2b5df19698aa07beb2c2236776723bea8062f..e8700a8b4ac872c033ddcdade6068cb878120429 100644 (file)
@@ -170,7 +170,7 @@ static struct test_segment mp_segments[] = {
        /* 8 */
        {
                "MP6",
-               "MP IP4/MPLS-laveled VPN",
+               "MP IP4/MPLS-labeled VPN",
                {CAPABILITY_CODE_MP, 0x4, 0x0, 0x1, 0x0, 0x80},
                6,
                SHOULD_PARSE,
index 4cb650092b82158b9d19eaf6fc71117848eccdba..872fcb6d122384fa7ad69b6d030ad933c78bec6f 100644 (file)
@@ -8,7 +8,7 @@ TestCapability.okfail("MPv6: MP IPv6/Uni")
 TestCapability.okfail("MP2: MP IP/Multicast")
 TestCapability.okfail("MP3: MP IP6/MPLS-labeled VPN")
 TestCapability.okfail("MP5: MP IP6/MPLS-VPN")
-TestCapability.okfail("MP6: MP IP4/MPLS-laveled VPN")
+TestCapability.okfail("MP6: MP IP4/MPLS-labeled VPN")
 TestCapability.okfail("MP8: MP unknown AFI/SAFI")
 TestCapability.okfail("MP-short: MP IP4/Unicast, length too short (< minimum)")
 TestCapability.okfail("MP-overflow: MP IP4/Unicast, length too long")
index 7c0afa1b92a5849b25c8a81a9347a281359eff4e..30d5fdd6cdbea6e5df0a0066180c6fa03597195d 100644 (file)
@@ -1059,7 +1059,7 @@ static void parse_test(struct peer *peer, struct test_segment *t, int type)
                parse_ret = bgp_mp_unreach_parse(&attr_args, &nlri);
        if (!parse_ret) {
                iana_afi_t pkt_afi;
-               safi_t pkt_safi;
+               iana_safi_t pkt_safi;
 
                /* Convert AFI, SAFI to internal values, check. */
                if (bgp_map_afi_safi_int2iana(nlri.afi, nlri.safi, &pkt_afi,
diff --git a/tests/isisd/.gitignore b/tests/isisd/.gitignore
new file mode 100644 (file)
index 0000000..e124221
--- /dev/null
@@ -0,0 +1 @@
+/*_afl/*
diff --git a/tests/isisd/test_fuzz_isis_tlv.c b/tests/isisd/test_fuzz_isis_tlv.c
new file mode 100644 (file)
index 0000000..6727e66
--- /dev/null
@@ -0,0 +1,188 @@
+#include "test_fuzz_isis_tlv_tests.h"
+
+#include <zebra.h>
+
+#include "memory.h"
+#include "sbuf.h"
+#include "stream.h"
+#include "thread.h"
+
+#include "isisd/isis_circuit.h"
+#include "isisd/isis_tlvs.h"
+
+#define TEST_STREAM_SIZE 1500
+
+struct thread_master *master;
+int isis_sock_init(struct isis_circuit *circuit);
+int isis_sock_init(struct isis_circuit *circuit)
+{
+       return 0;
+}
+
+static bool atexit_registered;
+
+static void show_meminfo_at_exit(void)
+{
+       log_memstats_stderr("isis fuzztest");
+}
+
+static int comp_line(const void *p1, const void *p2)
+{
+       return strcmp(*(char * const *)p1, *(char * const *)p2);
+}
+
+static char *sortlines(char *in)
+{
+       size_t line_count = 1;
+       size_t rv_len = strlen(in) + 1;
+       size_t rv_pos = 0;
+       char *rv = XMALLOC(MTYPE_TMP, rv_len);
+
+       for (char *c = in; *c; c++) {
+               if (*c == '\n')
+                       line_count++;
+       }
+
+       if (line_count == 1) {
+               strncpy(rv, in, rv_len);
+               return rv;
+       }
+
+       char **lines = XCALLOC(MTYPE_TMP, sizeof(char *)*line_count);
+       char *saveptr = NULL;
+       size_t i = 0;
+
+       for (char *line = strtok_r(in, "\n", &saveptr); line;
+            line = strtok_r(NULL, "\n", &saveptr)) {
+               lines[i++] = line;
+               assert(i <= line_count);
+       }
+
+       line_count = i;
+
+       qsort(lines, line_count, sizeof(char *), comp_line);
+
+       for (i = 0; i < line_count; i++) {
+               int printf_rv = snprintf(rv + rv_pos, rv_len - rv_pos, "%s\n", lines[i]);
+               assert(printf_rv >= 0);
+               rv_pos += printf_rv;
+       }
+
+       XFREE(MTYPE_TMP, lines);
+       return rv;
+}
+
+static int test(FILE *input, FILE *output)
+{
+       struct stream *s = stream_new(TEST_STREAM_SIZE);
+       char buf[TEST_STREAM_SIZE];
+       size_t bytes_read = 0;
+
+       if (!atexit_registered) {
+               atexit(show_meminfo_at_exit);
+               atexit_registered = true;
+       }
+
+       while (STREAM_WRITEABLE(s) && !feof(input)) {
+               bytes_read = fread(buf, 1, STREAM_WRITEABLE(s), input);
+               if (bytes_read == 0)
+                       break;
+               stream_put(s, buf, bytes_read);
+       }
+
+       if (bytes_read && !feof(input)) {
+               fprintf(output, "Too much input data.\n");
+               stream_free(s);
+               return 1;
+       }
+
+       stream_set_getp(s, 0);
+       struct isis_tlvs *tlvs;
+       const char *log;
+       int rv = isis_unpack_tlvs(STREAM_READABLE(s), s, &tlvs, &log);
+
+       if (rv) {
+               fprintf(output, "Could not unpack TLVs:\n%s\n", log);
+               isis_free_tlvs(tlvs);
+               stream_free(s);
+               return 2;
+       }
+
+       fprintf(output, "Unpack log:\n%s", log);
+       const char *s_tlvs = isis_format_tlvs(tlvs);
+       fprintf(output, "Unpacked TLVs:\n%s", s_tlvs);
+
+       struct isis_tlvs *tlv_copy = isis_copy_tlvs(tlvs);
+       isis_free_tlvs(tlvs);
+
+       struct stream *s2 = stream_new(TEST_STREAM_SIZE);
+
+       if (isis_pack_tlvs(tlv_copy, s2, (size_t)-1, false, false)) {
+               fprintf(output, "Could not pack TLVs.\n");
+               assert(0);
+       }
+
+       stream_set_getp(s2, 0);
+       rv = isis_unpack_tlvs(STREAM_READABLE(s2), s2, &tlvs, &log);
+       if (rv) {
+               fprintf(output, "Could not unpack own TLVs:\n%s\n", log);
+               assert(0);
+       }
+
+       char *orig_tlvs = XSTRDUP(MTYPE_TMP, s_tlvs);
+       s_tlvs = isis_format_tlvs(tlvs);
+
+       if (strcmp(orig_tlvs, s_tlvs)) {
+               fprintf(output,
+                       "Deserialized and Serialized LSP seem to differ.\n");
+               fprintf(output, "Re-Unpacked TLVs:\n%s", s_tlvs);
+               assert(0);
+       }
+
+       isis_free_tlvs(tlv_copy);
+       stream_free(s);
+       stream_free(s2);
+
+       struct list *fragments = isis_fragment_tlvs(tlvs, 550);
+       isis_free_tlvs(tlvs);
+       if (!fragments) {
+               XFREE(MTYPE_TMP, orig_tlvs);
+               return 0;
+       }
+
+       s = stream_new(550);
+
+       struct sbuf fragment_format;
+       sbuf_init(&fragment_format, NULL, 0);
+
+       struct listnode *node;
+       for (ALL_LIST_ELEMENTS_RO(fragments, node, tlvs)) {
+               stream_reset(s);
+               int rv = isis_pack_tlvs(tlvs, s, (size_t)-1, false, false);
+               if (rv) {
+                       fprintf(output, "Could not pack fragment, too large.\n");
+                       assert(0);
+               }
+               sbuf_push(&fragment_format, 0, "%s", isis_format_tlvs(tlvs));
+               isis_free_tlvs(tlvs);
+       }
+       list_delete(fragments);
+       stream_free(s);
+
+       char *fragment_content = sortlines((char *)sbuf_buf(&fragment_format));
+       sbuf_free(&fragment_format);
+       char *orig_tlv_content = sortlines(orig_tlvs);
+       XFREE(MTYPE_TMP, orig_tlvs);
+
+       if (strcmp(fragment_content, orig_tlv_content)) {
+               fprintf(output, "Fragmented and unfragmented LSP seem to differ.\n");
+               fprintf(output, "Original:\n%s\nFragmented:\n%s\n",
+                       orig_tlv_content, fragment_content);
+               assert(0);
+       }
+
+       XFREE(MTYPE_TMP, fragment_content);
+       XFREE(MTYPE_TMP, orig_tlv_content);
+
+       return 0;
+}
diff --git a/tests/isisd/test_fuzz_isis_tlv.py b/tests/isisd/test_fuzz_isis_tlv.py
new file mode 100644 (file)
index 0000000..6093847
--- /dev/null
@@ -0,0 +1,6 @@
+import frrtest
+
+class TestFuzzIsisTLV(frrtest.TestMultiOut):
+    program = './test_fuzz_isis_tlv'
+
+TestFuzzIsisTLV.exit_cleanly()
diff --git a/tests/isisd/test_fuzz_isis_tlv_tests.h.gz b/tests/isisd/test_fuzz_isis_tlv_tests.h.gz
new file mode 100644 (file)
index 0000000..3eb0205
Binary files /dev/null and b/tests/isisd/test_fuzz_isis_tlv_tests.h.gz differ
index 8b66ba25649e749c52397e7dce4afc1f32d6aecc..d179ed1d9984c77ae26319ff0f0fb8e94f5cefcd 100644 (file)
@@ -147,6 +147,7 @@ vtysh_cmd_FILES = $(vtysh_scan) \
                  $(top_srcdir)/zebra/zebra_fpm.c \
                  $(top_srcdir)/zebra/zebra_ptm.c \
                  $(top_srcdir)/zebra/zebra_mpls_vty.c \
+                 $(top_srcdir)/zebra/zebra_pw.c \
                  $(top_srcdir)/watchfrr/watchfrr_vty.c \
                  $(BGP_VNC_RFAPI_SRC) $(BGP_VNC_RFP_SRC)
 
index ca280c58720c0d1fe5baad8ddf9f2d851ef6003c..f33c7b9603a10c7ac3a24586dadfb96135e4e13a 100755 (executable)
@@ -85,7 +85,7 @@ foreach (@ARGV) {
             $protocol = "VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ZEBRA|VTYSH_PIMD|VTYSH_EIGRPD";
         }
         elsif ($file =~ /lib\/vrf\.c$/) {
-            $protocol = "VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ZEBRA|VTYSH_EIGRPD|VTYSH_BABELD";
+            $protocol = "VTYSH_ALL";
         }
         elsif ($file =~ /lib\/filter\.c$/) {
             $protocol = "VTYSH_ALL";
index f6a2c9258628ac4add2f7e586b7b8828df87480b..76c42173da84d4ab6e83b1cf0500ea053bb45bb2 100644 (file)
@@ -218,15 +218,27 @@ static int vtysh_client_run_all(struct vtysh_client *head_client,
 {
        struct vtysh_client *client;
        int rc, rc_all = CMD_SUCCESS;
+       int correct_instance = 0, wrong_instance = 0;
 
        for (client = head_client; client; client = client->next) {
                rc = vtysh_client_run(client, line, fp, callback, cbarg);
+               if (rc == CMD_NOT_MY_INSTANCE) {
+                       wrong_instance++;
+                       continue;
+               }
+               correct_instance++;
                if (rc != CMD_SUCCESS) {
                        if (!continue_on_err)
                                return rc;
                        rc_all = rc;
                }
        }
+       if (wrong_instance && !correct_instance && fp) {
+               fprintf(fp,
+                       "%% [%s]: command ignored as it targets an instance that is not running\n",
+                       head_client->name);
+               rc_all = CMD_WARNING_CONFIG_FAILED;
+       }
        return rc_all;
 }
 
@@ -911,6 +923,10 @@ static struct cmd_node interface_node = {
        INTERFACE_NODE, "%s(config-if)# ",
 };
 
+static struct cmd_node pw_node = {
+       PW_NODE, "%s(config-pw)# ",
+};
+
 static struct cmd_node ns_node = {
        NS_NODE, "%s(config-logical-router)# ",
 };
@@ -1406,6 +1422,7 @@ static int vtysh_exit(struct vty *vty)
                vty->node = ENABLE_NODE;
                break;
        case INTERFACE_NODE:
+       case PW_NODE:
        case NS_NODE:
        case VRF_NODE:
        case ZEBRA_NODE:
@@ -1659,6 +1676,15 @@ DEFUNSH(VTYSH_INTERFACE, vtysh_interface, vtysh_interface_cmd,
        return CMD_SUCCESS;
 }
 
+DEFUNSH(VTYSH_ZEBRA, vtysh_pseudowire, vtysh_pseudowire_cmd,
+       "pseudowire IFNAME",
+       "Static pseudowire configuration\n"
+       "Pseudowire name\n")
+{
+       vty->node = PW_NODE;
+       return CMD_SUCCESS;
+}
+
 /* TODO Implement "no interface command in isisd. */
 DEFSH(VTYSH_ZEBRA | VTYSH_RIPD | VTYSH_RIPNGD | VTYSH_OSPFD | VTYSH_OSPF6D
              | VTYSH_EIGRPD,
@@ -2909,6 +2935,7 @@ void vtysh_init_vty(void)
        install_node(&bgp_node, NULL);
        install_node(&rip_node, NULL);
        install_node(&interface_node, NULL);
+       install_node(&pw_node, NULL);
        install_node(&link_params_node, NULL);
        install_node(&ns_node, NULL);
        install_node(&vrf_node, NULL);
@@ -3081,6 +3108,10 @@ void vtysh_init_vty(void)
        install_element(LINK_PARAMS_NODE, &vtysh_exit_interface_cmd);
        install_element(INTERFACE_NODE, &vtysh_quit_interface_cmd);
 
+       install_element(PW_NODE, &vtysh_end_all_cmd);
+       install_element(PW_NODE, &vtysh_exit_interface_cmd);
+       install_element(PW_NODE, &vtysh_quit_interface_cmd);
+
        install_element(NS_NODE, &vtysh_end_all_cmd);
 
        install_element(CONFIG_NODE, &vtysh_ns_cmd);
@@ -3156,6 +3187,7 @@ void vtysh_init_vty(void)
        install_element(CONFIG_NODE, &vtysh_interface_cmd);
        install_element(CONFIG_NODE, &vtysh_no_interface_cmd);
        install_element(CONFIG_NODE, &vtysh_no_interface_vrf_cmd);
+       install_element(CONFIG_NODE, &vtysh_pseudowire_cmd);
        install_element(INTERFACE_NODE, &vtysh_link_params_cmd);
        install_element(ENABLE_NODE, &vtysh_show_running_config_cmd);
        install_element(ENABLE_NODE, &vtysh_copy_running_config_cmd);
index bef4b82d3fb3f336f2bb0c48ca60284163973c61..b0866ec7f3fa20e22ce051041a6c79755e700229 100644 (file)
@@ -47,7 +47,7 @@ DECLARE_MGROUP(MVTYSH)
 #define VTYSH_RMAP       VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_PIMD|VTYSH_EIGRPD
 #define VTYSH_INTERFACE          VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_ISISD|VTYSH_PIMD|VTYSH_NHRPD|VTYSH_EIGRPD|VTYSH_BABELD
 #define VTYSH_NS          VTYSH_ZEBRA
-#define VTYSH_VRF        VTYSH_ZEBRA
+#define VTYSH_VRF        VTYSH_ZEBRA|VTYSH_PIMD
 
 /* vtysh local configuration file. */
 #define VTYSH_DEFAULT_CONFIG "vtysh.conf"
index 74509d1ec81cd4fa9720c097609830ced0f0e9b8..43aff0e3a5271999e4f61f75591628433a54adbe 100644 (file)
@@ -181,6 +181,8 @@ void vtysh_config_parse_line(void *arg, const char *line)
        default:
                if (strncmp(line, "interface", strlen("interface")) == 0)
                        config = config_get(INTERFACE_NODE, line);
+               else if (strncmp(line, "pseudowire", strlen("pseudowire")) == 0)
+                       config = config_get(PW_NODE, line);
                else if (strncmp(line, "logical-router", strlen("ns")) == 0)
                        config = config_get(NS_NODE, line);
                else if (strncmp(line, "vrf", strlen("vrf")) == 0)
index 1aa25b41d030cde9add5717c8a12776b54b9369c..6adb25f322c099f9b9f27cf5284bc20d551c1f33 100644 (file)
@@ -684,9 +684,11 @@ static void daemon_send_ready(void)
 
                fp = fopen(DAEMON_VTY_DIR "/watchfrr.started", "w");
                fclose(fp);
+#if defined HAVE_SYSTEMD
                zlog_notice(
                        "Watchfrr: Notifying Systemd we are up and running");
                systemd_send_started(master, 0);
+#endif
                sent = 1;
        }
 }
index d0a752853914a13a21905794ab31f4fbb4e6e294..7a1321e54674901a0a8eb80b5b4460fc073a226c 100644 (file)
@@ -1,4 +1,4 @@
-Makefile
+!Makefile
 Makefile.in
 *.o
 zebra
diff --git a/zebra/Makefile b/zebra/Makefile
new file mode 100644 (file)
index 0000000..625a716
--- /dev/null
@@ -0,0 +1,10 @@
+all: ALWAYS
+       @$(MAKE) -s -C .. zebra/zebra
+%: ALWAYS
+       @$(MAKE) -s -C .. zebra/$@
+
+Makefile:
+       #nothing
+ALWAYS:
+.PHONY: ALWAYS makefiles
+.SUFFIXES:
diff --git a/zebra/Makefile.am b/zebra/Makefile.am
deleted file mode 100644 (file)
index 67031ea..0000000
+++ /dev/null
@@ -1,96 +0,0 @@
-include ../common.am
-
-## Process this file with automake to produce Makefile.in.
-
-AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib
-DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\"
-INSTALL_SDATA=@INSTALL@ -m 600
-
-LIBCAP = @LIBCAP@
-
-ipforward = @IPFORWARD@
-if_method = @IF_METHOD@
-rt_method = @RT_METHOD@
-rtread_method = @RTREAD_METHOD@
-kernel_method = @KERNEL_METHOD@
-ioctl_method = @IOCTL_METHOD@
-mpls_method = @MPLS_METHOD@
-
-otherobj = $(ioctl_method) $(ipforward) $(if_method) \
-       $(rt_method) $(rtread_method) $(kernel_method) $(mpls_method)
-
-AM_CFLAGS = $(WERROR)
-
-sbin_PROGRAMS = zebra
-module_LTLIBRARIES =
-
-zebra_SOURCES = \
-       zebra_memory.c \
-       zserv.c main.c interface.c connected.c zebra_rib.c zebra_routemap.c \
-       redistribute.c debug.c rtadv.c zebra_vty.c \
-       irdp_main.c irdp_interface.c irdp_packet.c router-id.c \
-       zebra_ptm.c zebra_rnh.c zebra_ptm_redistribute.c \
-       zebra_ns.c zebra_vrf.c zebra_static.c zebra_mpls.c zebra_mpls_vty.c \
-       zebra_mroute.c \
-       label_manager.c \
-       zebra_l2.c \
-       zebra_vxlan.c \
-       # end
-
-zebra_vty.o: zebra_vty_clippy.c
-
-noinst_HEADERS = \
-       zebra_memory.h \
-       connected.h ioctl.h rib.h rt.h zserv.h redistribute.h debug.h rtadv.h \
-       interface.h ipforward.h irdp.h router-id.h kernel_socket.h \
-       rt_netlink.h zebra_fpm_private.h zebra_rnh.h \
-       zebra_ptm_redistribute.h zebra_ptm.h zebra_routemap.h \
-       zebra_ns.h zebra_vrf.h ioctl_solaris.h zebra_static.h zebra_mpls.h \
-       kernel_netlink.h if_netlink.h zebra_mroute.h label_manager.h \
-       zebra_l2.h zebra_vxlan_private.h zebra_vxlan.h
-
-zebra_LDADD = $(otherobj) ../lib/libfrr.la $(LIBCAP)
-
-zebra_DEPENDENCIES = $(otherobj)
-
-if SNMP
-module_LTLIBRARIES += zebra_snmp.la
-endif
-zebra_snmp_la_SOURCES = zebra_snmp.c
-zebra_snmp_la_CFLAGS = $(WERROR) $(SNMP_CFLAGS)
-zebra_snmp_la_LDFLAGS = -avoid-version -module -shared -export-dynamic
-zebra_snmp_la_LIBADD = ../lib/libfrrsnmp.la
-
-if FPM
-module_LTLIBRARIES += zebra_fpm.la
-endif
-zebra_fpm_la_LDFLAGS = -avoid-version -module -shared -export-dynamic
-zebra_fpm_la_LIBADD = $(Q_FPM_PB_CLIENT_LDOPTS)
-zebra_fpm_la_SOURCES = zebra_fpm.c
-if HAVE_NETLINK
-zebra_fpm_la_SOURCES += zebra_fpm_netlink.c
-endif
-if HAVE_PROTOBUF
-zebra_fpm_la_SOURCES += zebra_fpm_protobuf.c
-if DEV_BUILD
-zebra_fpm_la_SOURCES += zebra_fpm_dt.c
-endif
-endif
-
-
-EXTRA_DIST = if_ioctl.c if_ioctl_solaris.c if_netlink.c \
-        if_sysctl.c ipforward_proc.c \
-       ipforward_solaris.c ipforward_sysctl.c rt_netlink.c \
-       rt_socket.c rtread_netlink.c rtread_sysctl.c \
-       rtread_getmsg.c kernel_socket.c kernel_netlink.c \
-       ioctl.c ioctl_solaris.c \
-       zebra_mpls_netlink.c zebra_mpls_openbsd.c zebra_mpls_null.c \
-       GNOME-SMI GNOME-PRODUCT-ZEBRA-MIB
-
-client : client_main.o ../lib/libfrr.la
-       $(CC) -g -o client client_main.o ../liblzebra.la $(LIBS) $(LIB_IPV6)
-
-frrconfdir = $(sysconfdir)
-
-examplesdir = $(exampledir)
-dist_examples_DATA = zebra.conf.sample
index 6aedea1e397aec65e96fff1ed47cd653a1799f6a..25f47bc51a8fa85e9068c0ce18a036f79699f496 100644 (file)
@@ -32,6 +32,7 @@ unsigned long zebra_debug_fpm;
 unsigned long zebra_debug_nht;
 unsigned long zebra_debug_mpls;
 unsigned long zebra_debug_vxlan;
+unsigned long zebra_debug_pw;
 
 DEFUN (show_debugging_zebra,
        show_debugging_zebra_cmd,
@@ -82,6 +83,8 @@ DEFUN (show_debugging_zebra,
                vty_out(vty, "  Zebra next-hop tracking debugging is on\n");
        if (IS_ZEBRA_DEBUG_MPLS)
                vty_out(vty, "  Zebra MPLS debugging is on\n");
+       if (IS_ZEBRA_DEBUG_PW)
+               vty_out(vty, "  Zebra pseudowire debugging is on\n");
 
        return CMD_SUCCESS;
 }
@@ -130,6 +133,21 @@ DEFUN (debug_zebra_vxlan,
        return CMD_WARNING;
 }
 
+DEFUN (debug_zebra_pw,
+       debug_zebra_pw_cmd,
+       "[no] debug zebra pseudowires",
+       "Negate a command or set its defaults\n"
+       DEBUG_STR
+       "Zebra configuration\n"
+       "Debug option set for zebra pseudowires\n")
+{
+       if (strmatch(argv[0]->text, "no"))
+               UNSET_FLAG(zebra_debug_pw, ZEBRA_DEBUG_PW);
+       else
+               SET_FLAG(zebra_debug_pw, ZEBRA_DEBUG_PW);
+       return CMD_WARNING;
+}
+
 DEFUN (debug_zebra_packet,
        debug_zebra_packet_cmd,
        "debug zebra packet [<recv|send>] [detail]",
@@ -419,6 +437,10 @@ static int config_write_debug(struct vty *vty)
                vty_out(vty, "debug zebra vxlan\n");
                write++;
        }
+       if (IS_ZEBRA_DEBUG_PW) {
+               vty_out(vty, "debug zebra pseudowires\n");
+               write++;
+       }
        return write;
 }
 
@@ -431,6 +453,7 @@ void zebra_debug_init(void)
        zebra_debug_fpm = 0;
        zebra_debug_mpls = 0;
        zebra_debug_vxlan = 0;
+       zebra_debug_pw = 0;
 
        install_node(&debug_node, config_write_debug);
 
@@ -440,6 +463,7 @@ void zebra_debug_init(void)
        install_element(ENABLE_NODE, &debug_zebra_nht_cmd);
        install_element(ENABLE_NODE, &debug_zebra_mpls_cmd);
        install_element(ENABLE_NODE, &debug_zebra_vxlan_cmd);
+       install_element(ENABLE_NODE, &debug_zebra_pw_cmd);
        install_element(ENABLE_NODE, &debug_zebra_packet_cmd);
        install_element(ENABLE_NODE, &debug_zebra_kernel_cmd);
        install_element(ENABLE_NODE, &debug_zebra_kernel_msgdump_cmd);
@@ -459,6 +483,7 @@ void zebra_debug_init(void)
        install_element(CONFIG_NODE, &debug_zebra_nht_cmd);
        install_element(CONFIG_NODE, &debug_zebra_mpls_cmd);
        install_element(CONFIG_NODE, &debug_zebra_vxlan_cmd);
+       install_element(CONFIG_NODE, &debug_zebra_pw_cmd);
        install_element(CONFIG_NODE, &debug_zebra_packet_cmd);
        install_element(CONFIG_NODE, &debug_zebra_kernel_cmd);
        install_element(CONFIG_NODE, &debug_zebra_kernel_msgdump_cmd);
index b52bb7d0e982dbf6392025b105e3e67f84271a43..987f9d012543e4b1a7daaad31384cac9cc19b137 100644 (file)
@@ -44,6 +44,8 @@
 
 #define ZEBRA_DEBUG_VXLAN   0x01
 
+#define ZEBRA_DEBUG_PW      0x01
+
 /* Debug related macro. */
 #define IS_ZEBRA_DEBUG_EVENT  (zebra_debug_event & ZEBRA_DEBUG_EVENT)
 
@@ -66,6 +68,7 @@
 #define IS_ZEBRA_DEBUG_NHT  (zebra_debug_nht & ZEBRA_DEBUG_NHT)
 #define IS_ZEBRA_DEBUG_MPLS  (zebra_debug_mpls & ZEBRA_DEBUG_MPLS)
 #define IS_ZEBRA_DEBUG_VXLAN (zebra_debug_vxlan & ZEBRA_DEBUG_VXLAN)
+#define IS_ZEBRA_DEBUG_PW  (zebra_debug_pw & ZEBRA_DEBUG_PW)
 
 extern unsigned long zebra_debug_event;
 extern unsigned long zebra_debug_packet;
@@ -75,6 +78,7 @@ extern unsigned long zebra_debug_fpm;
 extern unsigned long zebra_debug_nht;
 extern unsigned long zebra_debug_mpls;
 extern unsigned long zebra_debug_vxlan;
+extern unsigned long zebra_debug_pw;
 
 extern void zebra_debug_init(void);
 
index 2d5d604a8bbee487e7de138a1e820b53b1105c3c..a65fcb2b8c20eb91d74007d64fd2704ca7bdde76 100644 (file)
@@ -21,6 +21,8 @@
 
 #include <zebra.h>
 
+#ifdef OPEN_BSD
+
 #include "if.h"
 #include "sockunion.h"
 #include "prefix.h"
@@ -328,3 +330,5 @@ void interface_list(struct zebra_ns *zns)
        ifaddr_proc_ipv6();
 #endif /* HAVE_PROC_NET_IF_INET6 */
 }
+
+#endif /* OPEN_BSD */
index fce36ebc1d4af60df3a8b61f45e6ecd4bc38f763..3d53194593c640a432b9737cf58512f3de967b06 100644 (file)
@@ -21,6 +21,8 @@
 
 #include <zebra.h>
 
+#ifdef SUNOS_5
+
 #include "if.h"
 #include "sockunion.h"
 #include "prefix.h"
@@ -358,3 +360,5 @@ struct connected *if_lookup_linklocal(struct interface *ifp)
 
        return NULL;
 }
+
+#endif /* SUNOS_5 */
index acec2db5268002ed1fd911cb42ccc883408a6879..a46657dd2ebfa4f7d97e042a6f6cdd3df6e52ae8 100644 (file)
@@ -21,6 +21,8 @@
 
 #include <zebra.h>
 
+#ifdef GNU_LINUX
+
 /* The following definition is to workaround an issue in the Linux kernel
  * header files with redefinition of 'struct in6_addr' in both
  * netinet/in.h and linux/in6.h.
@@ -768,6 +770,33 @@ int interface_lookup_netlink(struct zebra_ns *zns)
        return 0;
 }
 
+int kernel_interface_set_master(struct interface *master,
+                               struct interface *slave)
+{
+       struct zebra_ns *zns = zebra_ns_lookup(NS_DEFAULT);
+
+       struct {
+               struct nlmsghdr n;
+               struct ifinfomsg ifa;
+               char buf[NL_PKT_BUF_SIZE];
+       } req;
+
+       memset(&req, 0, sizeof req);
+
+       req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
+       req.n.nlmsg_flags = NLM_F_REQUEST;
+       req.n.nlmsg_type = RTM_SETLINK;
+       req.n.nlmsg_pid = zns->netlink_cmd.snl.nl_pid;
+
+       req.ifa.ifi_index = slave->ifindex;
+
+       addattr_l(&req.n, sizeof req, IFLA_MASTER, &master->ifindex, 4);
+       addattr_l(&req.n, sizeof req, IFLA_LINK, &slave->ifindex, 4);
+
+       return netlink_talk(netlink_talk_filter, &req.n, &zns->netlink_cmd, zns,
+                           0);
+}
+
 /* Interface address modification. */
 static int netlink_address(int cmd, int family, struct interface *ifp,
                           struct connected *ifc)
@@ -1218,3 +1247,5 @@ void interface_list(struct zebra_ns *zns)
 {
        interface_lookup_netlink(zns);
 }
+
+#endif /* GNU_LINUX */
index 99b0f9d942fb88f117749f4d912b7bdcc958d9ba..39b7204e8e636ea2f7363e9cd3de6b0c520cc0cc 100644 (file)
@@ -21,6 +21,8 @@
 
 #include <zebra.h>
 
+#if !defined(GNU_LINUX) && !defined(OPEN_BSD) && !defined(SUNOS_5)
+
 #include "if.h"
 #include "sockunion.h"
 #include "prefix.h"
@@ -134,3 +136,5 @@ void interface_list(struct zebra_ns *zns)
        /* Free sysctl buffer. */
        XFREE(MTYPE_TMP, ref);
 }
+
+#endif /* !defined(GNU_LINUX) && !defined(OPEN_BSD) && !defined(SUNOS_5) */
index 03ddf8d3864a73f106b136c90e31b78d7dfac73b..c4d0363994f51c5169f06bd45fe789259edd3c67 100644 (file)
@@ -48,6 +48,7 @@
 #include "zebra/rt_netlink.h"
 #include "zebra/interface.h"
 #include "zebra/zebra_vxlan.h"
+#include "zebra/zebra_static.h"
 
 #define ZEBRA_PTM_SUPPORT
 
@@ -119,8 +120,6 @@ static int if_zebra_new_hook(struct interface *ifp)
                route_table_init_with_delegate(&zebra_if_table_delegate);
 
        ifp->info = zebra_if;
-
-       zebra_vrf_static_route_interface_fixup(ifp);
        return 0;
 }
 
@@ -510,6 +509,8 @@ void if_add_update(struct interface *ifp)
                        zlog_debug(
                                "interface %s vrf %u index %d becomes active.",
                                ifp->name, ifp->vrf_id, ifp->ifindex);
+
+               static_ifindex_update(ifp, true);
        } else {
                if (IS_ZEBRA_DEBUG_KERNEL)
                        zlog_debug("interface %s vrf %u index %d is added.",
@@ -675,6 +676,8 @@ void if_delete_update(struct interface *ifp)
                zlog_debug("interface %s vrf %u index %d is now inactive.",
                           ifp->name, ifp->vrf_id, ifp->ifindex);
 
+       static_ifindex_update(ifp, false);
+
        /* Delete connected routes from the kernel. */
        if_delete_connected(ifp);
 
@@ -714,6 +717,8 @@ void if_handle_vrf_change(struct interface *ifp, vrf_id_t vrf_id)
 
        old_vrf_id = ifp->vrf_id;
 
+       static_ifindex_update(ifp, false);
+
        /* Uninstall connected routes. */
        if_uninstall_connected(ifp);
 
@@ -737,6 +742,8 @@ void if_handle_vrf_change(struct interface *ifp, vrf_id_t vrf_id)
        /* Install connected routes (in new VRF). */
        if_install_connected(ifp);
 
+       static_ifindex_update(ifp, true);
+
        /* Due to connected route change, schedule RIB processing for both old
         * and new VRF.
         */
@@ -745,8 +752,6 @@ void if_handle_vrf_change(struct interface *ifp, vrf_id_t vrf_id)
                           ifp->vrf_id, ifp->name);
        rib_update(old_vrf_id, RIB_UPDATE_IF_CHANGE);
        rib_update(ifp->vrf_id, RIB_UPDATE_IF_CHANGE);
-
-       zebra_vrf_static_route_interface_fixup(ifp);
 }
 
 static void ipv6_ll_address_to_mac(struct in6_addr *address, u_char *mac)
@@ -859,8 +864,6 @@ void if_up(struct interface *ifp)
                           ifp->vrf_id, ifp->name);
        rib_update(ifp->vrf_id, RIB_UPDATE_IF_CHANGE);
 
-       zebra_vrf_static_route_interface_fixup(ifp);
-
        /* Handle interface up for specific types for EVPN. Non-VxLAN interfaces
         * are checked to see if (remote) neighbor entries need to be installed
         * on them for ARP suppression.
index 72d98943ef2faac28ac5a24a982c38bdb42c3598..835f1f4934c826edac851036b0889c9f6a1d7251 100644 (file)
@@ -33,6 +33,8 @@
 #include "zebra/rt.h"
 #include "zebra/interface.h"
 
+#ifndef SUNOS_5
+
 #ifdef HAVE_BSD_LINK_DETECT
 #include <net/if_media.h>
 #endif /* HAVE_BSD_LINK_DETECT*/
@@ -563,3 +565,5 @@ int if_prefix_delete_ipv6(struct interface *ifp, struct connected *ifc)
 #endif /* HAVE_STRUCT_IN6_ALIASREQ */
 
 #endif /* LINUX_IPV6 */
+
+#endif /* !SUNOS_5 */
index df1554ae6f5b20f08b533537a689c04d77a79a35..e8b65925f881815743187831e6ceafaca8a32630 100644 (file)
@@ -21,6 +21,8 @@
 
 #include <zebra.h>
 
+#ifdef SUNOS_5
+
 #include "linklist.h"
 #include "if.h"
 #include "prefix.h"
@@ -398,3 +400,5 @@ int if_prefix_delete_ipv6(struct interface *ifp, struct connected *ifc)
 
        return 0;
 }
+
+#endif /* SUNOS_5 */
index c3dcdda55ffc76a688fb38102c2d5a341ae803b6..2834eeeb9cc51f62921c9f95796f21030a56b481 100644 (file)
@@ -21,6 +21,8 @@
 
 #include <zebra.h>
 
+#ifdef GNU_LINUX
+
 #include "log.h"
 #include "privs.h"
 
@@ -193,3 +195,5 @@ int ipforward_ipv6_off(void)
 
        return ipforward_ipv6();
 }
+
+#endif /* GNU_LINUX */
index 0d6b7dac03c8a3023834f4ff3a6830ef36d3c481..123cf1bd081bdff15b7fb9cb2704ea02cc3307bc 100644 (file)
@@ -20,6 +20,9 @@
  */
 
 #include <zebra.h>
+
+#ifdef SUNOS_5
+
 #include "log.h"
 #include "prefix.h"
 
@@ -153,3 +156,5 @@ int ipforward_ipv6_off(void)
        (void)solaris_nd_set("ip6_forwarding", 0);
        return ipforward_ipv6();
 }
+
+#endif /* SUNOS_5 */
index 00be92bb6d3aaf4cd6ba1ef51c7ace1239b93390..36212a0132826c7082ba727a46b356ec10d29d7b 100644 (file)
@@ -19,6 +19,9 @@
  */
 
 #include <zebra.h>
+
+#if !defined(GNU_LINUX) && !defined(SUNOS_5)
+
 #include "privs.h"
 #include "zebra/ipforward.h"
 
@@ -147,3 +150,5 @@ int ipforward_ipv6_off(void)
                zlog_err("Can't lower privileges");
        return ip6forwarding;
 }
+
+#endif /* !defined(GNU_LINUX) && !defined(SUNOS_5) */
index 7fc2d613328c2f20cf9b507de197f5b2f25ea355..015e11b3a5f4ae093b2b624c7dff1ad22089e823 100644 (file)
@@ -20,6 +20,8 @@
 
 #include <zebra.h>
 
+#ifdef HAVE_NETLINK
+
 #include "linklist.h"
 #include "if.h"
 #include "log.h"
@@ -260,8 +262,9 @@ static int netlink_information_fetch(struct sockaddr_nl *snl,
                return netlink_neigh_change(snl, h, ns_id);
                break;
        default:
-               zlog_warn("Unknown netlink nlmsg_type %d vrf %u\n",
-                         h->nlmsg_type, ns_id);
+               if (IS_ZEBRA_DEBUG_KERNEL)
+                       zlog_debug("Unknown netlink nlmsg_type %d vrf %u\n",
+                                  h->nlmsg_type, ns_id);
                break;
        }
        return 0;
@@ -826,3 +829,5 @@ void kernel_terminate(struct zebra_ns *zns)
                zns->netlink_cmd.sock = -1;
        }
 }
+
+#endif /* HAVE_NETLINK */
index 4b63a3eb04b445273c1ddace96b0427e58ad653a..5ca6a488c31b8171742943185cfdea0d3c23cf65 100644 (file)
@@ -19,6 +19,9 @@
  */
 
 #include <zebra.h>
+
+#ifndef HAVE_NETLINK
+
 #include <net/if_types.h>
 #ifdef __OpenBSD__
 #include <netmpls/mpls.h>
@@ -624,6 +627,7 @@ int ifm_read(struct if_msghdr *ifm)
 #ifdef HAVE_NET_RT_IFLIST
        ifp->stats = ifm->ifm_data;
 #endif /* HAVE_NET_RT_IFLIST */
+       ifp->speed = ifm->ifm_data.ifi_baudrate / 1000000;
 
        if (IS_ZEBRA_DEBUG_KERNEL)
                zlog_debug("%s: interface %s index %d", __func__, ifp->name,
@@ -1376,3 +1380,5 @@ void kernel_terminate(struct zebra_ns *zns)
 {
        return;
 }
+
+#endif /* !HAVE_NETLINK */
index 27a6f3e02762974deb37867aa9fb11ef6e400cd7..f0bdafa35347b2fa53e4e91594b2ec924807d33c 100644 (file)
@@ -299,6 +299,7 @@ int main(int argc, char **argv)
 
        zebra_mpls_init();
        zebra_mpls_vty_init();
+       zebra_pw_vty_init();
 
        /* For debug purpose. */
        /* SET_FLAG (zebra_debug_event, ZEBRA_DEBUG_EVENT); */
index eca2be5eeec7a4160b608d5e3a267aae9c511ab1..de941bcbbe111dc8b39df43c0f862c763146f670 100644 (file)
@@ -89,6 +89,7 @@ struct route_entry {
 #define ROUTE_ENTRY_NEXTHOPS_CHANGED 0x2
 #define ROUTE_ENTRY_CHANGED          0x4
 #define ROUTE_ENTRY_SELECTED_FIB     0x8
+#define ROUTE_ENTRY_LABELS_CHANGED   0x10
 
        /* Nexthop information. */
        u_char nexthop_num;
index 81dffdf44168f2063e83d5489a8260ee49be7c2d..f5f0fa195b380d83f7990f605923fe191000bf46 100644 (file)
@@ -36,13 +36,14 @@ extern int kernel_route_rib(struct prefix *, struct prefix *,
 extern int kernel_address_add_ipv4(struct interface *, struct connected *);
 extern int kernel_address_delete_ipv4(struct interface *, struct connected *);
 extern int kernel_neigh_update(int, int, uint32_t, char *, int);
-
+extern int kernel_interface_set_master(struct interface *master,
+                                      struct interface *slave);
 extern int kernel_add_lsp(zebra_lsp_t *);
 extern int kernel_upd_lsp(zebra_lsp_t *);
 extern int kernel_del_lsp(zebra_lsp_t *);
 extern int mpls_kernel_init(void);
 
-extern int kernel_get_ipmr_sg_stats(void *mroute);
+extern int kernel_get_ipmr_sg_stats(struct zebra_vrf *zvrf, void *mroute);
 extern int kernel_add_vtep(vni_t vni, struct interface *ifp,
                           struct in_addr *vtep_ip);
 extern int kernel_del_vtep(vni_t vni, struct interface *ifp,
index c02774ca646534465f1e60a347b4542de3c57d02..192fffd29c9469eb0adfef8e9c55d8a50e3f8aca 100644 (file)
@@ -19,6 +19,9 @@
  */
 
 #include <zebra.h>
+
+#ifdef HAVE_NETLINK
+
 #include <net/if_arp.h>
 
 /* Hack for GNU libc version 2. */
@@ -503,6 +506,7 @@ static int netlink_route_change_read_multicast(struct sockaddr_nl *snl,
        char gbuf[40];
        char oif_list[256] = "\0";
        vrf_id_t vrf = ns_id;
+       int table;
 
        if (mroute)
                m = mroute;
@@ -518,6 +522,13 @@ static int netlink_route_change_read_multicast(struct sockaddr_nl *snl,
        memset(tb, 0, sizeof tb);
        netlink_parse_rtattr(tb, RTA_MAX, RTM_RTA(rtm), len);
 
+       if (tb[RTA_TABLE])
+               table = *(int *)RTA_DATA(tb[RTA_TABLE]);
+       else
+               table = rtm->rtm_table;
+
+       vrf = vrf_lookup_by_table(table);
+
        if (tb[RTA_IIF])
                iif = *(int *)RTA_DATA(tb[RTA_IIF]);
 
@@ -558,10 +569,12 @@ static int netlink_route_change_read_multicast(struct sockaddr_nl *snl,
                        sprintf(temp, "%s ", ifp->name);
                        strcat(oif_list, temp);
                }
+               struct zebra_vrf *zvrf = zebra_vrf_lookup_by_id(vrf);
                ifp = if_lookup_by_index(iif, vrf);
-               zlog_debug("MCAST %s (%s,%s) IIF: %s OIF: %s jiffies: %lld",
-                          nl_msg_type_to_str(h->nlmsg_type), sbuf, gbuf,
-                          ifp->name, oif_list, m->lastused);
+               zlog_debug(
+                       "MCAST VRF: %s(%d) %s (%s,%s) IIF: %s OIF: %s jiffies: %lld",
+                       zvrf->vrf->name, vrf, nl_msg_type_to_str(h->nlmsg_type),
+                       sbuf, gbuf, ifp->name, oif_list, m->lastused);
        }
        return 0;
 }
@@ -1503,7 +1516,7 @@ skip:
                            0);
 }
 
-int kernel_get_ipmr_sg_stats(void *in)
+int kernel_get_ipmr_sg_stats(struct zebra_vrf *zvrf, void *in)
 {
        int suc = 0;
        struct mcast_route_data *mr = (struct mcast_route_data *)in;
@@ -1523,13 +1536,14 @@ int kernel_get_ipmr_sg_stats(void *in)
        req.n.nlmsg_flags = NLM_F_REQUEST;
        req.n.nlmsg_pid = zns->netlink_cmd.snl.nl_pid;
 
-       req.ndm.ndm_family = AF_INET;
+       req.ndm.ndm_family = RTNL_FAMILY_IPMR;
        req.n.nlmsg_type = RTM_GETROUTE;
 
        addattr_l(&req.n, sizeof(req), RTA_IIF, &mroute->ifindex, 4);
        addattr_l(&req.n, sizeof(req), RTA_OIF, &mroute->ifindex, 4);
        addattr_l(&req.n, sizeof(req), RTA_SRC, &mroute->sg.src.s_addr, 4);
        addattr_l(&req.n, sizeof(req), RTA_DST, &mroute->sg.grp.s_addr, 4);
+       addattr_l(&req.n, sizeof(req), RTA_TABLE, &zvrf->table_id, 4);
 
        suc = netlink_talk(netlink_route_change_read_multicast, &req.n,
                           &zns->netlink_cmd, zns, 0);
@@ -1690,17 +1704,17 @@ static int netlink_macfdb_change(struct sockaddr_nl *snl, struct nlmsghdr *h,
                return 0;
        }
 
-       if (RTA_PAYLOAD(tb[NDA_LLADDR]) != ETHER_ADDR_LEN) {
+       if (RTA_PAYLOAD(tb[NDA_LLADDR]) != ETH_ALEN) {
                zlog_warn(
-                       "%s family %s IF %s(%u) brIF %u - LLADDR is not MAC, len %ld",
+                       "%s family %s IF %s(%u) brIF %u - LLADDR is not MAC, len %lu",
                        nl_msg_type_to_str(h->nlmsg_type),
                        nl_family_to_str(ndm->ndm_family), ifp->name,
                        ndm->ndm_ifindex, zif->brslave_info.bridge_ifindex,
-                       RTA_PAYLOAD(tb[NDA_LLADDR]));
+                       (unsigned long)RTA_PAYLOAD(tb[NDA_LLADDR]));
                return 0;
        }
 
-       memcpy(&mac, RTA_DATA(tb[NDA_LLADDR]), ETHER_ADDR_LEN);
+       memcpy(&mac, RTA_DATA(tb[NDA_LLADDR]), ETH_ALEN);
 
        if ((NDA_VLAN <= NDA_MAX) && tb[NDA_VLAN]) {
                vid_present = 1;
@@ -2019,18 +2033,18 @@ static int netlink_ipneigh_change(struct sockaddr_nl *snl, struct nlmsghdr *h,
 
        if (h->nlmsg_type == RTM_NEWNEIGH) {
                if (tb[NDA_LLADDR]) {
-                       if (RTA_PAYLOAD(tb[NDA_LLADDR]) != ETHER_ADDR_LEN) {
+                       if (RTA_PAYLOAD(tb[NDA_LLADDR]) != ETH_ALEN) {
                                zlog_warn(
-                                       "%s family %s IF %s(%u) - LLADDR is not MAC, len %ld",
+                                       "%s family %s IF %s(%u) - LLADDR is not MAC, len %lu",
                                        nl_msg_type_to_str(h->nlmsg_type),
                                        nl_family_to_str(ndm->ndm_family),
                                        ifp->name, ndm->ndm_ifindex,
-                                       RTA_PAYLOAD(tb[NDA_LLADDR]));
+                                       (unsigned long)RTA_PAYLOAD(tb[NDA_LLADDR]));
                                return 0;
                        }
 
                        mac_present = 1;
-                       memcpy(&mac, RTA_DATA(tb[NDA_LLADDR]), ETHER_ADDR_LEN);
+                       memcpy(&mac, RTA_DATA(tb[NDA_LLADDR]), ETH_ALEN);
                }
 
                ext_learned = (ndm->ndm_flags & NTF_EXT_LEARNED) ? 1 : 0;
@@ -2442,3 +2456,5 @@ void clear_nhlfe_installed(zebra_lsp_t *lsp)
                UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
        }
 }
+
+#endif /* HAVE_NETLINK */
index 827d3987041dc14c37904edf1494b8602c0f0f09..4e4d726b4618042ad7878bc0f073a7d40582bc39 100644 (file)
@@ -20,6 +20,9 @@
  */
 
 #include <zebra.h>
+
+#ifndef HAVE_NETLINK
+
 #ifdef __OpenBSD__
 #include <netmpls/mpls.h>
 #endif
@@ -406,7 +409,7 @@ int kernel_neigh_update(int add, int ifindex, uint32_t addr, char *lla,
        return 0;
 }
 
-extern int kernel_get_ipmr_sg_stats(void *mroute)
+extern int kernel_get_ipmr_sg_stats(struct zebra_vrf *zvrf, void *mroute)
 {
        return 0;
 }
@@ -443,3 +446,11 @@ int kernel_del_neigh(struct interface *ifp, struct ipaddr *ip)
 {
        return 0;
 }
+
+extern int kernel_interface_set_master(struct interface *master,
+                                      struct interface *slave)
+{
+       return 0;
+}
+
+#endif /* !HAVE_NETLINK */
index 5384231f88cb87b542e79382e6934f31d1794e1b..1bba003a0a084820637d5b813cbc73706d0362a7 100644 (file)
@@ -21,6 +21,8 @@
 
 #include <zebra.h>
 
+#ifdef SUNOS_5
+
 #include "prefix.h"
 #include "log.h"
 #include "if.h"
@@ -258,3 +260,5 @@ void neigh_read(struct zebra_ns *zns)
 void neigh_read_for_vlan(struct zebra_ns *zns, struct interface *vlan_if)
 {
 }
+
+#endif /* SUNOS_5 */
index 304f441367b1aa68ec674d33eaf6477d8d6f1e25..f38cba65e737199c7880295c3b92c617fb2bdd8d 100644 (file)
@@ -21,6 +21,8 @@
 
 #include <zebra.h>
 
+#ifdef GNU_LINUX
+
 #include "vty.h"
 #include "zebra/zserv.h"
 #include "zebra/rt_netlink.h"
@@ -50,3 +52,5 @@ void neigh_read_for_vlan(struct zebra_ns *zns, struct interface *vlan_if)
 {
        netlink_neigh_read_for_vlan(zns, vlan_if);
 }
+
+#endif /* GNU_LINUX */
index d3e2eb6face03eb44ab16840929ba684786f70a8..53ed0e7906be83d7915be2d19535024689bae939 100644 (file)
@@ -21,6 +21,8 @@
 
 #include <zebra.h>
 
+#if !defined(GNU_LINUX) && !defined(SUNOS_5)
+
 #include "memory.h"
 #include "zebra_memory.h"
 #include "log.h"
@@ -90,3 +92,5 @@ void neigh_read(struct zebra_ns *zns)
 void neigh_read_for_vlan(struct zebra_ns *zns, struct interface *vlan_if)
 {
 }
+
+#endif /* !defined(GNU_LINUX) && !defined(SUNOS_5) */
diff --git a/zebra/subdir.am b/zebra/subdir.am
new file mode 100644 (file)
index 0000000..0391cab
--- /dev/null
@@ -0,0 +1,133 @@
+#
+# zebra
+#
+
+if ZEBRA
+sbin_PROGRAMS += zebra/zebra
+dist_examples_DATA += zebra/zebra.conf.sample
+
+if SNMP
+module_LTLIBRARIES += zebra/zebra_snmp.la
+endif
+if FPM
+module_LTLIBRARIES += zebra/zebra_fpm.la
+endif
+
+## endif ZEBRA
+endif
+
+zebra_zebra_LDADD = lib/libfrr.la $(LIBCAP)
+zebra_zebra_SOURCES = \
+       zebra/connected.c \
+       zebra/debug.c \
+       zebra/if_ioctl.c \
+       zebra/if_ioctl_solaris.c \
+       zebra/if_netlink.c \
+       zebra/if_sysctl.c \
+       zebra/interface.c \
+       zebra/ioctl.c \
+       zebra/ioctl_solaris.c \
+       zebra/ipforward_proc.c \
+       zebra/ipforward_solaris.c \
+       zebra/ipforward_sysctl.c \
+       zebra/irdp_interface.c \
+       zebra/irdp_main.c \
+       zebra/irdp_packet.c \
+       zebra/kernel_netlink.c \
+       zebra/kernel_socket.c \
+       zebra/label_manager.c \
+       zebra/main.c \
+       zebra/redistribute.c \
+       zebra/router-id.c \
+       zebra/rt_netlink.c \
+       zebra/rt_socket.c \
+       zebra/rtadv.c \
+       zebra/rtread_getmsg.c \
+       zebra/rtread_netlink.c \
+       zebra/rtread_sysctl.c \
+       zebra/zebra_l2.c \
+       zebra/zebra_memory.c \
+       zebra/zebra_mpls.c \
+       zebra/zebra_mpls_netlink.c \
+       zebra/zebra_mpls_openbsd.c \
+       zebra/zebra_mpls_null.c \
+       zebra/zebra_mpls_vty.c \
+       zebra/zebra_mroute.c \
+       zebra/zebra_ns.c \
+       zebra/zebra_ptm.c \
+       zebra/zebra_ptm_redistribute.c \
+       zebra/zebra_pw.c \
+       zebra/zebra_rib.c \
+       zebra/zebra_rnh.c \
+       zebra/zebra_routemap.c \
+       zebra/zebra_static.c \
+       zebra/zebra_vrf.c \
+       zebra/zebra_vty.c \
+       zebra/zebra_vxlan.c \
+       zebra/zserv.c \
+       # end
+
+zebra/zebra_vty_clippy.c: $(CLIPPY_DEPS)
+zebra/zebra_vty.$(OBJEXT): zebra/zebra_vty_clippy.c
+
+noinst_HEADERS += \
+       zebra/connected.h \
+       zebra/debug.h \
+       zebra/if_netlink.h \
+       zebra/interface.h \
+       zebra/ioctl.h \
+       zebra/ioctl_solaris.h \
+       zebra/ipforward.h \
+       zebra/irdp.h \
+       zebra/kernel_netlink.h \
+       zebra/kernel_socket.h \
+       zebra/label_manager.h \
+       zebra/redistribute.h \
+       zebra/rib.h \
+       zebra/router-id.h \
+       zebra/rt.h \
+       zebra/rt_netlink.h \
+       zebra/rtadv.h \
+       zebra/zebra_fpm_private.h \
+       zebra/zebra_l2.h \
+       zebra/zebra_memory.h \
+       zebra/zebra_mpls.h \
+       zebra/zebra_mroute.h \
+       zebra/zebra_ns.h \
+       zebra/zebra_ptm.h \
+       zebra/zebra_ptm_redistribute.h \
+       zebra/zebra_pw.h \
+       zebra/zebra_rnh.h \
+       zebra/zebra_routemap.h \
+       zebra/zebra_static.h \
+       zebra/zebra_vrf.h \
+       zebra/zebra_vxlan.h \
+       zebra/zebra_vxlan_private.h \
+       zebra/zserv.h \
+       # end
+
+zebra_zebra_snmp_la_SOURCES = zebra/zebra_snmp.c
+zebra_zebra_snmp_la_CFLAGS = $(WERROR) $(SNMP_CFLAGS)
+zebra_zebra_snmp_la_LDFLAGS = -avoid-version -module -shared -export-dynamic
+zebra_zebra_snmp_la_LIBADD = lib/libfrrsnmp.la
+
+zebra_zebra_fpm_la_LDFLAGS = -avoid-version -module -shared -export-dynamic
+zebra_zebra_fpm_la_LIBADD = $(Q_FPM_PB_CLIENT_LDOPTS)
+zebra_zebra_fpm_la_SOURCES = zebra/zebra_fpm.c
+zebra_zebra_fpm_la_SOURCES += zebra/zebra_fpm_netlink.c
+if HAVE_PROTOBUF
+zebra_zebra_fpm_la_SOURCES += zebra/zebra_fpm_protobuf.c
+if DEV_BUILD
+zebra_zebra_fpm_la_SOURCES += zebra/zebra_fpm_dt.c
+endif
+endif
+
+EXTRA_DIST += \
+       zebra/GNOME-SMI \
+       zebra/GNOME-PRODUCT-ZEBRA-MIB \
+       # end
+
+# -- unmaintained --
+# noinst_PROGRAMS += zebra/client
+# zebra_client_SOURCES = zebra/client_main.c
+# zebra_client_LDADD = lib/libfrr.la
index 862049cb857c41c8f67533575e890546fed72bbc..28f795663939aa4250cba15bb3174be33c294266 100644 (file)
@@ -24,6 +24,8 @@
 
 #include <zebra.h>
 
+#ifdef HAVE_NETLINK
+
 #include "log.h"
 #include "rib.h"
 #include "vty.h"
@@ -457,3 +459,5 @@ int zfpm_netlink_encode_route(int cmd, rib_dest_t *dest, struct route_entry *re,
 
        return netlink_route_info_encode(ri, in_buf, in_buf_len);
 }
+
+#endif /* HAVE_NETLINK */
index e44e5d2e6b52895c439fabba95f7954d49ef14c1..d1ab2dbb853d4ddd1233b0bdfcd9c52fa06e5d1f 100644 (file)
@@ -2222,7 +2222,7 @@ found:
                return 0;
 
        SET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
-       SET_FLAG(re->status, ROUTE_ENTRY_NEXTHOPS_CHANGED);
+       SET_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED);
        rib_queue_add(rn);
 
        return 0;
@@ -2405,7 +2405,7 @@ void mpls_ldp_ftn_uninstall_all(struct zebra_vrf *zvrf, int afi)
                                nexthop_del_labels(nexthop);
                                SET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
                                SET_FLAG(re->status,
-                                        ROUTE_ENTRY_NEXTHOPS_CHANGED);
+                                        ROUTE_ENTRY_LABELS_CHANGED);
                                update = 1;
                        }
 
index c5053563b906e28d00e9ad93ee9afad61272fd3a..8b30783a9a591ba652a4b4fae905e879f9e6551b 100644 (file)
@@ -19,6 +19,9 @@
  */
 
 #include <zebra.h>
+
+#ifdef HAVE_NETLINK
+
 #include "zebra/rt.h"
 #include "zebra/rt_netlink.h"
 #include "zebra/zebra_mpls.h"
@@ -105,3 +108,5 @@ int mpls_kernel_init(void)
 
        return 0;
 };
+
+#endif /* HAVE_NETLINK */
index a9da5c29c6d61a1e0d1673d8002ed2b61ddf4c19..e4dc570fd92a57b2bc9017c7084afbb4ba675ab5 100644 (file)
@@ -22,6 +22,8 @@
 #include "zebra/rt.h"
 #include "zebra/zebra_mpls.h"
 
+#if !defined(HAVE_NETLINK) && !defined(OPEN_BSD)
+
 int kernel_add_lsp(zebra_lsp_t *lsp)
 {
        return 0;
@@ -38,3 +40,5 @@ int mpls_kernel_init(void)
 {
        return -1;
 };
+
+#endif /* !defined(HAVE_NETLINK) && !defined(OPEN_BSD) */
index fc1df9227f6f43321f5892f12fb1e1bcd17af4be..119cd5b700c2aa62bebc1675cc81fa6eeda1c0ae 100644 (file)
@@ -19,6 +19,9 @@
  */
 
 #include <zebra.h>
+
+#ifdef OPEN_BSD
+
 #include <netmpls/mpls.h>
 #include "zebra/rt.h"
 #include "zebra/zebra_mpls.h"
@@ -34,6 +37,7 @@ extern struct zebra_privs_t zserv_privs;
 struct {
        u_int32_t rtseq;
        int fd;
+       int ioctl_fd;
 } kr_state;
 
 static int kernel_send_rtmsg_v4(int action, mpls_label_t in_label,
@@ -327,6 +331,85 @@ int kernel_del_lsp(zebra_lsp_t *lsp)
        return ret;
 }
 
+static int kmpw_install(struct zebra_pw *pw)
+{
+       struct ifreq ifr;
+       struct ifmpwreq imr;
+       struct sockaddr_storage ss;
+       struct sockaddr_in *sa_in = (struct sockaddr_in *)&ss;
+       struct sockaddr_in6 *sa_in6 = (struct sockaddr_in6 *)&ss;
+
+       memset(&imr, 0, sizeof(imr));
+       switch (pw->type) {
+       case PW_TYPE_ETHERNET:
+               imr.imr_type = IMR_TYPE_ETHERNET;
+               break;
+       case PW_TYPE_ETHERNET_TAGGED:
+               imr.imr_type = IMR_TYPE_ETHERNET_TAGGED;
+               break;
+       default:
+               zlog_err("%s: unhandled pseudowire type (%#X)", __func__,
+                        pw->type);
+               return -1;
+       }
+
+       if (pw->flags & F_PSEUDOWIRE_CWORD)
+               imr.imr_flags |= IMR_FLAG_CONTROLWORD;
+
+       /* pseudowire nexthop */
+       memset(&ss, 0, sizeof(ss));
+       switch (pw->af) {
+       case AF_INET:
+               sa_in->sin_family = AF_INET;
+               sa_in->sin_len = sizeof(struct sockaddr_in);
+               sa_in->sin_addr = pw->nexthop.ipv4;
+               break;
+       case AF_INET6:
+               sa_in6->sin6_family = AF_INET6;
+               sa_in6->sin6_len = sizeof(struct sockaddr_in6);
+               sa_in6->sin6_addr = pw->nexthop.ipv6;
+               break;
+       default:
+               zlog_err("%s: unhandled pseudowire address-family (%u)",
+                        __func__, pw->af);
+               return -1;
+       }
+       memcpy(&imr.imr_nexthop, (struct sockaddr *)&ss,
+              sizeof(imr.imr_nexthop));
+
+       /* pseudowire local/remote labels */
+       imr.imr_lshim.shim_label = pw->local_label;
+       imr.imr_rshim.shim_label = pw->remote_label;
+
+       /* ioctl */
+       memset(&ifr, 0, sizeof(ifr));
+       strlcpy(ifr.ifr_name, pw->ifname, sizeof(ifr.ifr_name));
+       ifr.ifr_data = (caddr_t)&imr;
+       if (ioctl(kr_state.ioctl_fd, SIOCSETMPWCFG, &ifr) == -1) {
+               zlog_err("ioctl SIOCSETMPWCFG: %s", safe_strerror(errno));
+               return -1;
+       }
+
+       return 0;
+}
+
+static int kmpw_uninstall(struct zebra_pw *pw)
+{
+       struct ifreq ifr;
+       struct ifmpwreq imr;
+
+       memset(&ifr, 0, sizeof(ifr));
+       memset(&imr, 0, sizeof(imr));
+       strlcpy(ifr.ifr_name, pw->ifname, sizeof(ifr.ifr_name));
+       ifr.ifr_data = (caddr_t)&imr;
+       if (ioctl(kr_state.ioctl_fd, SIOCSETMPWCFG, &ifr) == -1) {
+               zlog_err("ioctl SIOCSETMPWCFG: %s", safe_strerror(errno));
+               return -1;
+       }
+
+       return 0;
+}
+
 #define MAX_RTSOCK_BUF 128 * 1024
 int mpls_kernel_init(void)
 {
@@ -338,6 +421,12 @@ int mpls_kernel_init(void)
                return -1;
        }
 
+       if ((kr_state.ioctl_fd = socket(AF_INET, SOCK_DGRAM | SOCK_NONBLOCK, 0))
+           == -1) {
+               zlog_warn("%s: ioctl socket", __func__);
+               return -1;
+       }
+
        /* grow receive buffer, don't wanna miss messages */
        optlen = sizeof(default_rcvbuf);
        if (getsockopt(kr_state.fd, SOL_SOCKET, SO_RCVBUF, &default_rcvbuf,
@@ -356,5 +445,11 @@ int mpls_kernel_init(void)
 
        kr_state.rtseq = 1;
 
+       /* register hook to install/uninstall pseudowires */
+       hook_register(pw_install, kmpw_install);
+       hook_register(pw_uninstall, kmpw_uninstall);
+
        return 0;
 }
+
+#endif /* OPEN_BSD */
index c00498171d84e11e1868ad2891ff914953f0288d..c4d674df23b43c9078d3baca6d5f92795135ae9a 100644 (file)
@@ -30,6 +30,7 @@
 #include "zebra/zebra_vrf.h"
 #include "zebra/zebra_mroute.h"
 #include "zebra/rt.h"
+#include "zebra/debug.h"
 
 int zebra_ipmr_route_stats(struct zserv *client, int fd, u_short length,
                           struct zebra_vrf *zvrf)
@@ -38,18 +39,22 @@ int zebra_ipmr_route_stats(struct zserv *client, int fd, u_short length,
        struct stream *s;
        int suc;
 
-       char sbuf[40];
-       char gbuf[40];
-
        memset(&mroute, 0, sizeof(mroute));
        stream_get(&mroute.sg.src, client->ibuf, 4);
        stream_get(&mroute.sg.grp, client->ibuf, 4);
        mroute.ifindex = stream_getl(client->ibuf);
 
-       strcpy(sbuf, inet_ntoa(mroute.sg.src));
-       strcpy(gbuf, inet_ntoa(mroute.sg.grp));
+       if (IS_ZEBRA_DEBUG_KERNEL) {
+               char sbuf[40];
+               char gbuf[40];
+
+               strcpy(sbuf, inet_ntoa(mroute.sg.src));
+               strcpy(gbuf, inet_ntoa(mroute.sg.grp));
+
+               zlog_debug("Asking for (%s,%s) mroute information", sbuf, gbuf);
+       }
 
-       suc = kernel_get_ipmr_sg_stats(&mroute);
+       suc = kernel_get_ipmr_sg_stats(zvrf, &mroute);
 
        s = client->obuf;
 
diff --git a/zebra/zebra_pw.c b/zebra/zebra_pw.c
new file mode 100644 (file)
index 0000000..4f1d8b0
--- /dev/null
@@ -0,0 +1,533 @@
+/* Zebra PW code
+ * Copyright (C) 2016 Volta Networks, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ */
+
+#include <zebra.h>
+
+#include "log.h"
+#include "memory.h"
+#include "thread.h"
+#include "command.h"
+#include "vrf.h"
+
+#include "zebra/debug.h"
+#include "zebra/rib.h"
+#include "zebra/zserv.h"
+#include "zebra/zebra_rnh.h"
+#include "zebra/zebra_vrf.h"
+#include "zebra/zebra_pw.h"
+
+DEFINE_MTYPE_STATIC(LIB, PW, "Pseudowire")
+
+DEFINE_QOBJ_TYPE(zebra_pw)
+
+DEFINE_HOOK(pw_install, (struct zebra_pw * pw), (pw))
+DEFINE_HOOK(pw_uninstall, (struct zebra_pw * pw), (pw))
+
+#define MPLS_NO_LABEL MPLS_INVALID_LABEL
+
+extern struct zebra_t zebrad;
+
+static int zebra_pw_enabled(struct zebra_pw *);
+static void zebra_pw_install(struct zebra_pw *);
+static void zebra_pw_uninstall(struct zebra_pw *);
+static int zebra_pw_install_retry(struct thread *);
+static int zebra_pw_check_reachability(struct zebra_pw *);
+static void zebra_pw_update_status(struct zebra_pw *, int);
+
+static inline int zebra_pw_compare(const struct zebra_pw *a,
+                                  const struct zebra_pw *b)
+{
+       return (strcmp(a->ifname, b->ifname));
+}
+
+RB_GENERATE(zebra_pw_head, zebra_pw, pw_entry, zebra_pw_compare)
+RB_GENERATE(zebra_static_pw_head, zebra_pw, static_pw_entry, zebra_pw_compare)
+
+struct zebra_pw *zebra_pw_add(struct zebra_vrf *zvrf, const char *ifname,
+                             uint8_t protocol, struct zserv *client)
+{
+       struct zebra_pw *pw;
+
+       if (IS_ZEBRA_DEBUG_PW)
+               zlog_debug("%u: adding pseudowire %s protocol %s",
+                          zvrf_id(zvrf), ifname, zebra_route_string(protocol));
+
+       pw = XCALLOC(MTYPE_PW, sizeof(*pw));
+       strlcpy(pw->ifname, ifname, sizeof(pw->ifname));
+       pw->protocol = protocol;
+       pw->vrf_id = zvrf_id(zvrf);
+       pw->client = client;
+       pw->status = PW_STATUS_UP;
+       pw->local_label = MPLS_NO_LABEL;
+       pw->remote_label = MPLS_NO_LABEL;
+       pw->flags = F_PSEUDOWIRE_CWORD;
+
+       RB_INSERT(zebra_pw_head, &zvrf->pseudowires, pw);
+       if (pw->protocol == ZEBRA_ROUTE_STATIC) {
+               RB_INSERT(zebra_static_pw_head, &zvrf->static_pseudowires, pw);
+               QOBJ_REG(pw, zebra_pw);
+       }
+
+       return pw;
+}
+
+void zebra_pw_del(struct zebra_vrf *zvrf, struct zebra_pw *pw)
+{
+       if (IS_ZEBRA_DEBUG_PW)
+               zlog_debug("%u: deleting pseudowire %s protocol %s", pw->vrf_id,
+                          pw->ifname, zebra_route_string(pw->protocol));
+
+       /* remove nexthop tracking */
+       zebra_deregister_rnh_pseudowire(pw->vrf_id, pw);
+
+       /* uninstall */
+       if (pw->status == PW_STATUS_UP)
+               hook_call(pw_uninstall, pw);
+       else if (pw->install_retry_timer)
+               THREAD_TIMER_OFF(pw->install_retry_timer);
+
+       /* unlink and release memory */
+       RB_REMOVE(zebra_pw_head, &zvrf->pseudowires, pw);
+       if (pw->protocol == ZEBRA_ROUTE_STATIC)
+               RB_REMOVE(zebra_static_pw_head, &zvrf->static_pseudowires, pw);
+       XFREE(MTYPE_PW, pw);
+}
+
+void zebra_pw_change(struct zebra_pw *pw, ifindex_t ifindex, int type, int af,
+                    union g_addr *nexthop, uint32_t local_label,
+                    uint32_t remote_label, uint8_t flags,
+                    union pw_protocol_fields *data)
+{
+       zebra_deregister_rnh_pseudowire(pw->vrf_id, pw);
+
+       pw->ifindex = ifindex;
+       pw->type = type;
+       pw->af = af;
+       pw->nexthop = *nexthop;
+       pw->local_label = local_label;
+       pw->remote_label = remote_label;
+       pw->flags = flags;
+       pw->data = *data;
+
+       if (zebra_pw_enabled(pw))
+               zebra_register_rnh_pseudowire(pw->vrf_id, pw);
+       else
+               zebra_pw_uninstall(pw);
+}
+
+struct zebra_pw *zebra_pw_find(struct zebra_vrf *zvrf, const char *ifname)
+{
+       struct zebra_pw pw;
+       strlcpy(pw.ifname, ifname, sizeof(pw.ifname));
+       return (RB_FIND(zebra_pw_head, &zvrf->pseudowires, &pw));
+}
+
+static int zebra_pw_enabled(struct zebra_pw *pw)
+{
+       if (pw->protocol == ZEBRA_ROUTE_STATIC) {
+               if (pw->local_label == MPLS_NO_LABEL
+                   || pw->remote_label == MPLS_NO_LABEL || pw->af == AF_UNSPEC)
+                       return 0;
+               return 1;
+       } else
+               return pw->enabled;
+}
+
+void zebra_pw_update(struct zebra_pw *pw)
+{
+       if (zebra_pw_check_reachability(pw) < 0) {
+               zebra_pw_uninstall(pw);
+               /* wait for NHT and try again later */
+       } else {
+               /*
+                * Install or reinstall the pseudowire (e.g. to update
+                * parameters like the nexthop or the use of the control word).
+                */
+               zebra_pw_install(pw);
+       }
+}
+
+static void zebra_pw_install(struct zebra_pw *pw)
+{
+       if (IS_ZEBRA_DEBUG_PW)
+               zlog_debug("%u: installing pseudowire %s protocol %s",
+                          pw->vrf_id, pw->ifname,
+                          zebra_route_string(pw->protocol));
+
+       if (hook_call(pw_install, pw)) {
+               zebra_pw_install_failure(pw);
+               return;
+       }
+
+       if (pw->status == PW_STATUS_DOWN)
+               zebra_pw_update_status(pw, PW_STATUS_UP);
+}
+
+static void zebra_pw_uninstall(struct zebra_pw *pw)
+{
+       if (pw->status == PW_STATUS_DOWN)
+               return;
+
+       if (IS_ZEBRA_DEBUG_PW)
+               zlog_debug("%u: uninstalling pseudowire %s protocol %s",
+                          pw->vrf_id, pw->ifname,
+                          zebra_route_string(pw->protocol));
+
+       /* ignore any possible error */
+       hook_call(pw_uninstall, pw);
+
+       if (zebra_pw_enabled(pw))
+               zebra_pw_update_status(pw, PW_STATUS_DOWN);
+}
+
+/*
+ * Installation of the pseudowire in the kernel or hardware has failed. This
+ * function will notify the pseudowire client about the failure and schedule
+ * to retry the installation later. This function can be called by an external
+ * agent that performs the pseudowire installation in an asynchronous way.
+ */
+void zebra_pw_install_failure(struct zebra_pw *pw)
+{
+       if (IS_ZEBRA_DEBUG_PW)
+               zlog_debug(
+                       "%u: failed installing pseudowire %s, "
+                       "scheduling retry in %u seconds",
+                       pw->vrf_id, pw->ifname, PW_INSTALL_RETRY_INTERVAL);
+
+       /* schedule to retry later */
+       THREAD_TIMER_OFF(pw->install_retry_timer);
+       thread_add_timer(zebrad.master, zebra_pw_install_retry, pw,
+                        PW_INSTALL_RETRY_INTERVAL, &pw->install_retry_timer);
+
+       zebra_pw_update_status(pw, PW_STATUS_DOWN);
+}
+
+static int zebra_pw_install_retry(struct thread *thread)
+{
+       struct zebra_pw *pw = THREAD_ARG(thread);
+
+       pw->install_retry_timer = NULL;
+       zebra_pw_install(pw);
+
+       return 0;
+}
+
+static void zebra_pw_update_status(struct zebra_pw *pw, int status)
+{
+       pw->status = status;
+       if (pw->client)
+               zsend_pw_update(pw->client, pw);
+}
+
+static int zebra_pw_check_reachability(struct zebra_pw *pw)
+{
+       struct route_entry *re;
+       struct nexthop *nexthop;
+
+       /* TODO: consider GRE/L2TPv3 tunnels in addition to MPLS LSPs */
+
+       /* find route to the remote end of the pseudowire */
+       re = rib_match(family2afi(pw->af), SAFI_UNICAST, pw->vrf_id,
+                      &pw->nexthop, NULL);
+       if (!re) {
+               if (IS_ZEBRA_DEBUG_PW)
+                       zlog_warn("%s: no route found for %s", __func__,
+                                 pw->ifname);
+               return -1;
+       }
+
+       /*
+        * Need to ensure that there's a label binding for all nexthops.
+        * Otherwise, ECMP for this route could render the pseudowire unusable.
+        */
+       for (ALL_NEXTHOPS(re->nexthop, nexthop)) {
+               if (!nexthop->nh_label) {
+                       if (IS_ZEBRA_DEBUG_PW)
+                               zlog_warn("%s: unlabeled route for %s",
+                                         __func__, pw->ifname);
+                       return -1;
+               }
+       }
+
+       return 0;
+}
+
+void zebra_pw_client_close(struct zserv *client)
+{
+       struct vrf *vrf;
+       struct zebra_vrf *zvrf;
+       struct zebra_pw *pw, *tmp;
+
+       RB_FOREACH(vrf, vrf_id_head, &vrfs_by_id)
+       {
+               zvrf = vrf->info;
+               RB_FOREACH_SAFE(pw, zebra_pw_head, &zvrf->pseudowires, tmp)
+               {
+                       if (pw->client != client)
+                               continue;
+                       zebra_pw_del(zvrf, pw);
+               }
+       }
+}
+
+void zebra_pw_init(struct zebra_vrf *zvrf)
+{
+       RB_INIT(zebra_pw_head, &zvrf->pseudowires);
+       RB_INIT(zebra_static_pw_head, &zvrf->static_pseudowires);
+}
+
+void zebra_pw_exit(struct zebra_vrf *zvrf)
+{
+       struct zebra_pw *pw;
+
+       while ((pw = RB_ROOT(zebra_pw_head, &zvrf->pseudowires)) != NULL)
+               zebra_pw_del(zvrf, pw);
+}
+
+DEFUN_NOSH (pseudowire_if,
+           pseudowire_if_cmd,
+           "[no] pseudowire IFNAME",
+           NO_STR
+           "Static pseudowire configuration\n"
+           "Pseudowire name\n")
+{
+       struct zebra_vrf *zvrf;
+       struct zebra_pw *pw;
+       int idx = 0;
+       const char *ifname;
+
+       zvrf = vrf_info_lookup(VRF_DEFAULT);
+       if (!zvrf)
+               return CMD_WARNING;
+
+       argv_find(argv, argc, "IFNAME", &idx);
+       ifname = argv[idx]->arg;
+       pw = zebra_pw_find(zvrf, ifname);
+       if (pw && pw->protocol != ZEBRA_ROUTE_STATIC) {
+               vty_out(vty, "%% Pseudowire is not static\n");
+               return CMD_WARNING;
+       }
+
+       if (argv_find(argv, argc, "no", &idx)) {
+               if (!pw)
+                       return CMD_SUCCESS;
+               zebra_pw_del(zvrf, pw);
+       }
+
+       if (!pw)
+               pw = zebra_pw_add(zvrf, ifname, ZEBRA_ROUTE_STATIC, NULL);
+       VTY_PUSH_CONTEXT(PW_NODE, pw);
+
+       return CMD_SUCCESS;
+}
+
+DEFUN (pseudowire_labels,
+       pseudowire_labels_cmd,
+       "[no] mpls label local (16-1048575) remote (16-1048575)",
+       NO_STR
+       "MPLS L2VPN PW command\n"
+       "MPLS L2VPN static labels\n"
+       "Local pseudowire label\n"
+       "Local pseudowire label\n"
+       "Remote pseudowire label\n"
+       "Remote pseudowire label\n")
+{
+       VTY_DECLVAR_CONTEXT(zebra_pw, pw);
+       int idx = 0;
+       mpls_label_t local_label, remote_label;
+
+       if (argv_find(argv, argc, "no", &idx)) {
+               local_label = MPLS_NO_LABEL;
+               remote_label = MPLS_NO_LABEL;
+       } else {
+               argv_find(argv, argc, "local", &idx);
+               local_label = atoi(argv[idx + 1]->arg);
+               argv_find(argv, argc, "remote", &idx);
+               remote_label = atoi(argv[idx + 1]->arg);
+       }
+
+       zebra_pw_change(pw, pw->ifindex, pw->type, pw->af, &pw->nexthop,
+                       local_label, remote_label, pw->flags, &pw->data);
+
+       return CMD_SUCCESS;
+}
+
+DEFUN (pseudowire_neighbor,
+       pseudowire_neighbor_cmd,
+       "[no] neighbor <A.B.C.D|X:X::X:X>",
+       NO_STR
+       "Specify the IPv4 or IPv6 address of the remote endpoint\n"
+       "IPv4 address\n"
+       "IPv6 address\n")
+{
+       VTY_DECLVAR_CONTEXT(zebra_pw, pw);
+       int idx = 0;
+       const char *address;
+       int af;
+       union g_addr nexthop;
+
+       af = AF_UNSPEC;
+       memset(&nexthop, 0, sizeof(nexthop));
+
+       if (!argv_find(argv, argc, "no", &idx)) {
+               argv_find(argv, argc, "neighbor", &idx);
+               address = argv[idx + 1]->arg;
+
+               if (inet_pton(AF_INET, address, &nexthop.ipv4) == 1)
+                       af = AF_INET;
+               else if (inet_pton(AF_INET6, address, &nexthop.ipv6) == 1)
+                       af = AF_INET6;
+               else {
+                       vty_out(vty, "%% Malformed address\n");
+                       return CMD_WARNING;
+               }
+       }
+
+       zebra_pw_change(pw, pw->ifindex, pw->type, af, &nexthop,
+                       pw->local_label, pw->remote_label, pw->flags,
+                       &pw->data);
+
+       return CMD_SUCCESS;
+}
+
+DEFUN (pseudowire_control_word,
+       pseudowire_control_word_cmd,
+       "[no] control-word <exclude|include>",
+       NO_STR
+       "Control-word options\n"
+       "Exclude control-word in pseudowire packets\n"
+       "Include control-word in pseudowire packets\n")
+{
+       VTY_DECLVAR_CONTEXT(zebra_pw, pw);
+       int idx = 0;
+       uint8_t flags = 0;
+
+       if (argv_find(argv, argc, "no", &idx))
+               flags = F_PSEUDOWIRE_CWORD;
+       else {
+               argv_find(argv, argc, "control-word", &idx);
+               if (argv[idx + 1]->text[0] == 'i')
+                       flags = F_PSEUDOWIRE_CWORD;
+       }
+
+       zebra_pw_change(pw, pw->ifindex, pw->type, pw->af, &pw->nexthop,
+                       pw->local_label, pw->remote_label, flags, &pw->data);
+
+       return CMD_SUCCESS;
+}
+
+DEFUN (show_pseudowires,
+       show_pseudowires_cmd,
+       "show pseudowires",
+       SHOW_STR
+       "Pseudowires")
+{
+       struct zebra_vrf *zvrf;
+       struct zebra_pw *pw;
+
+       zvrf = vrf_info_lookup(VRF_DEFAULT);
+       if (!zvrf)
+               return 0;
+
+       vty_out(vty, "%-16s %-24s %-12s %-8s %-10s\n", "Interface", "Neighbor",
+               "Labels", "Protocol", "Status");
+
+       RB_FOREACH(pw, zebra_pw_head, &zvrf->pseudowires)
+       {
+               char buf_nbr[INET6_ADDRSTRLEN];
+               char buf_labels[64];
+
+               inet_ntop(pw->af, &pw->nexthop, buf_nbr, sizeof(buf_nbr));
+
+               if (pw->local_label != MPLS_NO_LABEL
+                   && pw->remote_label != MPLS_NO_LABEL)
+                       snprintf(buf_labels, sizeof(buf_labels), "%u/%u",
+                                pw->local_label, pw->remote_label);
+               else
+                       snprintf(buf_labels, sizeof(buf_labels), "-");
+
+               vty_out(vty, "%-16s %-24s %-12s %-8s %-10s\n", pw->ifname,
+                       (pw->af != AF_UNSPEC) ? buf_nbr : "-", buf_labels,
+                       zebra_route_string(pw->protocol),
+                       (zebra_pw_enabled(pw) && pw->status == PW_STATUS_UP)
+                               ? "UP"
+                               : "DOWN");
+       }
+
+       return CMD_SUCCESS;
+}
+
+/* Pseudowire configuration write function. */
+static int zebra_pw_config(struct vty *vty)
+{
+       int write = 0;
+       struct zebra_vrf *zvrf;
+       struct zebra_pw *pw;
+
+       zvrf = vrf_info_lookup(VRF_DEFAULT);
+       if (!zvrf)
+               return 0;
+
+       RB_FOREACH(pw, zebra_static_pw_head, &zvrf->static_pseudowires)
+       {
+               vty_out(vty, "pseudowire %s\n", pw->ifname);
+               if (pw->local_label != MPLS_NO_LABEL
+                   && pw->remote_label != MPLS_NO_LABEL)
+                       vty_out(vty, " mpls label local %u remote %u\n",
+                               pw->local_label, pw->remote_label);
+               else
+                       vty_out(vty,
+                               " ! Incomplete config, specify the static "
+                               "MPLS labels\n");
+
+               if (pw->af != AF_UNSPEC) {
+                       char buf[INET6_ADDRSTRLEN];
+                       inet_ntop(pw->af, &pw->nexthop, buf, sizeof(buf));
+                       vty_out(vty, " neighbor %s\n", buf);
+               } else
+                       vty_out(vty,
+                               " ! Incomplete config, specify a neighbor "
+                               "address\n");
+
+               if (!(pw->flags & F_PSEUDOWIRE_CWORD))
+                       vty_out(vty, " control-word exclude\n");
+
+               vty_out(vty, "!\n");
+               write = 1;
+       }
+
+       return write;
+}
+
+static struct cmd_node pw_node = {
+       PW_NODE, "%s(config-pw)# ", 1,
+};
+
+void zebra_pw_vty_init(void)
+{
+       install_node(&pw_node, zebra_pw_config);
+       install_default(PW_NODE);
+
+       install_element(CONFIG_NODE, &pseudowire_if_cmd);
+       install_element(PW_NODE, &pseudowire_labels_cmd);
+       install_element(PW_NODE, &pseudowire_neighbor_cmd);
+       install_element(PW_NODE, &pseudowire_control_word_cmd);
+
+       install_element(VIEW_NODE, &show_pseudowires_cmd);
+}
diff --git a/zebra/zebra_pw.h b/zebra/zebra_pw.h
new file mode 100644 (file)
index 0000000..417d26f
--- /dev/null
@@ -0,0 +1,75 @@
+/* Zebra PW code
+ * Copyright (C) 2016 Volta Networks, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ */
+
+#ifndef ZEBRA_PW_H_
+#define ZEBRA_PW_H_
+
+#include <net/if.h>
+#include <netinet/in.h>
+
+#include "hook.h"
+#include "qobj.h"
+
+#define PW_INSTALL_RETRY_INTERVAL      30
+
+struct zebra_pw {
+       RB_ENTRY(zebra_pw) pw_entry, static_pw_entry;
+       vrf_id_t vrf_id;
+       char ifname[IF_NAMESIZE];
+       ifindex_t ifindex;
+       int type;
+       int af;
+       union g_addr nexthop;
+       uint32_t local_label;
+       uint32_t remote_label;
+       uint8_t flags;
+       union pw_protocol_fields data;
+       int enabled;
+       int status;
+       uint8_t protocol;
+       struct zserv *client;
+       struct rnh *rnh;
+       struct thread *install_retry_timer;
+       QOBJ_FIELDS
+};
+DECLARE_QOBJ_TYPE(zebra_pw)
+
+RB_HEAD(zebra_pw_head, zebra_pw);
+RB_PROTOTYPE(zebra_pw_head, zebra_pw, pw_entry, zebra_pw_compare);
+
+RB_HEAD(zebra_static_pw_head, zebra_pw);
+RB_PROTOTYPE(zebra_static_pw_head, zebra_pw, static_pw_entry, zebra_pw_compare);
+
+DECLARE_HOOK(pw_install, (struct zebra_pw * pw), (pw))
+DECLARE_HOOK(pw_uninstall, (struct zebra_pw * pw), (pw))
+
+struct zebra_pw *zebra_pw_add(struct zebra_vrf *, const char *, uint8_t,
+                             struct zserv *);
+void zebra_pw_del(struct zebra_vrf *, struct zebra_pw *);
+void zebra_pw_change(struct zebra_pw *, ifindex_t, int, int, union g_addr *,
+                    uint32_t, uint32_t, uint8_t, union pw_protocol_fields *);
+struct zebra_pw *zebra_pw_find(struct zebra_vrf *, const char *);
+void zebra_pw_update(struct zebra_pw *);
+void zebra_pw_install_failure(struct zebra_pw *);
+void zebra_pw_client_close(struct zserv *);
+void zebra_pw_init(struct zebra_vrf *);
+void zebra_pw_exit(struct zebra_vrf *);
+void zebra_pw_vty_init(void);
+
+#endif /* ZEBRA_PW_H_ */
index 98508aaa89efbf6413cadf39df1efc0671a7f9b0..e61c2e7b0e8c3cf8910a8e369f78548d9a111ef0 100644 (file)
@@ -505,6 +505,8 @@ static int nexthop_active(afi_t afi, struct route_entry *re,
                                        }
                                        resolved = 1;
                                }
+                       if (resolved && set)
+                               re->nexthop_mtu = match->mtu;
                        return resolved;
                } else if (re->type == ZEBRA_ROUTE_STATIC) {
                        resolved = 0;
@@ -2237,13 +2239,12 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p,
                        continue;
 
                if (same->type == re->type && same->instance == re->instance
-                   && same->table == re->table
-                   && same->type != ZEBRA_ROUTE_CONNECT)
+                   && same->table == re->table && !RIB_SYSTEM_ROUTE(same))
                        break;
        }
 
        /* If this route is kernel route, set FIB flag to the route. */
-       if (re->type == ZEBRA_ROUTE_KERNEL || re->type == ZEBRA_ROUTE_CONNECT)
+       if (RIB_SYSTEM_ROUTE(re))
                for (nexthop = re->nexthop; nexthop; nexthop = nexthop->next)
                        SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
 
@@ -2467,11 +2468,11 @@ int rib_add(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, u_short instance,
                        continue;
                if (re->instance != instance)
                        continue;
-               if (re->type != ZEBRA_ROUTE_CONNECT) {
+               if (!RIB_SYSTEM_ROUTE(re)) {
                        same = re;
                        break;
                }
-               /* Duplicate connected route comes in. */
+               /* Duplicate system route comes in. */
                else if ((nexthop = re->nexthop)
                         && nexthop->type == NEXTHOP_TYPE_IFINDEX
                         && nexthop->ifindex == ifindex
@@ -2515,7 +2516,7 @@ int rib_add(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, u_short instance,
                route_entry_nexthop_ifindex_add(re, ifindex);
 
        /* If this route is kernel route, set FIB flag to the route. */
-       if (type == ZEBRA_ROUTE_KERNEL || type == ZEBRA_ROUTE_CONNECT)
+       if (RIB_SYSTEM_ROUTE(re))
                for (nexthop = re->nexthop; nexthop; nexthop = nexthop->next)
                        SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
 
index 8a326c27fc34a6475e7ec772d8d9392a9f2c3300..77cfa9860fc48bda68c6be9ad4cbc5a22e3317e0 100644 (file)
@@ -126,6 +126,7 @@ struct rnh *zebra_add_rnh(struct prefix *p, vrf_id_t vrfid, rnh_type_t type)
                rnh->client_list = list_new();
                rnh->vrf_id = vrfid;
                rnh->zebra_static_route_list = list_new();
+               rnh->zebra_pseudowire_list = list_new();
                route_lock_node(rn);
                rn->info = rnh;
                rnh->node = rn;
@@ -161,6 +162,7 @@ void zebra_free_rnh(struct rnh *rnh)
        rnh->flags |= ZEBRA_NHT_DELETED;
        list_free(rnh->client_list);
        list_free(rnh->zebra_static_route_list);
+       list_free(rnh->zebra_pseudowire_list);
        free_state(rnh->vrf_id, rnh->state, rnh->node);
        XFREE(MTYPE_RNH, rnh);
 }
@@ -210,7 +212,8 @@ void zebra_remove_rnh_client(struct rnh *rnh, struct zserv *client,
        }
        listnode_delete(rnh->client_list, client);
        if (list_isempty(rnh->client_list)
-           && list_isempty(rnh->zebra_static_route_list))
+           && list_isempty(rnh->zebra_static_route_list)
+           && list_isempty(rnh->zebra_pseudowire_list))
                zebra_delete_rnh(rnh, type);
 }
 
@@ -237,7 +240,8 @@ void zebra_deregister_rnh_static_nh(vrf_id_t vrf_id, struct prefix *nh,
        listnode_delete(rnh->zebra_static_route_list, static_rn);
 
        if (list_isempty(rnh->client_list)
-           && list_isempty(rnh->zebra_static_route_list))
+           && list_isempty(rnh->zebra_static_route_list)
+           && list_isempty(rnh->zebra_pseudowire_list))
                zebra_delete_rnh(rnh, RNH_NEXTHOP_TYPE);
 }
 
@@ -284,6 +288,58 @@ void zebra_deregister_rnh_static_nexthops(vrf_id_t vrf_id,
        }
 }
 
+/* XXX move this utility function elsewhere? */
+static void addr2hostprefix(int af, const union g_addr *addr,
+                           struct prefix *prefix)
+{
+       switch (af) {
+       case AF_INET:
+               prefix->family = AF_INET;
+               prefix->prefixlen = IPV4_MAX_BITLEN;
+               prefix->u.prefix4 = addr->ipv4;
+               break;
+       case AF_INET6:
+               prefix->family = AF_INET6;
+               prefix->prefixlen = IPV6_MAX_BITLEN;
+               prefix->u.prefix6 = addr->ipv6;
+               break;
+       default:
+               zlog_warn("%s: unknown address family %d", __func__, af);
+               break;
+       }
+}
+
+void zebra_register_rnh_pseudowire(vrf_id_t vrf_id, struct zebra_pw *pw)
+{
+       struct prefix nh;
+       struct rnh *rnh;
+
+       addr2hostprefix(pw->af, &pw->nexthop, &nh);
+       rnh = zebra_add_rnh(&nh, vrf_id, RNH_NEXTHOP_TYPE);
+       if (rnh && !listnode_lookup(rnh->zebra_pseudowire_list, pw)) {
+               listnode_add(rnh->zebra_pseudowire_list, pw);
+               pw->rnh = rnh;
+               zebra_evaluate_rnh(vrf_id, pw->af, 1, RNH_NEXTHOP_TYPE, &nh);
+       }
+}
+
+void zebra_deregister_rnh_pseudowire(vrf_id_t vrf_id, struct zebra_pw *pw)
+{
+       struct rnh *rnh;
+
+       rnh = pw->rnh;
+       if (!rnh)
+               return;
+
+       listnode_delete(rnh->zebra_pseudowire_list, pw);
+       pw->rnh = NULL;
+
+       if (list_isempty(rnh->client_list)
+           && list_isempty(rnh->zebra_static_route_list)
+           && list_isempty(rnh->zebra_pseudowire_list))
+               zebra_delete_rnh(rnh, RNH_NEXTHOP_TYPE);
+}
+
 /* Apply the NHT route-map for a client to the route (and nexthops)
  * resolving a NH.
  */
@@ -595,6 +651,15 @@ static void zebra_rnh_process_static_routes(vrf_id_t vrfid, int family,
        }
 }
 
+static void zebra_rnh_process_pseudowires(vrf_id_t vrfid, struct rnh *rnh)
+{
+       struct zebra_pw *pw;
+       struct listnode *node;
+
+       for (ALL_LIST_ELEMENTS_RO(rnh->zebra_pseudowire_list, node, pw))
+               zebra_pw_update(pw);
+}
+
 /*
  * See if a tracked nexthop entry has undergone any change, and if so,
  * take appropriate action; this involves notifying any clients and/or
@@ -636,6 +701,9 @@ static void zebra_rnh_eval_nexthop_entry(vrf_id_t vrfid, int family, int force,
                /* Process static routes attached to this nexthop */
                zebra_rnh_process_static_routes(vrfid, family, nrn, rnh, prn,
                                                rnh->state);
+
+               /* Process pseudowires attached to this nexthop */
+               zebra_rnh_process_pseudowires(vrfid, rnh);
        }
 }
 
@@ -694,8 +762,10 @@ static void zebra_rnh_clear_nhc_flag(vrf_id_t vrfid, int family,
 
        re = zebra_rnh_resolve_entry(vrfid, family, type, nrn, rnh, &prn);
 
-       if (re)
+       if (re) {
                UNSET_FLAG(re->status, ROUTE_ENTRY_NEXTHOPS_CHANGED);
+               UNSET_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED);
+       }
 }
 
 /* Evaluate all tracked entries (nexthops or routes for import into BGP)
@@ -815,6 +885,7 @@ static void copy_state(struct rnh *rnh, struct route_entry *re,
 
        state = XCALLOC(MTYPE_RE, sizeof(struct route_entry));
        state->type = re->type;
+       state->distance = re->distance;
        state->metric = re->metric;
 
        route_entry_copy_nexthops(state, re->nexthop);
@@ -830,13 +901,17 @@ static int compare_state(struct route_entry *r1, struct route_entry *r2)
        if ((!r1 && r2) || (r1 && !r2))
                return 1;
 
+       if (r1->distance != r2->distance)
+               return 1;
+
        if (r1->metric != r2->metric)
                return 1;
 
        if (r1->nexthop_num != r2->nexthop_num)
                return 1;
 
-       if (CHECK_FLAG(r1->status, ROUTE_ENTRY_NEXTHOPS_CHANGED))
+       if (CHECK_FLAG(r1->status, ROUTE_ENTRY_NEXTHOPS_CHANGED)
+           || CHECK_FLAG(r1->status, ROUTE_ENTRY_LABELS_CHANGED))
                return 1;
 
        return 0;
@@ -999,5 +1074,7 @@ static void print_rnh(struct route_node *rn, struct vty *vty)
        if (!list_isempty(rnh->zebra_static_route_list))
                vty_out(vty, " zebra%s",
                        rnh->filtered[ZEBRA_ROUTE_STATIC] ? "(filtered)" : "");
+       if (!list_isempty(rnh->zebra_pseudowire_list))
+               vty_out(vty, " zebra[pseudowires]");
        vty_out(vty, "\n");
 }
index f8d89ec8ca89fe2780e44734033a09264b012dc0..7e183684da40917a8bdbcee660c77c0b94060485 100644 (file)
@@ -42,6 +42,8 @@ struct rnh {
        struct list *
                zebra_static_route_list; /* static routes dependent on this NH
                                            */
+       struct list
+               *zebra_pseudowire_list; /* pseudowires dependent on this NH */
        struct route_node *node;
        int filtered[ZEBRA_ROUTE_MAX]; /* if this has been filtered for client
                                          */
@@ -67,6 +69,8 @@ extern void zebra_deregister_rnh_static_nexthops(vrf_id_t,
                                                 struct route_node *rn);
 extern void zebra_deregister_rnh_static_nh(vrf_id_t, struct prefix *,
                                           struct route_node *);
+extern void zebra_register_rnh_pseudowire(vrf_id_t, struct zebra_pw *);
+extern void zebra_deregister_rnh_pseudowire(vrf_id_t, struct zebra_pw *);
 extern void zebra_remove_rnh_client(struct rnh *rnh, struct zserv *client,
                                    rnh_type_t type);
 extern void zebra_evaluate_rnh(vrf_id_t vrfid, int family, int force,
index 0176b36840a8c351d5b0d707ee895231f8cb0ed1..c738cde0ac540f5b292fbd7b6c2f9b5451818136 100644 (file)
@@ -256,7 +256,7 @@ DEFUN (no_match_ip_nexthop_prefix_len,
 
 DEFUN (match_source_protocol,
        match_source_protocol_cmd,
-       "match source-protocol <bgp|ospf|rip|ripng|isis|ospf6|connected|system|kernel|static>",
+       "match source-protocol <bgp|ospf|rip|ripng|isis|ospf6|pim|nhrp|eigrp|babel|connected|system|kernel|static>",
        MATCH_STR
        "Match protocol via which the route was learnt\n"
        "BGP protocol\n"
@@ -265,6 +265,10 @@ DEFUN (match_source_protocol,
        "RIPNG protocol\n"
        "ISIS protocol\n"
        "OSPF6 protocol\n"
+       "PIM protocol\n"
+       "NHRP protocol\n"
+       "EIGRP protocol\n"
+       "BABEL protocol\n"
        "Routes from directly connected peer\n"
        "Routes from system configuration\n"
        "Routes from kernel\n"
@@ -284,7 +288,7 @@ DEFUN (match_source_protocol,
 
 DEFUN (no_match_source_protocol,
        no_match_source_protocol_cmd,
-       "no match source-protocol [<bgp|ospf|rip|ripng|isis|ospf6|connected|system|kernel|static>]",
+       "no match source-protocol [<bgp|ospf|rip|ripng|isis|ospf6|pim|nhrp|eigrp|babel|connected|system|kernel|static>]",
        NO_STR
        MATCH_STR
        "No match protocol via which the route was learnt\n"
@@ -294,6 +298,10 @@ DEFUN (no_match_source_protocol,
        "RIPNG protocol\n"
        "ISIS protocol\n"
        "OSPF6 protocol\n"
+       "PIM protocol\n"
+       "NHRP protocol\n"
+       "EIGRP protocol\n"
+       "BABEL protocol\n"
        "Routes from directly connected peer\n"
        "Routes from system configuration\n"
        "Routes from kernel\n"
index 6cebae997c86f256d4dc59d7a5d83b685f289149..dba228ea350df68c7d0ba04840a54dc8d95305c9 100644 (file)
@@ -24,6 +24,7 @@
 #include <lib/nexthop.h>
 #include <lib/memory.h>
 #include <lib/srcdest_table.h>
+#include <lib/if.h>
 
 #include "vty.h"
 #include "zebra/debug.h"
@@ -81,11 +82,11 @@ void static_install_route(afi_t afi, safi_t safi, struct prefix *p,
                        nh_p.u.prefix4 = si->addr.ipv4;
                        zebra_register_rnh_static_nh(si->vrf_id, &nh_p, rn);
                        break;
-               case STATIC_IPV4_GATEWAY_IFINDEX:
+               case STATIC_IPV4_GATEWAY_IFNAME:
                        nexthop = route_entry_nexthop_ipv4_ifindex_add(
                                re, &si->addr.ipv4, NULL, si->ifindex);
                        break;
-               case STATIC_IFINDEX:
+               case STATIC_IFNAME:
                        nexthop = route_entry_nexthop_ifindex_add(re,
                                                                  si->ifindex);
                        break;
@@ -100,7 +101,7 @@ void static_install_route(afi_t afi, safi_t safi, struct prefix *p,
                        nh_p.u.prefix6 = si->addr.ipv6;
                        zebra_register_rnh_static_nh(si->vrf_id, &nh_p, rn);
                        break;
-               case STATIC_IPV6_GATEWAY_IFINDEX:
+               case STATIC_IPV6_GATEWAY_IFNAME:
                        nexthop = route_entry_nexthop_ipv6_ifindex_add(
                                re, &si->addr.ipv6, si->ifindex);
                        break;
@@ -156,11 +157,11 @@ void static_install_route(afi_t afi, safi_t safi, struct prefix *p,
                        nh_p.u.prefix4 = si->addr.ipv4;
                        zebra_register_rnh_static_nh(si->vrf_id, &nh_p, rn);
                        break;
-               case STATIC_IPV4_GATEWAY_IFINDEX:
+               case STATIC_IPV4_GATEWAY_IFNAME:
                        nexthop = route_entry_nexthop_ipv4_ifindex_add(
                                re, &si->addr.ipv4, NULL, si->ifindex);
                        break;
-               case STATIC_IFINDEX:
+               case STATIC_IFNAME:
                        nexthop = route_entry_nexthop_ifindex_add(re,
                                                                  si->ifindex);
                        break;
@@ -175,7 +176,7 @@ void static_install_route(afi_t afi, safi_t safi, struct prefix *p,
                        nh_p.u.prefix6 = si->addr.ipv6;
                        zebra_register_rnh_static_nh(si->vrf_id, &nh_p, rn);
                        break;
-               case STATIC_IPV6_GATEWAY_IFINDEX:
+               case STATIC_IPV6_GATEWAY_IFNAME:
                        nexthop = route_entry_nexthop_ipv6_ifindex_add(
                                re, &si->addr.ipv6, si->ifindex);
                        break;
@@ -214,6 +215,9 @@ void static_install_route(afi_t afi, safi_t safi, struct prefix *p,
        }
 }
 
+/* this works correctly with IFNAME<>IFINDEX because a static route on a
+ * non-active interface will have IFINDEX_INTERNAL and thus compare false
+ */
 static int static_nexthop_same(struct nexthop *nexthop, struct static_route *si)
 {
        if (nexthop->type == NEXTHOP_TYPE_BLACKHOLE
@@ -225,12 +229,12 @@ static int static_nexthop_same(struct nexthop *nexthop, struct static_route *si)
            && IPV4_ADDR_SAME(&nexthop->gate.ipv4, &si->addr.ipv4))
                return 1;
        else if (nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX
-                && si->type == STATIC_IPV4_GATEWAY_IFINDEX
+                && si->type == STATIC_IPV4_GATEWAY_IFNAME
                 && IPV4_ADDR_SAME(&nexthop->gate.ipv4, &si->addr.ipv4)
                 && nexthop->ifindex == si->ifindex)
                return 1;
        else if (nexthop->type == NEXTHOP_TYPE_IFINDEX
-                && si->type == STATIC_IFINDEX
+                && si->type == STATIC_IFNAME
                 && nexthop->ifindex == si->ifindex)
                return 1;
        else if (nexthop->type == NEXTHOP_TYPE_IPV6
@@ -238,7 +242,7 @@ static int static_nexthop_same(struct nexthop *nexthop, struct static_route *si)
                 && IPV6_ADDR_SAME(&nexthop->gate.ipv6, &si->addr.ipv6))
                return 1;
        else if (nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX
-                && si->type == STATIC_IPV6_GATEWAY_IFINDEX
+                && si->type == STATIC_IPV6_GATEWAY_IFNAME
                 && IPV6_ADDR_SAME(&nexthop->gate.ipv6, &si->addr.ipv6)
                 && nexthop->ifindex == si->ifindex)
                return 1;
@@ -360,7 +364,7 @@ void static_uninstall_route(afi_t afi, safi_t safi, struct prefix *p,
 
 int static_add_route(afi_t afi, safi_t safi, u_char type, struct prefix *p,
                     struct prefix_ipv6 *src_p, union g_addr *gate,
-                    ifindex_t ifindex, const char *ifname, u_char flags,
+                    const char *ifname, u_char flags,
                     route_tag_t tag, u_char distance, struct zebra_vrf *zvrf,
                     struct static_nh_label *snh_label)
 {
@@ -376,15 +380,15 @@ int static_add_route(afi_t afi, safi_t safi, u_char type, struct prefix *p,
 
        if (!gate
            && (type == STATIC_IPV4_GATEWAY
-               || type == STATIC_IPV4_GATEWAY_IFINDEX
+               || type == STATIC_IPV4_GATEWAY_IFNAME
                || type == STATIC_IPV6_GATEWAY
-               || type == STATIC_IPV6_GATEWAY_IFINDEX))
+               || type == STATIC_IPV6_GATEWAY_IFNAME))
                return -1;
 
-       if (!ifindex
-           && (type == STATIC_IFINDEX
-               || type == STATIC_IPV4_GATEWAY_IFINDEX
-               || type == STATIC_IPV6_GATEWAY_IFINDEX))
+       if (!ifname
+           && (type == STATIC_IFNAME
+               || type == STATIC_IPV4_GATEWAY_IFNAME
+               || type == STATIC_IPV6_GATEWAY_IFNAME))
                return -1;
 
        /* Lookup static route prefix. */
@@ -397,7 +401,7 @@ int static_add_route(afi_t afi, safi_t safi, u_char type, struct prefix *p,
                                   && IPV4_ADDR_SAME(gate, &si->addr.ipv4))
                                  || (afi == AFI_IP6
                                      && IPV6_ADDR_SAME(gate, &si->addr.ipv6))))
-                   && (!ifindex || ifindex == si->ifindex)) {
+                   && (!strcmp (ifname ? ifname : "", si->ifname))) {
                        if ((distance == si->distance) && (tag == si->tag)
                            && !memcmp(&si->snh_label, snh_label,
                                       sizeof(struct static_nh_label))
@@ -411,7 +415,7 @@ int static_add_route(afi_t afi, safi_t safi, u_char type, struct prefix *p,
 
        /* Distance or tag or label changed, delete existing first. */
        if (update)
-               static_delete_route(afi, safi, type, p, src_p, gate, ifindex,
+               static_delete_route(afi, safi, type, p, src_p, gate, ifname,
                                    update->tag, update->distance, zvrf,
                                    &update->snh_label);
 
@@ -423,20 +427,20 @@ int static_add_route(afi_t afi, safi_t safi, u_char type, struct prefix *p,
        si->flags = flags;
        si->tag = tag;
        si->vrf_id = zvrf_id(zvrf);
-       si->ifindex = ifindex;
-       if (si->ifindex)
-               strcpy(si->ifname, ifname);
+       if (ifname)
+               strlcpy(si->ifname, ifname, sizeof(si->ifname));
+       si->ifindex = IFINDEX_INTERNAL;
 
        switch (type) {
        case STATIC_IPV4_GATEWAY:
-       case STATIC_IPV4_GATEWAY_IFINDEX:
+       case STATIC_IPV4_GATEWAY_IFNAME:
                si->addr.ipv4 = gate->ipv4;
                break;
        case STATIC_IPV6_GATEWAY:
-       case STATIC_IPV6_GATEWAY_IFINDEX:
+       case STATIC_IPV6_GATEWAY_IFNAME:
                si->addr.ipv6 = gate->ipv6;
                break;
-       case STATIC_IFINDEX:
+       case STATIC_IFNAME:
                break;
        }
 
@@ -471,15 +475,25 @@ int static_add_route(afi_t afi, safi_t safi, u_char type, struct prefix *p,
        si->prev = pp;
        si->next = cp;
 
-       /* Install into rib. */
-       static_install_route(afi, safi, p, src_p, si);
+       /* check whether interface exists in system & install if it does */
+       if (!ifname)
+               static_install_route(afi, safi, p, src_p, si);
+       else {
+               struct interface *ifp;
+
+               ifp = if_lookup_by_name(ifname, zvrf_id(zvrf));
+               if (ifp && ifp->ifindex != IFINDEX_INTERNAL) {
+                       si->ifindex = ifp->ifindex;
+                       static_install_route(afi, safi, p, src_p, si);
+               }
+       }
 
        return 1;
 }
 
 int static_delete_route(afi_t afi, safi_t safi, u_char type, struct prefix *p,
                        struct prefix_ipv6 *src_p, union g_addr *gate,
-                       ifindex_t ifindex, route_tag_t tag, u_char distance,
+                       const char *ifname, route_tag_t tag, u_char distance,
                        struct zebra_vrf *zvrf,
                        struct static_nh_label *snh_label)
 {
@@ -504,7 +518,7 @@ int static_delete_route(afi_t afi, safi_t safi, u_char type, struct prefix *p,
                                   && IPV4_ADDR_SAME(gate, &si->addr.ipv4))
                                  || (afi == AFI_IP6
                                      && IPV6_ADDR_SAME(gate, &si->addr.ipv6))))
-                   && (!ifindex || ifindex == si->ifindex)
+                   && (!strcmp(ifname ? ifname : "", si->ifname))
                    && (!tag || (tag == si->tag))
                    && (!snh_label->num_labels
                        || !memcmp(&si->snh_label, snh_label,
@@ -517,8 +531,9 @@ int static_delete_route(afi_t afi, safi_t safi, u_char type, struct prefix *p,
                return 0;
        }
 
-       /* Install into rib. */
-       static_uninstall_route(afi, safi, p, src_p, si);
+       /* Uninstall from rib. */
+       if (!si->ifname[0] || si->ifindex != IFINDEX_INTERNAL)
+               static_uninstall_route(afi, safi, p, src_p, si);
 
        /* Unlink static route from linked list. */
        if (si->prev)
@@ -536,3 +551,49 @@ int static_delete_route(afi_t afi, safi_t safi, u_char type, struct prefix *p,
 
        return 1;
 }
+
+static void static_ifindex_update_af(struct interface *ifp, bool up,
+                                    afi_t afi, safi_t safi)
+{
+       struct route_table *stable;
+       struct zebra_vrf *zvrf = zebra_vrf_lookup_by_id(ifp->vrf_id);
+       struct route_node *rn;
+       struct static_route *si;
+       struct prefix *p, *src_pp;
+       struct prefix_ipv6 *src_p;
+
+       stable = zebra_vrf_static_table(afi, safi, zvrf);
+       if (!stable)
+               return;
+
+       for (rn = route_top(stable); rn; rn = srcdest_route_next(rn)) {
+               srcdest_rnode_prefixes(rn, &p, &src_pp);
+               src_p = (struct prefix_ipv6 *)src_pp;
+
+               for (si = rn->info; si; si = si->next) {
+                       if (!si->ifname[0])
+                               continue;
+                       if (up) {
+                               if (strcmp(si->ifname, ifp->name))
+                                       continue;
+                               si->ifindex = ifp->ifindex;
+                               static_install_route(afi, safi, p, src_p, si);
+                       } else {
+                               if (si->ifindex != ifp->ifindex)
+                                       continue;
+                               static_uninstall_route(afi, safi, p, src_p,
+                                                      si);
+                               si->ifindex = IFINDEX_INTERNAL;
+                       }
+               }
+       }
+}
+
+/* called from if_{add,delete}_update, i.e. when ifindex becomes [in]valid */
+void static_ifindex_update(struct interface *ifp, bool up)
+{
+       static_ifindex_update_af(ifp, up, AFI_IP, SAFI_UNICAST);
+       static_ifindex_update_af(ifp, up, AFI_IP, SAFI_MULTICAST);
+       static_ifindex_update_af(ifp, up, AFI_IP6, SAFI_UNICAST);
+       static_ifindex_update_af(ifp, up, AFI_IP6, SAFI_MULTICAST);
+}
index 885774895fe9a4a70fcf3182ee2384a9f4b40ab2..6ab47094a1498d545c2a7a3319d881a9ae043a68 100644 (file)
@@ -30,12 +30,12 @@ struct static_nh_label {
 };
 
 typedef enum {
-       STATIC_IFINDEX,
+       STATIC_IFNAME,
        STATIC_IPV4_GATEWAY,
-       STATIC_IPV4_GATEWAY_IFINDEX,
+       STATIC_IPV4_GATEWAY_IFNAME,
        STATIC_BLACKHOLE,
        STATIC_IPV6_GATEWAY,
-       STATIC_IPV6_GATEWAY_IFINDEX,
+       STATIC_IPV6_GATEWAY_IFNAME,
 } zebra_static_types;
 
 /* Static route information. */
@@ -84,16 +84,18 @@ extern void static_uninstall_route(afi_t afi, safi_t safi, struct prefix *p,
 
 extern int static_add_route(afi_t, safi_t safi, u_char type, struct prefix *p,
                            struct prefix_ipv6 *src_p, union g_addr *gate,
-                           ifindex_t ifindex, const char *ifname, u_char flags,
+                           const char *ifname, u_char flags,
                            route_tag_t tag, u_char distance,
                            struct zebra_vrf *zvrf,
                            struct static_nh_label *snh_label);
 
 extern int static_delete_route(afi_t, safi_t safi, u_char type,
                               struct prefix *p, struct prefix_ipv6 *src_p,
-                              union g_addr *gate, ifindex_t ifindex,
+                              union g_addr *gate, const char *ifname,
                               route_tag_t tag, u_char distance,
                               struct zebra_vrf *zvrf,
                               struct static_nh_label *snh_label);
 
+extern void static_ifindex_update(struct interface *ifp, bool up);
+
 #endif
index feca13d3a2da4e2093e60f7a6a6ff25045622f56..ff140bad676835739325aa1fd059b407162843d2 100644 (file)
@@ -95,51 +95,6 @@ static int zebra_vrf_new(struct vrf *vrf)
        return 0;
 }
 
-/*
- * Moving an interface amongst different vrf's
- * causes the interface to get a new ifindex
- * so we need to find static routes with
- * the old ifindex and replace with new
- * ifindex to insert back into the table
- */
-void zebra_vrf_static_route_interface_fixup(struct interface *ifp)
-{
-       afi_t afi;
-       safi_t safi;
-       struct zebra_vrf *zvrf = zebra_vrf_lookup_by_id(ifp->vrf_id);
-       struct route_table *stable = NULL;
-       struct route_node *rn = NULL;
-       struct static_route *si = NULL;
-
-       if (!zvrf)
-               return;
-
-       for (afi = AFI_IP; afi < AFI_MAX; afi++) {
-               for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) {
-                       stable = zvrf->stable[afi][safi];
-                       if (stable)
-                               for (rn = route_top(stable); rn;
-                                    rn = route_next(rn)) {
-                                       if (rn->info) {
-                                               si = rn->info;
-                                               if ((strcmp(si->ifname,
-                                                           ifp->name)
-                                                    == 0)
-                                                   && (si->ifindex
-                                                       != ifp->ifindex)) {
-                                                       si->ifindex =
-                                                               ifp->ifindex;
-                                                       static_install_route(
-                                                               afi, safi,
-                                                               &rn->p, NULL,
-                                                               si);
-                                               }
-                                       }
-                               }
-               }
-       }
-}
-
 /* Callback upon enabling a VRF. */
 static int zebra_vrf_enable(struct vrf *vrf)
 {
@@ -248,6 +203,7 @@ static int zebra_vrf_delete(struct vrf *vrf)
                zebra_vxlan_close_tables(zvrf);
 
                zebra_mpls_close_tables(zvrf);
+               zebra_pw_exit(zvrf);
 
                for (ALL_LIST_ELEMENTS_RO(vrf->iflist, node, ifp))
                        if_nbr_ipv6ll_to_ipv4ll_neigh_del_all(ifp);
@@ -417,6 +373,7 @@ struct zebra_vrf *zebra_vrf_alloc(void)
 
        zebra_vxlan_init_tables(zvrf);
        zebra_mpls_init_tables(zvrf);
+       zebra_pw_init(zvrf);
 
        return zvrf;
 }
index eb0687bf8a6c2812ec8cf43a35aba9e0dd0bce3b..dca53bb9f3b746555f68ea0a7451a5a992b4479e 100644 (file)
@@ -23,6 +23,7 @@
 #define __ZEBRA_RIB_H__
 
 #include <zebra/zebra_ns.h>
+#include <zebra/zebra_pw.h>
 
 /* MPLS (Segment Routing) global block */
 typedef struct mpls_srgb_t_ {
@@ -89,6 +90,10 @@ struct zebra_vrf {
        /* MPLS Segment Routing Global block */
        mpls_srgb_t mpls_srgb;
 
+       /* Pseudowires. */
+       struct zebra_pw_head pseudowires;
+       struct zebra_static_pw_head static_pseudowires;
+
        /* MPLS processing flags */
        u_int16_t mpls_flags;
 #define MPLS_FLAG_SCHEDULE_LSPS    (1 << 0)
@@ -124,7 +129,6 @@ struct route_table *zebra_vrf_table_with_table_id(afi_t afi, safi_t safi,
                                                  vrf_id_t vrf_id,
                                                  u_int32_t table_id);
 
-extern void zebra_vrf_static_route_interface_fixup(struct interface *ifp);
 extern void zebra_vrf_update_all(struct zserv *client);
 extern struct zebra_vrf *zebra_vrf_lookup_by_id(vrf_id_t vrf_id);
 extern struct zebra_vrf *zebra_vrf_lookup_by_name(const char *);
index e8b82ecf902735ac8b051a5622591979e1a3288c..e260338131b6d8aad840b3558e3e9a9f7c93687a 100644 (file)
@@ -55,9 +55,6 @@ static int do_show_ip_route(struct vty *vty, const char *vrf_name, afi_t afi,
 static void vty_show_ip_route_detail(struct vty *vty, struct route_node *rn,
                                     int mcast);
 
-#define ONE_DAY_SECOND 60*60*24
-#define ONE_WEEK_SECOND 60*60*24*7
-
 /* VNI range as per RFC 7432 */
 #define CMD_VNI_RANGE "(1-16777215)"
 
@@ -80,7 +77,6 @@ static int zebra_static_route(struct vty *vty, afi_t afi, safi_t safi,
        u_char flag = 0;
        route_tag_t tag = 0;
        struct zebra_vrf *zvrf;
-       unsigned int ifindex = 0;
        u_char type;
        struct static_nh_label snh_label;
 
@@ -207,26 +203,15 @@ static int zebra_static_route(struct vty *vty, afi_t afi, safi_t safi,
                gatep = &gate;
        }
 
-       if (ifname) {
-               struct interface *ifp;
-               ifp = if_lookup_by_name(ifname, zvrf_id(zvrf));
-               if (!ifp) {
-                       vty_out(vty, "%% Malformed Interface name %s\n",
-                               ifname);
-                       ifindex = IFINDEX_DELETED;
-               } else
-                       ifindex = ifp->ifindex;
-       }
-
        if (gate_str == NULL && ifname == NULL)
                type = STATIC_BLACKHOLE;
        else if (gate_str && ifname) {
                if (afi == AFI_IP)
-                       type = STATIC_IPV4_GATEWAY_IFINDEX;
+                       type = STATIC_IPV4_GATEWAY_IFNAME;
                else
-                       type = STATIC_IPV6_GATEWAY_IFINDEX;
+                       type = STATIC_IPV6_GATEWAY_IFNAME;
        } else if (ifname)
-               type = STATIC_IFINDEX;
+               type = STATIC_IFNAME;
        else {
                if (afi == AFI_IP)
                        type = STATIC_IPV4_GATEWAY;
@@ -235,10 +220,10 @@ static int zebra_static_route(struct vty *vty, afi_t afi, safi_t safi,
        }
 
        if (!negate)
-               static_add_route(afi, safi, type, &p, src_p, gatep, ifindex,
-                                ifname, flag, tag, distance, zvrf, &snh_label);
+               static_add_route(afi, safi, type, &p, src_p, gatep, ifname,
+                                   flag, tag, distance, zvrf, &snh_label);
        else
-               static_delete_route(afi, safi, type, &p, src_p, gatep, ifindex,
+               static_delete_route(afi, safi, type, &p, src_p, gatep, ifname,
                                    tag, distance, zvrf, &snh_label);
 
        return CMD_SUCCESS;
@@ -540,6 +525,9 @@ static void vty_show_ip_route_detail(struct vty *vty, struct route_node *rn,
                                break;
                        }
 
+                       if (re->nexthop_mtu)
+                               vty_out(vty, ", mtu %u", re->nexthop_mtu);
+
                        /* Label information */
                        if (nexthop->nh_label
                            && nexthop->nh_label->num_labels) {
@@ -586,8 +574,7 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn,
                if (CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED))
                        json_object_boolean_true_add(json_route, "selected");
 
-               if (re->type != ZEBRA_ROUTE_CONNECT
-                   && re->type != ZEBRA_ROUTE_KERNEL) {
+               if (re->type != ZEBRA_ROUTE_CONNECT) {
                        json_object_int_add(json_route, "distance",
                                            re->distance);
                        json_object_int_add(json_route, "metric", re->metric);
@@ -774,8 +761,7 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn,
                                srcdest_rnode2str(rn, buf, sizeof buf));
 
                        /* Distance and metric display. */
-                       if (re->type != ZEBRA_ROUTE_CONNECT
-                           && re->type != ZEBRA_ROUTE_KERNEL)
+                       if (re->type != ZEBRA_ROUTE_CONNECT)
                                len += vty_out(vty, " [%d/%d]", re->distance,
                                               re->metric);
                } else
@@ -1704,7 +1690,7 @@ static int static_config(struct vty *vty, afi_t afi, safi_t safi,
                                                          &si->addr.ipv6, buf,
                                                          sizeof buf));
                                        break;
-                               case STATIC_IFINDEX:
+                               case STATIC_IFNAME:
                                        vty_out(vty, " %s", si->ifname);
                                        break;
                                /* blackhole and Null0 mean the same thing */
@@ -1714,7 +1700,7 @@ static int static_config(struct vty *vty, afi_t afi, safi_t safi,
                                        else
                                                vty_out(vty, " Null0");
                                        break;
-                               case STATIC_IPV4_GATEWAY_IFINDEX:
+                               case STATIC_IPV4_GATEWAY_IFNAME:
                                        vty_out(vty, " %s %s",
                                                inet_ntop(AF_INET,
                                                          &si->addr.ipv4, buf,
@@ -1722,7 +1708,7 @@ static int static_config(struct vty *vty, afi_t afi, safi_t safi,
                                                ifindex2ifname(si->ifindex,
                                                               si->vrf_id));
                                        break;
-                               case STATIC_IPV6_GATEWAY_IFINDEX:
+                               case STATIC_IPV6_GATEWAY_IFNAME:
                                        vty_out(vty, " %s %s",
                                                inet_ntop(AF_INET6,
                                                          &si->addr.ipv6, buf,
index c96f073064d80d1d347049e4e5345e9543990dc0..7d265af30971f1246e887247aadee8288c7e49f5 100644 (file)
@@ -469,7 +469,7 @@ static int zvni_macip_send_msg_to_client(struct zebra_vrf *zvrf, vni_t vni,
 
        zserv_create_header(s, cmd, zvrf_id(zvrf));
        stream_putl(s, vni);
-       stream_put(s, macaddr->octet, ETHER_ADDR_LEN);
+       stream_put(s, macaddr->octet, ETH_ALEN);
        if (ip) {
                ipa_len = 0;
                if (IS_IPADDR_V4(ip))
@@ -776,18 +776,9 @@ static void zvni_install_neigh_hash(struct hash_backet *backet, void *ctxt)
 static unsigned int mac_hash_keymake(void *p)
 {
        zebra_mac_t *pmac = p;
-       char *pnt = (char *)pmac->macaddr.octet;
-       unsigned int key = 0;
-       int c = 0;
+       const void *pnt = (void *)pmac->macaddr.octet;
 
-       key += pnt[c];
-       key += pnt[c + 1];
-       key += pnt[c + 2];
-       key += pnt[c + 3];
-       key += pnt[c + 4];
-       key += pnt[c + 5];
-
-       return (key);
+       return jhash(pnt, ETH_ALEN, 0xa5a5a55a);
 }
 
 /*
@@ -805,7 +796,7 @@ static int mac_cmp(const void *p1, const void *p2)
                return 0;
 
        return (memcmp(pmac1->macaddr.octet, pmac2->macaddr.octet,
-                      ETHER_ADDR_LEN)
+                      ETH_ALEN)
                == 0);
 }
 
@@ -832,7 +823,7 @@ static zebra_mac_t *zvni_mac_add(zebra_vni_t *zvni, struct ethaddr *macaddr)
        zebra_mac_t *mac = NULL;
 
        memset(&tmp_mac, 0, sizeof(zebra_mac_t));
-       memcpy(&tmp_mac.macaddr, macaddr, ETHER_ADDR_LEN);
+       memcpy(&tmp_mac.macaddr, macaddr, ETH_ALEN);
        mac = hash_get(zvni->mac_table, &tmp_mac, zvni_mac_alloc);
        assert(mac);
 
@@ -940,7 +931,7 @@ static zebra_mac_t *zvni_mac_lookup(zebra_vni_t *zvni, struct ethaddr *mac)
        zebra_mac_t *pmac;
 
        memset(&tmp, 0, sizeof(tmp));
-       memcpy(&tmp.macaddr, mac, ETHER_ADDR_LEN);
+       memcpy(&tmp.macaddr, mac, ETH_ALEN);
        pmac = hash_lookup(zvni->mac_table, &tmp);
 
        return pmac;
@@ -1976,7 +1967,7 @@ int zebra_vxlan_local_neigh_add_update(struct interface *ifp,
        if (n) {
                if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)) {
                        if (memcmp(n->emac.octet, macaddr->octet,
-                                  ETHER_ADDR_LEN)
+                                  ETH_ALEN)
                            == 0) {
                                if (n->ifindex == ifp->ifindex)
                                        /* we're not interested in whatever has
@@ -2022,7 +2013,7 @@ int zebra_vxlan_local_neigh_add_update(struct interface *ifp,
 
        /* Set "local" forwarding info. */
        SET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL);
-       memcpy(&n->emac, macaddr, ETHER_ADDR_LEN);
+       memcpy(&n->emac, macaddr, ETH_ALEN);
        n->ifindex = ifp->ifindex;
 
        /* Inform BGP if required. */
@@ -2062,14 +2053,14 @@ int zebra_vxlan_remote_macip_del(struct zserv *client, int sock, u_short length,
                n = NULL;
                memset(&ip, 0, sizeof(ip));
                vni = (vni_t)stream_getl(s);
-               stream_get(&macaddr.octet, s, ETHER_ADDR_LEN);
+               stream_get(&macaddr.octet, s, ETH_ALEN);
                ipa_len = stream_getl(s);
                if (ipa_len) {
                        ip.ipa_type = (ipa_len == IPV4_MAX_BYTELEN) ? IPADDR_V4
                                                                    : IPADDR_V6;
                        stream_get(&ip.ip.addr, s, ipa_len);
                }
-               l += 4 + ETHER_ADDR_LEN + 4 + ipa_len;
+               l += 4 + ETH_ALEN + 4 + ipa_len;
                vtep_ip.s_addr = stream_get_ipv4(s);
                l += IPV4_MAX_BYTELEN;
 
@@ -2148,7 +2139,7 @@ int zebra_vxlan_remote_macip_del(struct zserv *client, int sock, u_short length,
                         */
                        if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE)
                            && (memcmp(n->emac.octet, macaddr.octet,
-                                      ETHER_ADDR_LEN)
+                                      ETH_ALEN)
                                == 0)) {
                                zvni_neigh_uninstall(zvni, n);
                                zvni_neigh_del(zvni, n);
@@ -2205,14 +2196,14 @@ int zebra_vxlan_remote_macip_add(struct zserv *client, int sock, u_short length,
                n = NULL;
                memset(&ip, 0, sizeof(ip));
                vni = (vni_t)stream_getl(s);
-               stream_get(&macaddr.octet, s, ETHER_ADDR_LEN);
+               stream_get(&macaddr.octet, s, ETH_ALEN);
                ipa_len = stream_getl(s);
                if (ipa_len) {
                        ip.ipa_type = (ipa_len == IPV4_MAX_BYTELEN) ? IPADDR_V4
                                                                    : IPADDR_V6;
                        stream_get(&ip.ip.addr, s, ipa_len);
                }
-               l += 4 + ETHER_ADDR_LEN + 4 + ipa_len;
+               l += 4 + ETH_ALEN + 4 + ipa_len;
                vtep_ip.s_addr = stream_get_ipv4(s);
                l += IPV4_MAX_BYTELEN;
 
@@ -2363,7 +2354,7 @@ int zebra_vxlan_remote_macip_add(struct zserv *client, int sock, u_short length,
                        /* Set "remote" forwarding info. */
                        UNSET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL);
                        /* TODO: Handle MAC change. */
-                       memcpy(&n->emac, &macaddr, ETHER_ADDR_LEN);
+                       memcpy(&n->emac, &macaddr, ETH_ALEN);
                        n->r_vtep_ip = vtep_ip;
                        SET_FLAG(n->flags, ZEBRA_NEIGH_REMOTE);
 
index 3bc5f83f6451d68fea444fea5165d275d75f86e9..bdb7755b63ce42748b0c15c7977e1ee57ae096c7 100644 (file)
@@ -55,6 +55,7 @@
 #include "zebra/zebra_mroute.h"
 #include "zebra/label_manager.h"
 #include "zebra/zebra_vxlan.h"
+#include "zebra/rt.h"
 
 /* Event list of zebra. */
 enum event { ZEBRA_SERV, ZEBRA_READ, ZEBRA_WRITE };
@@ -1084,6 +1085,27 @@ int zsend_router_id_update(struct zserv *client, struct prefix *p,
        return zebra_server_send_message(client);
 }
 
+/*
+ * Function used by Zebra to send a PW status update to LDP daemon
+ */
+int zsend_pw_update(struct zserv *client, struct zebra_pw *pw)
+{
+       struct stream *s;
+
+       s = client->obuf;
+       stream_reset(s);
+
+       zserv_create_header(s, ZEBRA_PW_STATUS_UPDATE, pw->vrf_id);
+       stream_write(s, pw->ifname, IF_NAMESIZE);
+       stream_putl(s, pw->ifindex);
+       stream_putl(s, pw->status);
+
+       /* Put length at the first point of the stream. */
+       stream_putw_at(s, 0, stream_get_endp(s));
+
+       return zebra_server_send_message(client);
+}
+
 /* Register zebra server interface information.  Send current all
    interface and address information. */
 static int zread_interface_add(struct zserv *client, u_short length,
@@ -1876,14 +1898,12 @@ static void zread_mpls_labels(int command, struct zserv *client, u_short length,
        if (command == ZEBRA_MPLS_LABELS_ADD) {
                mpls_lsp_install(zvrf, type, in_label, out_label, gtype, &gate,
                                 ifindex);
-               if (out_label != MPLS_IMP_NULL_LABEL)
-                       mpls_ftn_update(1, zvrf, type, &prefix, gtype, &gate,
-                                       ifindex, distance, out_label);
+               mpls_ftn_update(1, zvrf, type, &prefix, gtype, &gate, ifindex,
+                               distance, out_label);
        } else if (command == ZEBRA_MPLS_LABELS_DELETE) {
                mpls_lsp_uninstall(zvrf, type, in_label, gtype, &gate, ifindex);
-               if (out_label != MPLS_IMP_NULL_LABEL)
-                       mpls_ftn_update(0, zvrf, type, &prefix, gtype, &gate,
-                                       ifindex, distance, out_label);
+               mpls_ftn_update(0, zvrf, type, &prefix, gtype, &gate, ifindex,
+                               distance, out_label);
        }
 }
 /* Send response to a label manager connect request to client */
@@ -2038,6 +2058,97 @@ static void zread_label_manager_request(int cmd, struct zserv *client,
        }
 }
 
+static int zread_pseudowire(int command, struct zserv *client, u_short length,
+                           vrf_id_t vrf_id)
+{
+       struct stream *s;
+       struct zebra_vrf *zvrf;
+       char ifname[IF_NAMESIZE];
+       ifindex_t ifindex;
+       int type;
+       int af;
+       union g_addr nexthop;
+       uint32_t local_label;
+       uint32_t remote_label;
+       uint8_t flags;
+       union pw_protocol_fields data;
+       uint8_t protocol;
+       struct zebra_pw *pw;
+
+       zvrf = vrf_info_lookup(vrf_id);
+       if (!zvrf)
+               return -1;
+
+       /* Get input stream.  */
+       s = client->ibuf;
+
+       /* Get data. */
+       stream_get(ifname, s, IF_NAMESIZE);
+       ifindex = stream_getl(s);
+       type = stream_getl(s);
+       af = stream_getl(s);
+       switch (af) {
+       case AF_INET:
+               nexthop.ipv4.s_addr = stream_get_ipv4(s);
+               break;
+       case AF_INET6:
+               stream_get(&nexthop.ipv6, s, 16);
+               break;
+       default:
+               return -1;
+       }
+       local_label = stream_getl(s);
+       remote_label = stream_getl(s);
+       flags = stream_getc(s);
+       stream_get(&data, s, sizeof(data));
+       protocol = client->proto;
+
+       pw = zebra_pw_find(zvrf, ifname);
+       switch (command) {
+       case ZEBRA_PW_ADD:
+               if (pw) {
+                       zlog_warn("%s: pseudowire %s already exists [%s]",
+                                 __func__, ifname,
+                                 zserv_command_string(command));
+                       return -1;
+               }
+
+               zebra_pw_add(zvrf, ifname, protocol, client);
+               break;
+       case ZEBRA_PW_DELETE:
+               if (!pw) {
+                       zlog_warn("%s: pseudowire %s not found [%s]", __func__,
+                                 ifname, zserv_command_string(command));
+                       return -1;
+               }
+
+               zebra_pw_del(zvrf, pw);
+               break;
+       case ZEBRA_PW_SET:
+       case ZEBRA_PW_UNSET:
+               if (!pw) {
+                       zlog_warn("%s: pseudowire %s not found [%s]", __func__,
+                                 ifname, zserv_command_string(command));
+                       return -1;
+               }
+
+               switch (command) {
+               case ZEBRA_PW_SET:
+                       pw->enabled = 1;
+                       break;
+               case ZEBRA_PW_UNSET:
+                       pw->enabled = 0;
+                       break;
+               }
+
+               zebra_pw_change(pw, ifindex, type, af, &nexthop, local_label,
+                               remote_label, flags, &data);
+               break;
+       }
+
+       return 0;
+}
+
 /* Cleanup registered nexthops (across VRFs) upon client disconnect. */
 static void zebra_client_close_cleanup_rnh(struct zserv *client)
 {
@@ -2082,6 +2193,9 @@ static void zebra_client_close(struct zserv *client)
        zebra_mpls_cleanup_fecs_for_client(vrf_info_lookup(VRF_DEFAULT),
                                           client);
 
+       /* Remove pseudowires associated with this client */
+       zebra_pw_client_close(client);
+
        /* Close file descriptor. */
        if (client->sock) {
                unsigned long nroutes;
@@ -2164,6 +2278,31 @@ static void zebra_client_create(int sock)
        zebra_vrf_update_all(client);
 }
 
+static int zread_interface_set_master(struct zserv *client, int sock,
+                                     u_short length)
+{
+       struct interface *master;
+       struct interface *slave;
+       struct stream *s = client->ibuf;
+       int ifindex;
+       vrf_id_t vrf_id;
+
+       vrf_id = stream_getw(s);
+       ifindex = stream_getl(s);
+       master = if_lookup_by_index(ifindex, vrf_id);
+
+       vrf_id = stream_getw(s);
+       ifindex = stream_getl(s);
+       slave = if_lookup_by_index(ifindex, vrf_id);
+
+       if (!master || !slave)
+               return 0;
+
+       kernel_interface_set_master(master, slave);
+
+       return 1;
+}
+
 /* Handler of zebra service request. */
 static int zebra_client_read(struct thread *thread)
 {
@@ -2407,6 +2546,15 @@ static int zebra_client_read(struct thread *thread)
        case ZEBRA_REMOTE_MACIP_DEL:
                zebra_vxlan_remote_macip_del(client, sock, length, zvrf);
                break;
+       case ZEBRA_INTERFACE_SET_MASTER:
+               zread_interface_set_master(client, sock, length);
+               break;
+       case ZEBRA_PW_ADD:
+       case ZEBRA_PW_DELETE:
+       case ZEBRA_PW_SET:
+       case ZEBRA_PW_UNSET:
+               zread_pseudowire(command, client, length, vrf_id);
+               break;
        default:
                zlog_info("Zebra received unknown command %d", command);
                break;
@@ -2618,10 +2766,6 @@ static char *zserv_time_buf(time_t *time1, char *buf, int buflen)
        now -= *time1;
        tm = gmtime(&now);
 
-/* Making formatted timer strings. */
-#define ONE_DAY_SECOND 60*60*24
-#define ONE_WEEK_SECOND 60*60*24*7
-
        if (now < ONE_DAY_SECOND)
                snprintf(buf, buflen, "%02d:%02d:%02d", tm->tm_hour, tm->tm_min,
                         tm->tm_sec);
index a2cf5d9f41dce8fb278533a8f05df931adb38e73..f661572d538e745c0c3eb8bfaa5e5b708eb71599 100644 (file)
@@ -30,6 +30,8 @@
 #include "zclient.h"
 
 #include "zebra/zebra_ns.h"
+#include "zebra/zebra_pw.h"
+
 /* Default port information. */
 #define ZEBRA_VTY_PORT                2601
 
@@ -175,6 +177,7 @@ extern int zsend_interface_vrf_update(struct zserv *, struct interface *,
                                      vrf_id_t);
 
 extern int zsend_interface_link_params(struct zserv *, struct interface *);
+extern int zsend_pw_update(struct zserv *, struct zebra_pw *);
 
 extern pid_t pid;