]> git.proxmox.com Git - mirror_frr.git/commitdiff
Merge pull request #1756 from qlyoung/stylechecker
authorPhilippe Guibert <philippe.guibert@6wind.com>
Thu, 22 Feb 2018 17:55:48 +0000 (18:55 +0100)
committerGitHub <noreply@github.com>
Thu, 22 Feb 2018 17:55:48 +0000 (18:55 +0100)
tools: improve checkpatch.sh

268 files changed:
.clang-format
README
babeld/kernel.c
bgpd/Makefile.am
bgpd/bgp_advertise.c
bgpd/bgp_attr.c
bgpd/bgp_attr.h
bgpd/bgp_attr_evpn.c
bgpd/bgp_attr_evpn.h
bgpd/bgp_bfd.c
bgpd/bgp_debug.c
bgpd/bgp_debug.h
bgpd/bgp_ecommunity.c
bgpd/bgp_evpn.c
bgpd/bgp_evpn.h
bgpd/bgp_evpn_private.h
bgpd/bgp_evpn_vty.c
bgpd/bgp_fsm.c
bgpd/bgp_io.c
bgpd/bgp_io.h
bgpd/bgp_keepalives.c
bgpd/bgp_keepalives.h
bgpd/bgp_label.c
bgpd/bgp_main.c
bgpd/bgp_memory.c
bgpd/bgp_memory.h
bgpd/bgp_mplsvpn.c
bgpd/bgp_mplsvpn.h
bgpd/bgp_nht.c
bgpd/bgp_packet.c
bgpd/bgp_route.c
bgpd/bgp_route.h
bgpd/bgp_routemap.c
bgpd/bgp_snmp.c
bgpd/bgp_updgrp_packet.c
bgpd/bgp_vty.c
bgpd/bgp_vty.h
bgpd/bgp_zebra.c
bgpd/bgp_zebra.h
bgpd/bgpd.c
bgpd/bgpd.h
bgpd/rfapi/bgp_rfapi_cfg.c
bgpd/rfapi/rfapi.c
bgpd/rfapi/rfapi_import.c
bgpd/rfapi/rfapi_rib.c
bgpd/rfapi/rfapi_vty.c
bgpd/rfapi/vnc_export_bgp.c
bgpd/rfapi/vnc_import_bgp.c
bgpd/rfapi/vnc_zebra.c
configure.ac
debianpkg/.gitignore [new file with mode: 0644]
debianpkg/README.deb_build.md
debianpkg/backports/ubuntu12.04/debian/control
debianpkg/backports/ubuntu12.04/debian/rules
debianpkg/backports/ubuntu14.04/debian/control
debianpkg/backports/ubuntu14.04/debian/frr.install
debianpkg/backports/ubuntu14.04/debian/rules
debianpkg/frr.install
debianpkg/rules
doc/Building_FRR_on_Debian9.md
doc/Makefile.am
doc/OSPF-SR.rst [new file with mode: 0644]
doc/bgpd.texi
doc/install.texi
doc/isisd.texi
doc/mtracebis.8.in [new file with mode: 0644]
doc/ospfd.texi
doc/pimd.texi [new file with mode: 0644]
doc/routemap.texi
doc/vnc.texi
eigrpd/eigrp_zebra.c
indent.py
isisd/dict.h
isisd/isis_bpf.c
isisd/isis_circuit.c
isisd/isis_lsp.c
isisd/isis_tlvs.c
isisd/isis_zebra.c
ldpd/labelmapping.c
ldpd/lde.c
ldpd/logmsg.c
lib/command.c
lib/command.h
lib/command_graph.c
lib/command_lex.l
lib/command_match.c
lib/defun_lex.l
lib/frr_pthread.c
lib/frr_pthread.h
lib/grammar_sandbox.c
lib/if.c
lib/if.h
lib/keychain.c
lib/log.c
lib/md5.c
lib/md5.h
lib/mpls.h
lib/nexthop.c
lib/nexthop.h
lib/ns.h
lib/prefix.c
lib/prefix.h
lib/ptm_lib.c
lib/ringbuf.c [new file with mode: 0644]
lib/ringbuf.h [new file with mode: 0644]
lib/spf_backoff.c
lib/subdir.am
lib/thread.c
lib/vrf.c
lib/vrf.h
lib/vty.c
lib/zassert.h
lib/zclient.c
lib/zclient.h
lib/zebra.h
nhrpd/nhrp_route.c
ospf6d/ospf6_abr.c
ospf6d/ospf6_area.c
ospf6d/ospf6_area.h
ospf6d/ospf6_asbr.c
ospf6d/ospf6_asbr.h
ospf6d/ospf6_flood.c
ospf6d/ospf6_flood.h
ospf6d/ospf6_interface.c
ospf6d/ospf6_interface.h
ospf6d/ospf6_intra.c
ospf6d/ospf6_intra.h
ospf6d/ospf6_lsa.c
ospf6d/ospf6_lsa.h
ospf6d/ospf6_lsdb.c
ospf6d/ospf6_main.c
ospf6d/ospf6_memory.c
ospf6d/ospf6_memory.h
ospf6d/ospf6_message.c
ospf6d/ospf6_neighbor.c
ospf6d/ospf6_route.c
ospf6d/ospf6_route.h
ospf6d/ospf6_spf.c
ospf6d/ospf6_spf.h
ospf6d/ospf6_top.c
ospf6d/ospf6_top.h
ospf6d/ospf6_zebra.c
ospf6d/ospf6d.c
ospfd/OSPF-ALIGNMENT.txt
ospfd/ospf_abr.c
ospfd/ospf_apiserver.c
ospfd/ospf_ase.c
ospfd/ospf_dump.c
ospfd/ospf_dump.h
ospfd/ospf_ext.c [new file with mode: 0644]
ospfd/ospf_ext.h [new file with mode: 0644]
ospfd/ospf_flood.c
ospfd/ospf_ia.c
ospfd/ospf_interface.c
ospfd/ospf_interface.h
ospfd/ospf_lsa.c
ospfd/ospf_memory.c
ospfd/ospf_memory.h
ospfd/ospf_network.c
ospfd/ospf_nsm.c
ospfd/ospf_opaque.c
ospfd/ospf_opaque.h
ospfd/ospf_packet.c
ospfd/ospf_ri.c
ospfd/ospf_ri.h
ospfd/ospf_routemap.c
ospfd/ospf_snmp.c
ospfd/ospf_spf.c
ospfd/ospf_sr.c [new file with mode: 0644]
ospfd/ospf_sr.h [new file with mode: 0644]
ospfd/ospf_te.c
ospfd/ospf_te.h
ospfd/ospf_vty.c
ospfd/ospf_vty.h
ospfd/ospf_zebra.c
ospfd/ospfd.c
ospfd/ospfd.h
ospfd/subdir.am
pimd/.gitignore
pimd/COMMANDS
pimd/mtracebis.c [new file with mode: 0644]
pimd/mtracebis_netlink.c [new file with mode: 0644]
pimd/mtracebis_netlink.h [new file with mode: 0644]
pimd/mtracebis_routeget.c [new file with mode: 0644]
pimd/mtracebis_routeget.h [new file with mode: 0644]
pimd/pim_cmd.c
pimd/pim_cmd.h
pimd/pim_igmp.c
pimd/pim_igmp.h
pimd/pim_igmp_mtrace.c [new file with mode: 0644]
pimd/pim_igmp_mtrace.h [new file with mode: 0644]
pimd/pim_instance.c
pimd/pim_nht.c
pimd/pim_oil.c
pimd/pim_oil.h
pimd/pim_vty.c
pimd/pim_vty.h
pimd/pim_zebra.c
pimd/pimd.h
pimd/subdir.am
pkgsrc/README.txt
redhat/frr.spec.in
ripd/rip_zebra.c
ripd/ripd.c
ripd/ripd.conf.sample
ripngd/ripng_zebra.c
ripngd/ripngd.conf.sample
sharpd/.gitignore [new file with mode: 0644]
sharpd/sharp_vty.c
sharpd/sharp_zebra.c
sharpd/sharp_zebra.h
sharpd/subdir.am
tests/Makefile.am
tests/bgpd/test_aspath.c
tests/bgpd/test_capability.c
tests/bgpd/test_mp_attr.c
tests/helpers/c/main.c
tests/lib/test_heavy.c
tests/lib/test_heavy_thread.c
tests/lib/test_privs.c
tests/lib/test_ringbuf.c [new file with mode: 0644]
tests/lib/test_ringbuf.py [new file with mode: 0644]
tools/frr-reload.py
tools/start-stop-daemon.c
vtysh/Makefile.am
vtysh/vtysh.c
vtysh/vtysh.h
vtysh/vtysh_config.c
vtysh/vtysh_main.c
zebra/connected.c
zebra/if_netlink.c
zebra/interface.c
zebra/interface.h
zebra/ipforward_sysctl.c
zebra/kernel_socket.c
zebra/label_manager.c
zebra/main.c
zebra/redistribute.c
zebra/rib.h
zebra/rt.h
zebra/rt_netlink.c
zebra/rt_socket.c
zebra/rtread_getmsg.c
zebra/zebra.conf.sample
zebra/zebra_fpm.c
zebra/zebra_mpls.c
zebra/zebra_mpls.h
zebra/zebra_mpls_vty.c
zebra/zebra_mroute.c
zebra/zebra_ns.c
zebra/zebra_ns.h
zebra/zebra_ptm.c
zebra/zebra_ptm_redistribute.c
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/zebra_vxlan.h
zebra/zebra_vxlan_null.c
zebra/zebra_vxlan_private.h
zebra/zserv.c
zebra/zserv.h

index 21fe9d7c5e570b85d5f68d0c94f37b73f054b516..cc5a95baf6a9d70ba87afe27395d02c46d630886 100644 (file)
@@ -57,3 +57,5 @@ ForEachMacros:
   - SUBGRP_FOREACH_ADJ_SAFE
   - AF_FOREACH
   - FOREACH_AFI_SAFI
+  # ospfd
+  - LSDB_LOOP
diff --git a/README b/README
index bbad60087ba1e3afb81f5d6e466e0212552257e0..af14795a6a4465c7bab8a915441d5612f74861b2 100644 (file)
--- a/README
+++ b/README
@@ -1,12 +1,14 @@
-FRRouting is free software that manages various IPv4 and IPv6 routing
-protocols.
+FRRouting is free software that implements and manages various IPv4 and IPv6
+routing protocols.
 
-Currently FRRouting supports BGP4, BGP4+, OSPFv2, OSPFv3, RIPv1,
-RIPv2, RIPng, PIM-SM/MSDP and LDP as well as very early support for IS-IS,
-EIGRP and NHRP.
+Currently FRRouting supports BGP4, BGP4+, OSPFv2, OSPFv3, RIPv1, RIPv2, RIPng,
+IS-IS, PIM-SM/MSDP, LDP and Babel as well as very early support for EIGRP and
+NHRP.
 
 See the file REPORTING-BUGS to report bugs.
 
+See COMMUNITY.md for information on contributing.
+
 Free RRRouting is free software. See the file COPYING for copying conditions.
 
 Public email discussion can be found at https://lists.frrouting.org/listinfo
index 8c4fc953e7abe217599dac2514f1bb1c4d96b33f..8b1b80665c5afdb768138482f32ceccf6460f43c 100644 (file)
@@ -174,8 +174,8 @@ zebra_route(int add, int family, const unsigned char *pref, unsigned short plen,
         SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP);
         api.nexthop_num = 1;
         api_nh->ifindex = ifindex;
-
-        switch (family) {
+       api_nh->vrf_id = VRF_DEFAULT;
+       switch (family) {
         case AF_INET:
             uchar_to_inaddr(&api_nh->gate.ipv4, gate);
             if (IPV4_ADDR_SAME (&api_nh->gate.ipv4, &quagga_prefix.u.prefix4) &&
index b0d34dc43b8115ba16d888ef2063c4a32b849887..5e08f82774dffdb1238b38f3093b46fb3698c181 100644 (file)
@@ -133,6 +133,7 @@ dist_examples_DATA = bgpd.conf.sample bgpd.conf.sample2 \
        bgpd.conf.vnc.sample
 
 bgp_vty.o: bgp_vty_clippy.c
+bgp_route.o: bgp_route_clippy.c
 
 EXTRA_DIST = BGP4-MIB.txt
 
index 840cc35751f0965c7a1f441f898ca377c2d286ad..29b6ca6bfa788fc72fb5baa2053945d27df1da32 100644 (file)
@@ -246,8 +246,6 @@ void bgp_sync_init(struct peer *peer)
                BGP_ADV_FIFO_INIT(&sync->withdraw);
                BGP_ADV_FIFO_INIT(&sync->withdraw_low);
                peer->sync[afi][safi] = sync;
-               peer->hash[afi][safi] = hash_create(baa_hash_key, baa_hash_cmp,
-                                                   "BGP Sync Hash");
        }
 }
 
@@ -260,9 +258,5 @@ void bgp_sync_delete(struct peer *peer)
                if (peer->sync[afi][safi])
                        XFREE(MTYPE_BGP_SYNCHRONISE, peer->sync[afi][safi]);
                peer->sync[afi][safi] = NULL;
-
-               if (peer->hash[afi][safi])
-                       hash_free(peer->hash[afi][safi]);
-               peer->hash[afi][safi] = NULL;
        }
 }
index e80889500f089df249d0dbeb656f51124b532bb4..3f3acbe0e2923db2638035a707dc494883508cb5 100644 (file)
@@ -74,6 +74,7 @@ static const struct message attr_str[] = {
        {BGP_ATTR_AS4_PATH, "AS4_PATH"},
        {BGP_ATTR_AS4_AGGREGATOR, "AS4_AGGREGATOR"},
        {BGP_ATTR_AS_PATHLIMIT, "AS_PATHLIMIT"},
+       {BGP_ATTR_PMSI_TUNNEL, "PMSI_TUNNEL_ATTRIBUTE"},
        {BGP_ATTR_ENCAP, "ENCAP"},
 #if ENABLE_BGP_VNC
        {BGP_ATTR_VNC, "VNC"},
@@ -492,19 +493,13 @@ unsigned int attrhash_key_make(void *p)
        const struct attr *attr = (struct attr *)p;
        uint32_t key = 0;
 #define MIX(val)       key = jhash_1word(val, key)
+#define MIX3(a, b, c)  key = jhash_3words((a), (b), (c), key)
 
-       MIX(attr->origin);
-       MIX(attr->nexthop.s_addr);
-       MIX(attr->med);
-       MIX(attr->local_pref);
-       MIX(attr->aggregator_as);
-       MIX(attr->aggregator_addr.s_addr);
-       MIX(attr->weight);
-       MIX(attr->mp_nexthop_global_in.s_addr);
-       MIX(attr->originator_id.s_addr);
-       MIX(attr->tag);
-       MIX(attr->label);
-       MIX(attr->label_index);
+       MIX3(attr->origin, attr->nexthop.s_addr, attr->med);
+       MIX3(attr->local_pref, attr->aggregator_as, attr->aggregator_addr.s_addr);
+       MIX3(attr->weight, attr->mp_nexthop_global_in.s_addr,
+            attr->originator_id.s_addr);
+       MIX3(attr->tag, attr->label, attr->label_index);
 
        if (attr->aspath)
                MIX(aspath_key_make(attr->aspath));
@@ -550,12 +545,6 @@ int attrhash_cmp(const void *p1, const void *p2)
                    && attr1->tag == attr2->tag
                    && attr1->label_index == attr2->label_index
                    && attr1->mp_nexthop_len == attr2->mp_nexthop_len
-                   && IPV6_ADDR_SAME(&attr1->mp_nexthop_global,
-                                     &attr2->mp_nexthop_global)
-                   && IPV6_ADDR_SAME(&attr1->mp_nexthop_local,
-                                     &attr2->mp_nexthop_local)
-                   && IPV4_ADDR_SAME(&attr1->mp_nexthop_global_in,
-                                     &attr2->mp_nexthop_global_in)
                    && attr1->ecommunity == attr2->ecommunity
                    && attr1->lcommunity == attr2->lcommunity
                    && attr1->cluster == attr2->cluster
@@ -565,6 +554,12 @@ int attrhash_cmp(const void *p1, const void *p2)
 #if ENABLE_BGP_VNC
                    && encap_same(attr1->vnc_subtlvs, attr2->vnc_subtlvs)
 #endif
+                   && IPV6_ADDR_SAME(&attr1->mp_nexthop_global,
+                                     &attr2->mp_nexthop_global)
+                   && IPV6_ADDR_SAME(&attr1->mp_nexthop_local,
+                                     &attr2->mp_nexthop_local)
+                   && IPV4_ADDR_SAME(&attr1->mp_nexthop_global_in,
+                                     &attr2->mp_nexthop_global_in)
                    && IPV4_ADDR_SAME(&attr1->originator_id,
                                      &attr2->originator_id)
                    && overlay_index_same(attr1, attr2))
@@ -1040,6 +1035,8 @@ const u_int8_t attr_flags_values[] = {
                        BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
                [BGP_ATTR_AS4_AGGREGATOR] =
                        BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
+               [BGP_ATTR_PMSI_TUNNEL] =
+                       BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
                [BGP_ATTR_LARGE_COMMUNITIES] =
                        BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
                [BGP_ATTR_PREFIX_SID] =
@@ -1879,6 +1876,12 @@ bgp_attr_ext_communities(struct bgp_attr_parser_args *args)
        attr->mm_seqnum = bgp_attr_mac_mobility_seqnum(attr, &sticky);
        attr->sticky = sticky;
 
+       /* Check if this is a Gateway MAC-IP advertisement */
+       attr->default_gw = bgp_attr_default_gw(attr);
+
+       /* Extract the Rmac, if any */
+       bgp_attr_rmac(attr, &attr->rmac);
+
        return BGP_ATTR_PARSE_PROCEED;
 }
 
@@ -2698,8 +2701,9 @@ size_t bgp_packet_mpattr_start(struct stream *s, struct peer *peer, afi_t afi,
 
 void bgp_packet_mpattr_prefix(struct stream *s, afi_t afi, safi_t safi,
                              struct prefix *p, struct prefix_rd *prd,
-                             mpls_label_t *label, int addpath_encode,
-                             u_int32_t addpath_tx_id, struct attr *attr)
+                             mpls_label_t *label, u_int32_t num_labels,
+                             int addpath_encode, u_int32_t addpath_tx_id,
+                             struct attr *attr)
 {
        if (safi == SAFI_MPLS_VPN) {
                if (addpath_encode)
@@ -2711,8 +2715,8 @@ void bgp_packet_mpattr_prefix(struct stream *s, afi_t afi, safi_t safi,
                stream_put(s, &p->u.prefix, PSIZE(p->prefixlen));
        } else if (afi == AFI_L2VPN && safi == SAFI_EVPN) {
                /* EVPN prefix - contents depend on type */
-               bgp_evpn_encode_prefix(s, p, prd, label, attr, addpath_encode,
-                                      addpath_tx_id);
+               bgp_evpn_encode_prefix(s, p, prd, label, num_labels,
+                                      attr, addpath_encode, addpath_tx_id);
        } else if (safi == SAFI_LABELED_UNICAST) {
                /* Prefix write with label. */
                stream_put_labeled_prefix(s, p, label);
@@ -2840,8 +2844,8 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer,
                                struct bpacket_attr_vec_arr *vecarr,
                                struct prefix *p, afi_t afi, safi_t safi,
                                struct peer *from, struct prefix_rd *prd,
-                               mpls_label_t *label, int addpath_encode,
-                               u_int32_t addpath_tx_id)
+                               mpls_label_t *label, u_int32_t num_labels,
+                               int addpath_encode, u_int32_t addpath_tx_id)
 {
        size_t cp;
        size_t aspath_sizep;
@@ -2863,7 +2867,8 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer,
 
                mpattrlen_pos = bgp_packet_mpattr_start(s, peer, afi, safi,
                                                        vecarr, attr);
-               bgp_packet_mpattr_prefix(s, afi, safi, p, prd, label,
+               bgp_packet_mpattr_prefix(s, afi, safi, p, prd,
+                                        label, num_labels,
                                         addpath_encode, addpath_tx_id, attr);
                bgp_packet_mpattr_end(s, mpattrlen_pos);
        }
@@ -3252,6 +3257,17 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer,
 #endif
        }
 
+       /* PMSI Tunnel */
+       if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_PMSI_TUNNEL)) {
+               stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS);
+               stream_putc(s, BGP_ATTR_PMSI_TUNNEL);
+               stream_putc(s, 9); // Length
+               stream_putc(s, 0); // Flags
+               stream_putc(s, 6); // Tunnel type: Ingress Replication (6)
+               stream_put(s, &(attr->label), BGP_LABEL_BYTES); // MPLS Label / VXLAN VNI
+               stream_put_ipv4(s, attr->nexthop.s_addr); // Unicast tunnel endpoint IP address
+       }
+
        /* Unknown transit attribute. */
        if (attr->transit)
                stream_put(s, attr->transit->val, attr->transit->length);
@@ -3284,15 +3300,19 @@ size_t bgp_packet_mpunreach_start(struct stream *s, afi_t afi, safi_t safi)
 
 void bgp_packet_mpunreach_prefix(struct stream *s, struct prefix *p, afi_t afi,
                                 safi_t safi, struct prefix_rd *prd,
-                                mpls_label_t *label, int addpath_encode,
-                                u_int32_t addpath_tx_id, struct attr *attr)
+                                mpls_label_t *label, u_int32_t num_labels,
+                                int addpath_encode, u_int32_t addpath_tx_id,
+                                struct attr *attr)
 {
        u_char wlabel[3] = {0x80, 0x00, 0x00};
 
-       if (safi == SAFI_LABELED_UNICAST)
+       if (safi == SAFI_LABELED_UNICAST) {
                label = (mpls_label_t *)wlabel;
+               num_labels = 1;
+       }
 
-       return bgp_packet_mpattr_prefix(s, afi, safi, p, prd, label,
+       return bgp_packet_mpattr_prefix(s, afi, safi, p, prd,
+                                       label, num_labels,
                                        addpath_encode, addpath_tx_id, attr);
 }
 
index f694f01adb10be860f746d0d0d3232b3cc288908..1b1471a198974cdb7e4de38639225e1ba1a6bad4 100644 (file)
@@ -162,6 +162,9 @@ struct attr {
        /* Static MAC for EVPN */
        u_char sticky;
 
+       /* Flag for default gateway extended community in EVPN */
+       u_char default_gw;
+
        /* route tag */
        route_tag_t tag;
 
@@ -182,6 +185,9 @@ struct attr {
 
        /* EVPN MAC Mobility sequence number, if any. */
        u_int32_t mm_seqnum;
+
+       /* EVPN local router-mac */
+       struct ethaddr rmac;
 };
 
 /* rmap_change_flags definition */
@@ -254,7 +260,8 @@ extern bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *,
                                       struct bpacket_attr_vec_arr *vecarr,
                                       struct prefix *, afi_t, safi_t,
                                       struct peer *, struct prefix_rd *,
-                                      mpls_label_t *, int, u_int32_t);
+                                      mpls_label_t *, u_int32_t,
+                                      int, u_int32_t);
 extern void bgp_dump_routes_attr(struct stream *, struct attr *,
                                 struct prefix *);
 extern int attrhash_cmp(const void *, const void *);
@@ -302,7 +309,8 @@ extern size_t bgp_packet_mpattr_start(struct stream *s, struct peer *peer,
                                      struct attr *attr);
 extern void bgp_packet_mpattr_prefix(struct stream *s, afi_t afi, safi_t safi,
                                     struct prefix *p, struct prefix_rd *prd,
-                                    mpls_label_t *label, int addpath_encode,
+                                    mpls_label_t *label, u_int32_t num_labels,
+                                    int addpath_encode,
                                     u_int32_t addpath_tx_id, struct attr *);
 extern size_t bgp_packet_mpattr_prefix_size(afi_t afi, safi_t safi,
                                            struct prefix *p);
@@ -312,7 +320,8 @@ extern size_t bgp_packet_mpunreach_start(struct stream *s, afi_t afi,
                                         safi_t safi);
 extern void bgp_packet_mpunreach_prefix(struct stream *s, struct prefix *p,
                                        afi_t afi, safi_t safi,
-                                       struct prefix_rd *prd, mpls_label_t *,
+                                       struct prefix_rd *prd,
+                                       mpls_label_t *, u_int32_t,
                                        int, u_int32_t, struct attr *);
 extern void bgp_packet_mpunreach_end(struct stream *s, size_t attrlen_pnt);
 
index 300c9ddb506a4f471a788ba351dfa4af33474986..e74fa5a2be5876ae9383e166a23dfabe9f777fb7 100644 (file)
@@ -105,6 +105,65 @@ char *ecom_mac2str(char *ecom_mac)
        return prefix_mac2str((struct ethaddr *)en, NULL, 0);
 }
 
+/* Fetch router-mac from extended community */
+void bgp_attr_rmac(struct attr *attr,
+                  struct ethaddr *rmac)
+{
+       int i = 0;
+       struct ecommunity *ecom;
+
+       ecom = attr->ecommunity;
+       if (!ecom || !ecom->size)
+               return;
+
+       /* If there is a router mac extended community, set RMAC in attr */
+       for (i = 0; i < ecom->size; i++) {
+               u_char *pnt = NULL;
+               u_char type = 0;
+               u_char sub_type = 0;
+
+               pnt = (ecom->val + (i * ECOMMUNITY_SIZE));
+               type = *pnt++;
+               sub_type = *pnt++;
+
+               if (!(type == ECOMMUNITY_ENCODE_EVPN &&
+                    sub_type == ECOMMUNITY_EVPN_SUBTYPE_ROUTERMAC))
+                       continue;
+
+               memcpy(rmac, pnt, ETH_ALEN);
+       }
+}
+
+/*
+ * return true if attr contains default gw extended community
+ */
+uint8_t bgp_attr_default_gw(struct attr *attr)
+{
+       struct ecommunity       *ecom;
+       int                     i;
+
+       ecom = attr->ecommunity;
+       if (!ecom || !ecom->size)
+               return 0;
+
+       /* If there is a default gw extendd community return true otherwise
+        * return 0 */
+       for (i = 0; i < ecom->size; i++) {
+               u_char          *pnt;
+               u_char          type, sub_type;
+
+               pnt = (ecom->val + (i * ECOMMUNITY_SIZE));
+               type = *pnt++;
+               sub_type = *pnt++;
+
+               if ((type == ECOMMUNITY_ENCODE_OPAQUE
+                     && sub_type == ECOMMUNITY_EVPN_SUBTYPE_DEF_GW))
+                       return 1;
+       }
+
+       return 0;
+}
+
 /*
  * Fetch and return the sequence number from MAC Mobility extended
  * community, if present, else 0.
index 15d9e126e404cd8e2ac42a4fa5a653355f507b7a..a211da8d2f0d746f23823c98bd0c2d8e1b41a0b3 100644 (file)
@@ -59,8 +59,9 @@ extern void bgp_add_routermac_ecom(struct attr *attr,
                                   struct ethaddr *routermac);
 extern int bgp_build_evpn_prefix(int type, uint32_t eth_tag,
                                 struct prefix *dst);
-
+extern void bgp_attr_rmac(struct attr *attr, struct ethaddr *rmac);
 extern u_int32_t bgp_attr_mac_mobility_seqnum(struct attr *attr,
                                              u_char *sticky);
+extern uint8_t bgp_attr_default_gw(struct attr *attr);
 
 #endif /* _QUAGGA_BGP_ATTR_EVPN_H */
index 2e277bfa5ff6909960e020fa2215064cea8984dd..ce46b21f03d1be51d1de1224ff43c6184c4bae56 100644 (file)
@@ -302,13 +302,13 @@ static int bgp_bfd_dest_update(int command, struct zclient *zclient,
                prefix2str(&dp, buf[0], sizeof(buf[0]));
                if (ifp) {
                        zlog_debug(
-                               "Zebra: vrf %d interface %s bfd destination %s %s",
+                               "Zebra: vrf %u interface %s bfd destination %s %s",
                                vrf_id, ifp->name, buf[0],
                                bfd_get_status_str(status));
                } else {
                        prefix2str(&sp, buf[1], sizeof(buf[1]));
                        zlog_debug(
-                               "Zebra: vrf %d source %s bfd destination %s %s",
+                               "Zebra: vrf %u source %s bfd destination %s %s",
                                vrf_id, buf[1], buf[0],
                                bfd_get_status_str(status));
                }
index 45ac8e68597fbf1ccabf712d5c77d0270acbc503..e89f399e418d0e424564f89c48fb6296ace4f428 100644 (file)
@@ -385,8 +385,8 @@ int bgp_dump_attr(struct attr *attr, char *buf, size_t size)
 
        if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES)))
                snprintf(buf + strlen(buf), size - strlen(buf),
-                        ", community %s", community_str(attr->community,
-                                                        false));
+                        ", community %s",
+                        community_str(attr->community, false));
 
        if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES)))
                snprintf(buf + strlen(buf), size - strlen(buf),
@@ -2017,8 +2017,9 @@ int bgp_debug_zebra(struct prefix *p)
 const char *bgp_debug_rdpfxpath2str(afi_t afi, safi_t safi,
                                    struct prefix_rd *prd,
                                    union prefixconstptr pu,
-                                   mpls_label_t *label, int addpath_valid,
-                                   u_int32_t addpath_id, char *str, int size)
+                                   mpls_label_t *label, u_int32_t num_labels,
+                                   int addpath_valid, u_int32_t addpath_id,
+                                   char *str, int size)
 {
        char rd_buf[RD_ADDRSTRLEN];
        char pfx_buf[PREFIX_STRLEN];
@@ -2041,11 +2042,19 @@ const char *bgp_debug_rdpfxpath2str(afi_t afi, safi_t safi,
                         addpath_id);
 
        tag_buf[0] = '\0';
-       if (bgp_labeled_safi(safi) && label) {
-               u_int32_t label_value;
+       if (bgp_labeled_safi(safi) && num_labels) {
 
-               label_value = decode_label(label);
-               sprintf(tag_buf, " label %u", label_value);
+               if (safi == SAFI_EVPN) {
+                       char tag_buf2[20];
+
+                       bgp_evpn_label2str(label, num_labels, tag_buf2, 20);
+                       sprintf(tag_buf, " label %s", tag_buf2);
+               } else {
+                       u_int32_t label_value;
+
+                       label_value = decode_label(label);
+                       sprintf(tag_buf, " label %u", label_value);
+               }
        }
 
        if (prd)
index 5fe19b162b88d80c25f18a5d6cac5b685e1c4dca..765e43f5b4330b4a87a3525129df7ecd6d5d39ea 100644 (file)
@@ -154,7 +154,8 @@ extern int bgp_debug_zebra(struct prefix *p);
 extern int bgp_debug_count(void);
 extern const char *bgp_debug_rdpfxpath2str(afi_t, safi_t, struct prefix_rd *,
                                           union prefixconstptr, mpls_label_t *,
-                                          int, u_int32_t, char *, int);
+                                          u_int32_t, int, u_int32_t, char *,
+                                          int);
 const char *bgp_notify_admin_message(char *buf, size_t bufsz, u_char *data,
                                     size_t datalen);
 
index e19f516505f0d840c443bbfd8be00c3c52a0b8c2..7dafde51a120ad5f57f1b384096773d749c4f97c 100644 (file)
@@ -690,24 +690,27 @@ char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter)
                                tunneltype = ntohs(tunneltype);
                                len = sprintf(str_buf + str_pnt, "ET:%d",
                                              tunneltype);
+                       }  else if (*pnt == ECOMMUNITY_EVPN_SUBTYPE_DEF_GW) {
+                               len = sprintf(str_buf + str_pnt,
+                                             "Default Gateway");
                        } else
                                unk_ecom = 1;
                } else if (type == ECOMMUNITY_ENCODE_EVPN) {
                        if (filter == ECOMMUNITY_ROUTE_TARGET)
                                continue;
-                       if (*pnt == ECOMMUNITY_SITE_ORIGIN) {
-                               char macaddr[6];
+                       if (*pnt == ECOMMUNITY_EVPN_SUBTYPE_ROUTERMAC) {
+                               struct ethaddr rmac;
                                pnt++;
-                               memcpy(&macaddr, pnt, 6);
+                               memcpy(&rmac, pnt, ETH_ALEN);
                                len = sprintf(
                                        str_buf + str_pnt,
-                                       "EVPN:%02x:%02x:%02x:%02x:%02x:%02x",
-                                       (uint8_t)macaddr[0],
-                                       (uint8_t)macaddr[1],
-                                       (uint8_t)macaddr[2],
-                                       (uint8_t)macaddr[3],
-                                       (uint8_t)macaddr[4],
-                                       (uint8_t)macaddr[5]);
+                                       "Rmac:%02x:%02x:%02x:%02x:%02x:%02x",
+                                       (uint8_t)rmac.octet[0],
+                                       (uint8_t)rmac.octet[1],
+                                       (uint8_t)rmac.octet[2],
+                                       (uint8_t)rmac.octet[3],
+                                       (uint8_t)rmac.octet[4],
+                                       (uint8_t)rmac.octet[5]);
                        } else if (*pnt
                                   == ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY) {
                                u_int32_t seqnum;
index 182a6c64f2b3aad2a4c7dfef627959b4b77fd0d9..ec8e2907a69c5b641005259c6df6f30ccbd34627 100644 (file)
@@ -92,6 +92,120 @@ static int vni_hash_cmp(const void *p1, const void *p2)
        return (vpn1->vni == vpn2->vni);
 }
 
+/*
+ * Make vrf import route target hash key.
+ */
+static unsigned int vrf_import_rt_hash_key_make(void *p)
+{
+       struct vrf_irt_node *irt = p;
+       char *pnt = irt->rt.val;
+
+       return jhash(pnt, 8, 0x5abc1234);
+}
+
+/*
+ * Comparison function for vrf import rt hash
+ */
+static int vrf_import_rt_hash_cmp(const void *p1, const void *p2)
+{
+       const struct vrf_irt_node *irt1 = p1;
+       const struct vrf_irt_node *irt2 = p2;
+
+       if (irt1 == NULL && irt2 == NULL)
+               return 1;
+
+       if (irt1 == NULL || irt2 == NULL)
+               return 0;
+
+       return (memcmp(irt1->rt.val, irt2->rt.val, ECOMMUNITY_SIZE) == 0);
+}
+
+/*
+ * Create a new vrf import_rt in default instance
+ */
+static struct vrf_irt_node *vrf_import_rt_new(struct ecommunity_val *rt)
+{
+       struct bgp *bgp_def = NULL;
+       struct vrf_irt_node *irt;
+
+       bgp_def = bgp_get_default();
+       if (!bgp_def) {
+               zlog_err("vrf import rt new - def instance not created yet");
+               return NULL;
+       }
+
+       irt = XCALLOC(MTYPE_BGP_EVPN_VRF_IMPORT_RT,
+                     sizeof(struct vrf_irt_node));
+       if (!irt)
+               return NULL;
+
+       irt->rt = *rt;
+       irt->vrfs = list_new();
+
+       /* Add to hash */
+       if (!hash_get(bgp_def->vrf_import_rt_hash, irt, hash_alloc_intern)) {
+               XFREE(MTYPE_BGP_EVPN_VRF_IMPORT_RT, irt);
+               return NULL;
+       }
+
+       return irt;
+}
+
+/*
+ * Free the vrf import rt node
+ */
+static void vrf_import_rt_free(struct vrf_irt_node *irt)
+{
+       struct bgp *bgp_def = NULL;
+
+       bgp_def = bgp_get_default();
+       if (!bgp_def) {
+               zlog_err("vrf import rt free - def instance not created yet");
+               return;
+       }
+
+       hash_release(bgp_def->vrf_import_rt_hash, irt);
+       XFREE(MTYPE_BGP_EVPN_VRF_IMPORT_RT, irt);
+}
+
+/*
+ * Function to lookup Import RT node - used to map a RT to set of
+ * VNIs importing routes with that RT.
+ */
+static struct vrf_irt_node *lookup_vrf_import_rt(struct ecommunity_val *rt)
+{
+       struct bgp *bgp_def = NULL;
+       struct vrf_irt_node *irt;
+       struct vrf_irt_node tmp;
+
+       bgp_def = bgp_get_default();
+       if (!bgp_def) {
+               zlog_err("vrf import rt lookup - def instance not created yet");
+               return NULL;
+       }
+
+       memset(&tmp, 0, sizeof(struct vrf_irt_node));
+       memcpy(&tmp.rt, rt, ECOMMUNITY_SIZE);
+       irt = hash_lookup(bgp_def->vrf_import_rt_hash, &tmp);
+       return irt;
+}
+
+/*
+ * Is specified VRF present on the RT's list of "importing" VRFs?
+ */
+static int is_vrf_present_in_irt_vrfs(struct list *vrfs,
+                                     struct bgp *bgp_vrf)
+{
+       struct listnode *node = NULL, *nnode = NULL;
+       struct bgp *tmp_bgp_vrf = NULL;
+
+       for (ALL_LIST_ELEMENTS(vrfs, node, nnode, tmp_bgp_vrf)) {
+               if (tmp_bgp_vrf == bgp_vrf)
+                       return 1;
+       }
+       return 0;
+}
+
 /*
  * Make import route target hash key.
  */
@@ -99,19 +213,8 @@ static unsigned int import_rt_hash_key_make(void *p)
 {
        struct irt_node *irt = p;
        char *pnt = irt->rt.val;
-       unsigned int key = 0;
-       int c = 0;
 
-       key += pnt[c];
-       key += pnt[c + 1];
-       key += pnt[c + 2];
-       key += pnt[c + 3];
-       key += pnt[c + 4];
-       key += pnt[c + 5];
-       key += pnt[c + 6];
-       key += pnt[c + 7];
-
-       return (key);
+       return jhash(pnt, 8, 0xdeadbeef);
 }
 
 /*
@@ -246,6 +349,57 @@ static inline void mask_ecom_global_admin(struct ecommunity_val *dst,
        }
 }
 
+/*
+ * Map one RT to specified VRF.
+ * bgp_vrf = BGP vrf instance
+ */
+static void map_vrf_to_rt(struct bgp *bgp_vrf,
+                         struct ecommunity_val *eval)
+{
+       struct vrf_irt_node *irt = NULL;
+       struct ecommunity_val eval_tmp;
+
+       /* If using "automatic" RT,
+        * we only care about the local-admin sub-field.
+        * This is to facilitate using L3VNI(VRF-VNI)
+        * as the RT for EBGP peering too.
+        */
+       memcpy(&eval_tmp, eval, ECOMMUNITY_SIZE);
+       if (!CHECK_FLAG(bgp_vrf->vrf_flags,
+                       BGP_VRF_IMPORT_RT_CFGD))
+               mask_ecom_global_admin(&eval_tmp, eval);
+
+       irt = lookup_vrf_import_rt(&eval_tmp);
+       if (irt && irt->vrfs)
+               if (is_vrf_present_in_irt_vrfs(irt->vrfs, bgp_vrf))
+                       /* Already mapped. */
+                       return;
+
+       if (!irt) {
+               irt = vrf_import_rt_new(&eval_tmp);
+               assert(irt);
+       }
+
+       /* Add VRF to the list for this RT. */
+       listnode_add(irt->vrfs, bgp_vrf);
+}
+
+/*
+ * Unmap specified VRF from specified RT. If there are no other
+ * VRFs for this RT, then the RT hash is deleted.
+ * bgp_vrf: BGP VRF specific instance
+ */
+static void unmap_vrf_from_rt(struct bgp *bgp_vrf,
+                             struct vrf_irt_node *irt)
+{
+       /* Delete VRF from list for this RT. */
+       listnode_delete(irt->vrfs, bgp_vrf);
+       if (!listnode_head(irt->vrfs)) {
+               list_delete_and_null(&irt->vrfs);
+               vrf_import_rt_free(irt);
+       }
+}
+
 /*
  * Map one RT to specified VNI.
  */
@@ -301,12 +455,12 @@ static void unmap_vni_from_rt(struct bgp *bgp, struct bgpevpn *vpn,
  * VNIs but the same across routers (in the same AS) for a particular
  * VNI.
  */
-static void form_auto_rt(struct bgp *bgp, struct bgpevpn *vpn, struct list *rtl)
+static void form_auto_rt(struct bgp *bgp, vni_t vni, struct list *rtl)
 {
        struct ecommunity_val eval;
        struct ecommunity *ecomadd;
 
-       encode_route_target_as((bgp->as & 0xFFFF), vpn->vni, &eval);
+       encode_route_target_as((bgp->as & 0xFFFF), vni, &eval);
 
        ecomadd = ecommunity_new();
        ecommunity_add_val(ecomadd, &eval);
@@ -330,7 +484,7 @@ static void derive_rd_rt_for_vni(struct bgp *bgp, struct bgpevpn *vpn)
 static int bgp_zebra_send_remote_macip(struct bgp *bgp, struct bgpevpn *vpn,
                                       struct prefix_evpn *p,
                                       struct in_addr remote_vtep_ip, int add,
-                                      u_char sticky)
+                                      u_char flags)
 {
        struct stream *s;
        int ipa_len;
@@ -365,18 +519,18 @@ static int bgp_zebra_send_remote_macip(struct bgp *bgp, struct bgpevpn *vpn,
        }
        stream_put_in_addr(s, &remote_vtep_ip);
 
-       /* TX MAC sticky status */
+       /* TX flags - MAC sticky status and/or gateway mac */
        if (add)
-               stream_putc(s, sticky);
+               stream_putc(s, flags);
 
        stream_putw_at(s, 0, stream_get_endp(s));
 
        if (bgp_debug_zebra(NULL))
-               zlog_debug("Tx %s MACIP, VNI %u %sMAC %s IP %s remote VTEP %s",
+               zlog_debug("Tx %s MACIP, VNI %u MAC %s IP %s (flags: 0x%x) remote VTEP %s",
                           add ? "ADD" : "DEL", vpn->vni,
-                          sticky ? "sticky " : "",
                           prefix_mac2str(&p->prefix.mac, buf1, sizeof(buf1)),
                           ipaddr2str(&p->prefix.ip, buf3, sizeof(buf3)),
+                          flags,
                           inet_ntop(AF_INET, &remote_vtep_ip, buf2,
                                     sizeof(buf2)));
 
@@ -425,20 +579,78 @@ static int bgp_zebra_send_remote_vtep(struct bgp *bgp, struct bgpevpn *vpn,
        return zclient_send_message(zclient);
 }
 
+/*
+ * Build extended communities for EVPN prefix route.
+ */
+static void build_evpn_type5_route_extcomm(struct bgp *bgp_vrf,
+                                          struct attr *attr)
+{
+       struct ecommunity ecom_encap;
+       struct ecommunity ecom_rmac;
+       struct ecommunity_val eval;
+       struct ecommunity_val eval_rmac;
+       bgp_encap_types tnl_type;
+       struct listnode *node, *nnode;
+       struct ecommunity *ecom;
+       struct list *vrf_export_rtl = NULL;
+
+       /* Encap */
+       tnl_type = BGP_ENCAP_TYPE_VXLAN;
+       memset(&ecom_encap, 0, sizeof(ecom_encap));
+       encode_encap_extcomm(tnl_type, &eval);
+       ecom_encap.size = 1;
+       ecom_encap.val = (u_int8_t *)eval.val;
+
+       /* Add Encap */
+       attr->ecommunity = ecommunity_dup(&ecom_encap);
+
+       /* Add the export RTs for L3VNI/VRF */
+       vrf_export_rtl = bgp_vrf->vrf_export_rtl;
+       if (vrf_export_rtl && !list_isempty(vrf_export_rtl)) {
+               for (ALL_LIST_ELEMENTS(vrf_export_rtl, node, nnode, ecom))
+                       attr->ecommunity = ecommunity_merge(attr->ecommunity,
+                                                           ecom);
+       }
+
+       /* add the router mac extended community */
+       if (!is_zero_mac(&attr->rmac)) {
+               memset(&ecom_rmac, 0, sizeof(ecom_rmac));
+               encode_rmac_extcomm(&eval_rmac, &attr->rmac);
+               ecom_rmac.size = 1;
+               ecom_rmac.val = (uint8_t *)eval_rmac.val;
+               attr->ecommunity = ecommunity_merge(attr->ecommunity,
+                                                   &ecom_rmac);
+       }
+
+       attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES);
+}
+
 /*
  * Build extended communities for EVPN route. RT and ENCAP are
  * applicable to all routes.
+ * TODO: currently kernel doesnt support ipv6 routes with ipv4 nexthops.
+ * This means that we can't do symmetric routing for ipv6 hosts routes
+ * in the same way as ipv4 host routes.
+ * We wont attach l3-vni related RTs for ipv6 routes.
+ * For now, We will only adevrtise ipv4 host routes
+ * with L3-VNI related ext-comm.
  */
-static void build_evpn_route_extcomm(struct bgpevpn *vpn, struct attr *attr)
+static void build_evpn_route_extcomm(struct bgpevpn *vpn, struct attr *attr,
+                                    afi_t afi)
 {
        struct ecommunity ecom_encap;
        struct ecommunity ecom_sticky;
+       struct ecommunity ecom_default_gw;
+       struct ecommunity ecom_rmac;
        struct ecommunity_val eval;
        struct ecommunity_val eval_sticky;
+       struct ecommunity_val eval_default_gw;
+       struct ecommunity_val eval_rmac;
        bgp_encap_types tnl_type;
        struct listnode *node, *nnode;
        struct ecommunity *ecom;
        u_int32_t seqnum;
+       struct list *vrf_export_rtl = NULL;
 
        /* Encap */
        tnl_type = BGP_ENCAP_TYPE_VXLAN;
@@ -450,10 +662,24 @@ static void build_evpn_route_extcomm(struct bgpevpn *vpn, struct attr *attr)
        /* Add Encap */
        attr->ecommunity = ecommunity_dup(&ecom_encap);
 
-       /* Add the export RTs */
+       /* Add the export RTs for L2VNI */
        for (ALL_LIST_ELEMENTS(vpn->export_rtl, node, nnode, ecom))
                attr->ecommunity = ecommunity_merge(attr->ecommunity, ecom);
 
+       /* Add the export RTs for L3VNI - currently only supported for IPV4 host
+        * routes
+        */
+       if (afi == AFI_IP) {
+               vrf_export_rtl = bgpevpn_get_vrf_export_rtl(vpn);
+               if (vrf_export_rtl && !list_isempty(vrf_export_rtl)) {
+                       for (ALL_LIST_ELEMENTS(vrf_export_rtl, node, nnode,
+                                              ecom))
+                               attr->ecommunity =
+                                       ecommunity_merge(attr->ecommunity,
+                                                        ecom);
+               }
+       }
+
        if (attr->sticky) {
                seqnum = 0;
                memset(&ecom_sticky, 0, sizeof(ecom_sticky));
@@ -464,6 +690,24 @@ static void build_evpn_route_extcomm(struct bgpevpn *vpn, struct attr *attr)
                        ecommunity_merge(attr->ecommunity, &ecom_sticky);
        }
 
+       if (afi == AFI_IP && !is_zero_mac(&attr->rmac)) {
+               memset(&ecom_rmac, 0, sizeof(ecom_rmac));
+               encode_rmac_extcomm(&eval_rmac, &attr->rmac);
+               ecom_rmac.size = 1;
+               ecom_rmac.val = (uint8_t *)eval_rmac.val;
+               attr->ecommunity = ecommunity_merge(attr->ecommunity,
+                                                   &ecom_rmac);
+       }
+
+       if (attr->default_gw) {
+               memset(&ecom_default_gw, 0, sizeof(ecom_default_gw));
+               encode_default_gw_extcomm(&eval_default_gw);
+               ecom_default_gw.size = 1;
+               ecom_default_gw.val = (uint8_t *)eval_default_gw.val;
+               attr->ecommunity = ecommunity_merge(attr->ecommunity,
+                                                   &ecom_default_gw);
+       }
+
        attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES);
 }
 
@@ -521,13 +765,13 @@ static void add_mac_mobility_to_attr(u_int32_t seq_num, struct attr *attr)
 /* Install EVPN route into zebra. */
 static int evpn_zebra_install(struct bgp *bgp, struct bgpevpn *vpn,
                              struct prefix_evpn *p,
-                             struct in_addr remote_vtep_ip, u_char sticky)
+                             struct in_addr remote_vtep_ip, u_char flags)
 {
        int ret;
 
        if (p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE)
                ret = bgp_zebra_send_remote_macip(bgp, vpn, p, remote_vtep_ip,
-                                                 1, sticky);
+                                                 1, flags);
        else
                ret = bgp_zebra_send_remote_vtep(bgp, vpn, p, 1);
 
@@ -598,6 +842,7 @@ static int evpn_route_select_install(struct bgp *bgp, struct bgpevpn *vpn,
        afi_t afi = AFI_L2VPN;
        safi_t safi = SAFI_EVPN;
        int ret = 0;
+       u_char                  flags = 0;
 
        /* Compute the best path. */
        bgp_best_selection(bgp, rn, &bgp->maxpaths[afi][safi], &old_and_new,
@@ -615,11 +860,16 @@ static int evpn_route_select_install(struct bgp *bgp, struct bgpevpn *vpn,
            && !CHECK_FLAG(rn->flags, BGP_NODE_USER_CLEAR)
            && !CHECK_FLAG(old_select->flags, BGP_INFO_ATTR_CHANGED)
            && !bgp->addpath_tx_used[afi][safi]) {
-               if (bgp_zebra_has_route_changed(rn, old_select))
+               if (bgp_zebra_has_route_changed(rn, old_select)) {
+                       if (old_select->attr->sticky)
+                               SET_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY);
+                       if (old_select->attr->default_gw)
+                               SET_FLAG(flags, ZEBRA_MACIP_TYPE_GW);
                        ret = evpn_zebra_install(bgp, vpn,
                                                 (struct prefix_evpn *)&rn->p,
                                                 old_select->attr->nexthop,
-                                                old_select->attr->sticky);
+                                                flags);
+               }
                UNSET_FLAG(old_select->flags, BGP_INFO_MULTIPATH_CHG);
                bgp_zebra_clear_route_change_flags(rn);
                return ret;
@@ -644,9 +894,14 @@ static int evpn_route_select_install(struct bgp *bgp, struct bgpevpn *vpn,
 
        if (new_select && new_select->type == ZEBRA_ROUTE_BGP
            && new_select->sub_type == BGP_ROUTE_NORMAL) {
+               flags = 0;
+               if (new_select->attr->sticky)
+                       SET_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY);
+               if (new_select->attr->default_gw)
+                       SET_FLAG(flags, ZEBRA_MACIP_TYPE_GW);
                ret = evpn_zebra_install(bgp, vpn, (struct prefix_evpn *)&rn->p,
                                         new_select->attr->nexthop,
-                                        new_select->attr->sticky);
+                                        flags);
                /* If an old best existed and it was a "local" route, the only
                 * reason
                 * it would be supplanted is due to MAC mobility procedures. So,
@@ -676,6 +931,28 @@ static int evpn_route_select_install(struct bgp *bgp, struct bgpevpn *vpn,
        return ret;
 }
 
+/*
+ * Return true if the local ri for this rn is of type gateway mac
+ */
+static int evpn_route_is_def_gw(struct bgp *bgp, struct bgp_node *rn)
+{
+       struct bgp_info         *tmp_ri = NULL;
+       struct bgp_info         *local_ri = NULL;
+
+       local_ri = NULL;
+       for (tmp_ri = rn->info; tmp_ri; tmp_ri = tmp_ri->next) {
+               if (tmp_ri->peer == bgp->peer_self
+                   && tmp_ri->type == ZEBRA_ROUTE_BGP
+                   && tmp_ri->sub_type == BGP_ROUTE_STATIC)
+                       local_ri = tmp_ri;
+       }
+
+       if (!local_ri)
+               return 0;
+
+       return local_ri->attr->default_gw;
+}
+
 
 /*
  * Return true if the local ri for this rn has sticky set
@@ -699,6 +976,133 @@ static int evpn_route_is_sticky(struct bgp *bgp, struct bgp_node *rn)
        return local_ri->attr->sticky;
 }
 
+static int update_evpn_type5_route_entry(struct bgp *bgp_def,
+                                        struct bgp *bgp_vrf, afi_t afi,
+                                        safi_t safi, struct bgp_node *rn,
+                                        struct attr *attr, int *route_changed)
+{
+       struct attr *attr_new = NULL;
+       struct bgp_info *ri = NULL;
+       mpls_label_t label = MPLS_INVALID_LABEL;
+       struct bgp_info *local_ri = NULL;
+       struct bgp_info *tmp_ri = NULL;
+
+       *route_changed = 0;
+       /* locate the local route entry if any */
+       for (tmp_ri = rn->info; tmp_ri; tmp_ri = tmp_ri->next) {
+               if (tmp_ri->peer == bgp_def->peer_self
+                   && tmp_ri->type == ZEBRA_ROUTE_BGP
+                   && tmp_ri->sub_type == BGP_ROUTE_STATIC)
+                       local_ri = tmp_ri;
+       }
+
+       /* create a new route entry if one doesnt exist.
+          Otherwise see if route attr has changed
+        */
+       if (!local_ri) {
+
+               /* route has changed as this is the first entry */
+               *route_changed = 1;
+
+               /* Add (or update) attribute to hash. */
+               attr_new = bgp_attr_intern(attr);
+
+               /* create the route info from attribute */
+               ri = info_make(ZEBRA_ROUTE_BGP, BGP_ROUTE_STATIC, 0,
+                              bgp_def->peer_self, attr_new, rn);
+               SET_FLAG(ri->flags, BGP_INFO_VALID);
+
+               /* Type-5 routes advertise the L3-VNI */
+               bgp_info_extra_get(ri);
+               vni2label(bgp_vrf->l3vni, &label);
+               memcpy(&ri->extra->label, &label, sizeof(label));
+               ri->extra->num_labels = 1;
+
+               /* add the route entry to route node*/
+               bgp_info_add(rn, ri);
+       } else {
+
+               tmp_ri = local_ri;
+               if (!attrhash_cmp(tmp_ri->attr, attr)) {
+
+                       /* attribute changed */
+                       *route_changed = 1;
+
+                       /* The attribute has changed. */
+                       /* Add (or update) attribute to hash. */
+                       attr_new = bgp_attr_intern(attr);
+                       bgp_info_set_flag(rn, tmp_ri, BGP_INFO_ATTR_CHANGED);
+
+                       /* Restore route, if needed. */
+                       if (CHECK_FLAG(tmp_ri->flags, BGP_INFO_REMOVED))
+                               bgp_info_restore(rn, tmp_ri);
+
+                       /* Unintern existing, set to new. */
+                       bgp_attr_unintern(&tmp_ri->attr);
+                       tmp_ri->attr = attr_new;
+                       tmp_ri->uptime = bgp_clock();
+               }
+       }
+       return 0;
+}
+
+/* update evpn type-5 route entry */
+static int update_evpn_type5_route(struct bgp *bgp_vrf,
+                                  struct prefix_evpn *evp,
+                                  struct attr* src_attr)
+{
+       afi_t afi = AFI_L2VPN;
+       safi_t safi = SAFI_EVPN;
+       struct attr attr;
+       struct bgp_node *rn = NULL;
+       struct bgp *bgp_def = NULL;
+       int route_changed = 0;
+
+       bgp_def = bgp_get_default();
+       if (!bgp_def)
+               return 0;
+
+       /* Build path attribute for this route - use the source attr, if
+        * present, else treat as locally originated.
+        */
+       if (src_attr)
+               bgp_attr_dup(&attr, src_attr);
+       else {
+               memset(&attr, 0, sizeof(struct attr));
+               bgp_attr_default_set(&attr, BGP_ORIGIN_IGP);
+       }
+       /* Set nexthop to ourselves and fill in the Router MAC. */
+       attr.nexthop = bgp_vrf->originator_ip;
+       attr.mp_nexthop_global_in = bgp_vrf->originator_ip;
+       attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4;
+       memcpy(&attr.rmac, &bgp_vrf->rmac, sizeof(struct ethaddr));
+
+       /* Setup RT and encap extended community */
+       build_evpn_type5_route_extcomm(bgp_vrf, &attr);
+
+       /* get the route node in global table */
+       rn = bgp_afi_node_get(bgp_def->rib[afi][safi], afi, safi,
+                             (struct prefix *)evp,
+                             &bgp_vrf->vrf_prd);
+       assert(rn);
+
+       /* create or update the route entry within the route node */
+       update_evpn_type5_route_entry(bgp_def, bgp_vrf,
+                                     afi, safi,
+                                     rn, &attr, &route_changed);
+
+       /* schedule for processing and unlock node */
+       if (route_changed) {
+               bgp_process(bgp_def, rn, afi, safi);
+               bgp_unlock_node(rn);
+       }
+
+       /* uninten temporary */
+       if (!src_attr)
+               aspath_unintern(&attr.aspath);
+       return 0;
+}
+
 /*
  * Create or update EVPN route entry. This could be in the VNI route table
  * or the global route table.
@@ -711,11 +1115,15 @@ static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
        struct bgp_info *tmp_ri;
        struct bgp_info *local_ri, *remote_ri;
        struct attr *attr_new;
-       mpls_label_t label = MPLS_INVALID_LABEL;
+       mpls_label_t label[BGP_MAX_LABELS];
+       u_int32_t num_labels = 1;
        int route_change = 1;
        u_char sticky = 0;
+       struct prefix_evpn *evp;
 
        *ri = NULL;
+       evp = (struct prefix_evpn *)&rn->p;
+       memset(&label, 0, sizeof(label));
 
        /* See if this is an update of an existing route, or a new add. Also,
         * identify if already known from remote, and if so, the one with the
@@ -757,7 +1165,7 @@ static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
                 * SVI) advertised in EVPN.
                 * This will ensure that local routes are preferred for g/w macs
                 */
-               if (remote_ri && !CHECK_FLAG(flags, ZEBRA_MAC_TYPE_GW)) {
+               if (remote_ri && !CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_GW)) {
                        u_int32_t cur_seqnum;
 
                        /* Add MM extended community to route. */
@@ -780,9 +1188,20 @@ static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
                bgp_info_extra_get(tmp_ri);
 
                /* The VNI goes into the 'label' field of the route */
-               vni2label(vpn->vni, &label);
+               vni2label(vpn->vni, &label[0]);
+               /* Type-2 routes may carry a second VNI - the L3-VNI */
+               if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) {
+                       vni_t l3vni;
+
+                       l3vni = bgpevpn_get_l3vni(vpn);
+                       if (l3vni) {
+                               vni2label(l3vni, &label[1]);
+                               num_labels++;
+                       }
+               }
 
-               memcpy(&tmp_ri->extra->label, &label, BGP_LABEL_BYTES);
+               memcpy(&tmp_ri->extra->label, label, sizeof(label));
+               tmp_ri->extra->num_labels = num_labels;
                bgp_info_add(rn, tmp_ri);
        } else {
                tmp_ri = local_ri;
@@ -833,10 +1252,16 @@ static int update_evpn_route(struct bgp *bgp, struct bgpevpn *vpn,
        attr.nexthop = vpn->originator_ip;
        attr.mp_nexthop_global_in = vpn->originator_ip;
        attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4;
-       attr.sticky = CHECK_FLAG(flags, ZEBRA_MAC_TYPE_STICKY) ? 1 : 0;
+       attr.sticky = CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY) ? 1 : 0;
+       attr.default_gw = CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_GW) ? 1 : 0;
+       attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_PMSI_TUNNEL);
+       bgpevpn_get_rmac(vpn, &attr.rmac);
+       vni2label(vpn->vni, &(attr.label));
 
        /* Set up RT and ENCAP extended community. */
-       build_evpn_route_extcomm(vpn, &attr);
+       build_evpn_route_extcomm(vpn, &attr,
+                                IS_EVPN_PREFIX_IPADDR_V4(p) ?
+                                       AFI_IP : AFI_IP6);
 
        /* First, create (or fetch) route node within the VNI. */
        /* NOTE: There is no RD here. */
@@ -878,6 +1303,58 @@ static int update_evpn_route(struct bgp *bgp, struct bgpevpn *vpn,
        return 0;
 }
 
+/* Delete EVPN type5 route entry from global table */
+static void delete_evpn_type5_route_entry(struct bgp *bgp_def,
+                                         struct bgp *bgp_vrf,
+                                         afi_t afi, safi_t safi,
+                                         struct bgp_node *rn,
+                                         struct bgp_info **ri)
+{
+       struct bgp_info *tmp_ri = NULL;
+
+       *ri = NULL;
+
+       /* find the matching route entry */
+       for (tmp_ri = rn->info; tmp_ri; tmp_ri = tmp_ri->next)
+               if (tmp_ri->peer == bgp_def->peer_self
+                   && tmp_ri->type == ZEBRA_ROUTE_BGP
+                   && tmp_ri->sub_type == BGP_ROUTE_STATIC)
+                       break;
+
+       *ri = tmp_ri;
+
+       /* Mark route for delete. */
+       if (tmp_ri)
+               bgp_info_delete(rn, tmp_ri);
+}
+
+/* Delete EVPN type5 route */
+static int delete_evpn_type5_route(struct bgp *bgp_vrf,
+                                  struct prefix_evpn *evp)
+{
+       afi_t afi = AFI_L2VPN;
+       safi_t safi = SAFI_EVPN;
+       struct bgp_node *rn = NULL;
+       struct bgp_info *ri = NULL;
+       struct bgp *bgp_def = NULL; /* default bgp instance */
+
+       bgp_def = bgp_get_default();
+       if (!bgp_def)
+               return 0;
+
+       /* locate the global route entry for this type-5 prefix */
+       rn = bgp_afi_node_lookup(bgp_def->rib[afi][safi], afi, safi,
+                                (struct prefix *)evp, &bgp_vrf->vrf_prd);
+       if (!rn)
+               return 0;
+
+       delete_evpn_type5_route_entry(bgp_def, bgp_vrf, afi, safi, rn, &ri);
+       if (ri)
+               bgp_process(bgp_def, rn, afi, safi);
+       bgp_unlock_node(rn);
+       return 0;
+}
+
 /*
  * Delete EVPN route entry. This could be in the VNI route table
  * or the global route table.
@@ -965,29 +1442,66 @@ static int update_all_type2_routes(struct bgp *bgp, struct bgpevpn *vpn)
        struct bgp_info *ri;
        struct attr attr;
        struct attr attr_sticky;
+       struct attr attr_def_gw;
+       struct attr attr_ip6;
+       struct attr attr_sticky_ip6;
+       struct attr attr_def_gw_ip6;
        struct attr *attr_new;
 
        afi = AFI_L2VPN;
        safi = SAFI_EVPN;
        memset(&attr, 0, sizeof(struct attr));
        memset(&attr_sticky, 0, sizeof(struct attr));
+       memset(&attr_def_gw, 0, sizeof(struct attr));
+       memset(&attr_ip6, 0, sizeof(struct attr));
+       memset(&attr_sticky_ip6, 0, sizeof(struct attr));
+       memset(&attr_def_gw_ip6, 0, sizeof(struct attr));
 
        /* Build path-attribute - all type-2 routes for this VNI will share the
         * same path attribute.
         */
        bgp_attr_default_set(&attr, BGP_ORIGIN_IGP);
        bgp_attr_default_set(&attr_sticky, BGP_ORIGIN_IGP);
+       bgp_attr_default_set(&attr_def_gw, BGP_ORIGIN_IGP);
        attr.nexthop = vpn->originator_ip;
        attr.mp_nexthop_global_in = vpn->originator_ip;
        attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4;
+       bgpevpn_get_rmac(vpn, &attr.rmac);
        attr_sticky.nexthop = vpn->originator_ip;
        attr_sticky.mp_nexthop_global_in = vpn->originator_ip;
        attr_sticky.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4;
        attr_sticky.sticky = 1;
+       bgpevpn_get_rmac(vpn, &attr_sticky.rmac);
+       attr_def_gw.nexthop = vpn->originator_ip;
+       attr_def_gw.mp_nexthop_global_in = vpn->originator_ip;
+       attr_def_gw.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4;
+       attr_def_gw.default_gw = 1;
+       bgpevpn_get_rmac(vpn, &attr_def_gw.rmac);
+       bgp_attr_default_set(&attr_ip6, BGP_ORIGIN_IGP);
+       bgp_attr_default_set(&attr_sticky_ip6, BGP_ORIGIN_IGP);
+       bgp_attr_default_set(&attr_def_gw_ip6, BGP_ORIGIN_IGP);
+       attr_ip6.nexthop = vpn->originator_ip;
+       attr_ip6.mp_nexthop_global_in = vpn->originator_ip;
+       attr_ip6.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4;
+       bgpevpn_get_rmac(vpn, &attr_ip6.rmac);
+       attr_sticky_ip6.nexthop = vpn->originator_ip;
+       attr_sticky_ip6.mp_nexthop_global_in = vpn->originator_ip;
+       attr_sticky_ip6.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4;
+       attr_sticky_ip6.sticky = 1;
+       bgpevpn_get_rmac(vpn, &attr_sticky_ip6.rmac);
+       attr_def_gw_ip6.nexthop = vpn->originator_ip;
+       attr_def_gw_ip6.mp_nexthop_global_in = vpn->originator_ip;
+       attr_def_gw_ip6.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4;
+       attr_def_gw_ip6.default_gw = 1;
+       bgpevpn_get_rmac(vpn, &attr_def_gw_ip6.rmac);
 
        /* Set up RT, ENCAP and sticky MAC extended community. */
-       build_evpn_route_extcomm(vpn, &attr);
-       build_evpn_route_extcomm(vpn, &attr_sticky);
+       build_evpn_route_extcomm(vpn, &attr, AFI_IP);
+       build_evpn_route_extcomm(vpn, &attr_sticky, AFI_IP);
+       build_evpn_route_extcomm(vpn, &attr_def_gw, AFI_IP);
+       build_evpn_route_extcomm(vpn, &attr_ip6, AFI_IP6);
+       build_evpn_route_extcomm(vpn, &attr_sticky_ip6, AFI_IP6);
+       build_evpn_route_extcomm(vpn, &attr_def_gw_ip6, AFI_IP);
 
        /* Walk this VNI's route table and update local type-2 routes. For any
         * routes updated, update corresponding entry in the global table too.
@@ -1001,12 +1515,32 @@ static int update_all_type2_routes(struct bgp *bgp, struct bgpevpn *vpn)
                if (evp->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE)
                        continue;
 
-               if (evpn_route_is_sticky(bgp, rn))
-                       update_evpn_route_entry(bgp, vpn, afi, safi, rn,
-                                               &attr_sticky, 0, 1, &ri, 0);
-               else
-                       update_evpn_route_entry(bgp, vpn, afi, safi, rn, &attr,
-                                               0, 1, &ri, 0);
+               if (IS_EVPN_PREFIX_IPADDR_V4(evp)) {
+                       if (evpn_route_is_sticky(bgp, rn))
+                               update_evpn_route_entry(bgp, vpn, afi, safi, rn,
+                                                       &attr_sticky, 0, 1,
+                                                       &ri, 0);
+                       else if (evpn_route_is_def_gw(bgp, rn))
+                               update_evpn_route_entry(bgp, vpn, afi, safi, rn,
+                                                       &attr_def_gw, 0, 1,
+                                                       &ri, 0);
+                       else
+                               update_evpn_route_entry(bgp, vpn, afi, safi, rn,
+                                                       &attr, 0, 1, &ri, 0);
+               } else {
+                       if (evpn_route_is_sticky(bgp, rn))
+                               update_evpn_route_entry(bgp, vpn, afi, safi, rn,
+                                                       &attr_sticky_ip6, 0, 1,
+                                                       &ri, 0);
+                       else if (evpn_route_is_def_gw(bgp, rn))
+                               update_evpn_route_entry(bgp, vpn, afi, safi, rn,
+                                                       &attr_def_gw_ip6, 0, 1,
+                                                       &ri, 0);
+                       else
+                               update_evpn_route_entry(bgp, vpn, afi, safi, rn,
+                                                       &attr_ip6, 0, 1,
+                                                       &ri, 0);
+               }
 
                /* If a local route exists for this prefix, we need to update
                 * the global routing table too.
@@ -1036,7 +1570,11 @@ static int update_all_type2_routes(struct bgp *bgp, struct bgpevpn *vpn)
 
        /* Unintern temporary. */
        aspath_unintern(&attr.aspath);
+       aspath_unintern(&attr_ip6.aspath);
        aspath_unintern(&attr_sticky.aspath);
+       aspath_unintern(&attr_sticky_ip6.aspath);
+       aspath_unintern(&attr_def_gw.aspath);
+       aspath_unintern(&attr_def_gw_ip6.aspath);
 
        return 0;
 }
@@ -1220,18 +1758,114 @@ static int handle_tunnel_ip_change(struct bgp *bgp, struct bgpevpn *vpn,
 }
 
 /*
- * Install route entry into the VNI routing table and invoke route selection.
+ * Install route entry into the VRF routing table and invoke route selection.
  */
-static int install_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
-                                   struct prefix_evpn *p,
-                                   struct bgp_info *parent_ri)
+static int install_evpn_route_entry_in_vrf(struct bgp *bgp_vrf,
+                                          struct prefix_evpn *evp,
+                                          struct bgp_info *parent_ri)
 {
        struct bgp_node *rn;
        struct bgp_info *ri;
        struct attr *attr_new;
-       int ret;
-
-       /* Create (or fetch) route within the VNI. */
+       int ret = 0;
+       struct prefix p;
+       struct prefix *pp = &p;
+       afi_t afi = 0;
+       safi_t safi = 0;
+       char buf[PREFIX_STRLEN];
+       char buf1[PREFIX_STRLEN];
+
+       memset(pp, 0, sizeof(struct prefix));
+       if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE)
+               ip_prefix_from_type2_prefix(evp, pp);
+       else if (evp->prefix.route_type == BGP_EVPN_IP_PREFIX_ROUTE)
+               ip_prefix_from_type5_prefix(evp, pp);
+
+       if (bgp_debug_zebra(NULL)) {
+               zlog_debug("installing evpn prefix %s as ip prefix %s in vrf %s",
+                          prefix2str(evp, buf, sizeof(buf)),
+                          prefix2str(pp, buf1, sizeof(buf)),
+                          vrf_id_to_name(bgp_vrf->vrf_id));
+       }
+
+       /* Create (or fetch) route within the VRF. */
+       /* NOTE: There is no RD here. */
+       if (IS_EVPN_PREFIX_IPADDR_V4(evp)) {
+               afi = AFI_IP;
+               safi = SAFI_UNICAST;
+               rn = bgp_node_get(bgp_vrf->rib[afi][safi], pp);
+       } else if (IS_EVPN_PREFIX_IPADDR_V6(evp)) {
+               afi = AFI_IP6;
+               safi = SAFI_UNICAST;
+               rn = bgp_node_get(bgp_vrf->rib[afi][safi], pp);
+       } else
+               return 0;
+
+       /* Check if route entry is already present. */
+       for (ri = rn->info; ri; ri = ri->next)
+               if (ri->extra
+                   && (struct bgp_info *)ri->extra->parent == parent_ri)
+                       break;
+
+       if (!ri) {
+               /* Add (or update) attribute to hash. */
+               attr_new = bgp_attr_intern(parent_ri->attr);
+
+               /* Create new route with its attribute. */
+               ri = info_make(parent_ri->type, parent_ri->sub_type, 0,
+                              parent_ri->peer, attr_new, rn);
+               SET_FLAG(ri->flags, BGP_INFO_VALID);
+               bgp_info_extra_get(ri);
+               ri->extra->parent = parent_ri;
+               if (parent_ri->extra) {
+                       memcpy(&ri->extra->label, &parent_ri->extra->label,
+                              sizeof(ri->extra->label));
+                       ri->extra->num_labels = parent_ri->extra->num_labels;
+               }
+               bgp_info_add(rn, ri);
+       } else {
+               if (attrhash_cmp(ri->attr, parent_ri->attr)
+                   && !CHECK_FLAG(ri->flags, BGP_INFO_REMOVED)) {
+                       bgp_unlock_node(rn);
+                       return 0;
+               }
+               /* The attribute has changed. */
+               /* Add (or update) attribute to hash. */
+               attr_new = bgp_attr_intern(parent_ri->attr);
+
+               /* Restore route, if needed. */
+               if (CHECK_FLAG(ri->flags, BGP_INFO_REMOVED))
+                       bgp_info_restore(rn, ri);
+
+               /* Mark if nexthop has changed. */
+               if (!IPV4_ADDR_SAME(&ri->attr->nexthop, &attr_new->nexthop))
+                       SET_FLAG(ri->flags, BGP_INFO_IGP_CHANGED);
+
+               /* Unintern existing, set to new. */
+               bgp_attr_unintern(&ri->attr);
+               ri->attr = attr_new;
+               ri->uptime = bgp_clock();
+       }
+
+       /* Perform route selection and update zebra, if required. */
+       bgp_process(bgp_vrf, rn, afi, safi);
+
+       return ret;
+}
+
+/*
+ * Install route entry into the VNI routing table and invoke route selection.
+ */
+static int install_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
+                                   struct prefix_evpn *p,
+                                   struct bgp_info *parent_ri)
+{
+       struct bgp_node *rn;
+       struct bgp_info *ri;
+       struct attr *attr_new;
+       int ret;
+
+       /* Create (or fetch) route within the VNI. */
        /* NOTE: There is no RD here. */
        rn = bgp_node_get(vpn->route_table, (struct prefix *)p);
 
@@ -1251,9 +1885,11 @@ static int install_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
                SET_FLAG(ri->flags, BGP_INFO_VALID);
                bgp_info_extra_get(ri);
                ri->extra->parent = parent_ri;
-               if (parent_ri->extra)
+               if (parent_ri->extra) {
                        memcpy(&ri->extra->label, &parent_ri->extra->label,
-                              BGP_LABEL_BYTES);
+                              sizeof(ri->extra->label));
+                       ri->extra->num_labels = parent_ri->extra->num_labels;
+               }
                bgp_info_add(rn, ri);
        } else {
                if (attrhash_cmp(ri->attr, parent_ri->attr)
@@ -1285,6 +1921,73 @@ static int install_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
        return ret;
 }
 
+/*
+ * Uninstall route entry from the VRF routing table and send message
+ * to zebra, if appropriate.
+ */
+static int uninstall_evpn_route_entry_in_vrf(struct bgp *bgp_vrf,
+                                            struct prefix_evpn *evp,
+                                            struct bgp_info *parent_ri)
+{
+       struct bgp_node *rn;
+       struct bgp_info *ri;
+       int ret = 0;
+       struct prefix p;
+       struct prefix *pp = &p;
+       afi_t afi = 0;
+       safi_t safi = 0;
+       char buf[PREFIX_STRLEN];
+       char buf1[PREFIX_STRLEN];
+
+       memset(pp, 0, sizeof(struct prefix));
+       if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE)
+               ip_prefix_from_type2_prefix(evp, pp);
+       else if (evp->prefix.route_type == BGP_EVPN_IP_PREFIX_ROUTE)
+               ip_prefix_from_type5_prefix(evp, pp);
+
+       if (bgp_debug_zebra(NULL)) {
+               zlog_debug("uninstalling evpn prefix %s as ip prefix %s in vrf %s",
+                          prefix2str(evp, buf, sizeof(buf)),
+                          prefix2str(pp, buf1, sizeof(buf)),
+                          vrf_id_to_name(bgp_vrf->vrf_id));
+       }
+
+       /* Locate route within the VRF. */
+       /* NOTE: There is no RD here. */
+       if (IS_EVPN_PREFIX_IPADDR_V4(evp)) {
+               afi = AFI_IP;
+               safi = SAFI_UNICAST;
+               rn = bgp_node_lookup(bgp_vrf->rib[afi][safi], pp);
+       } else {
+               afi = AFI_IP6;
+               safi = SAFI_UNICAST;
+               rn = bgp_node_lookup(bgp_vrf->rib[afi][safi], pp);
+       }
+
+       if (!rn)
+               return 0;
+
+       /* Find matching route entry. */
+       for (ri = rn->info; ri; ri = ri->next)
+               if (ri->extra
+                   && (struct bgp_info *)ri->extra->parent == parent_ri)
+                       break;
+
+       if (!ri)
+               return 0;
+
+       /* Mark entry for deletion */
+       bgp_info_delete(rn, ri);
+
+       /* Perform route selection and update zebra, if required. */
+       bgp_process(bgp_vrf, rn, afi, safi);
+
+       /* Unlock route node. */
+       bgp_unlock_node(rn);
+
+       return ret;
+}
+
 /*
  * Uninstall route entry from the VNI routing table and send message
  * to zebra, if appropriate.
@@ -1324,6 +2027,73 @@ static int uninstall_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
        return ret;
 }
 
+/*
+ * Given a route entry and a VRF, see if this route entry should be
+ * imported into the VRF i.e., RTs match.
+ */
+static int is_route_matching_for_vrf(struct bgp *bgp_vrf,
+                                    struct bgp_info *ri)
+{
+       struct attr *attr = ri->attr;
+       struct ecommunity *ecom;
+       int i;
+
+       assert(attr);
+       /* Route should have valid RT to be even considered. */
+       if (!(attr->flag & ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES)))
+               return 0;
+
+       ecom = attr->ecommunity;
+       if (!ecom || !ecom->size)
+               return 0;
+
+       /* For each extended community RT, see if it matches this VNI. If any RT
+        * matches, we're done.
+        */
+       for (i = 0; i < ecom->size; i++) {
+               u_char *pnt;
+               u_char type, sub_type;
+               struct ecommunity_val *eval;
+               struct ecommunity_val eval_tmp;
+               struct vrf_irt_node *irt;
+
+               /* Only deal with RTs */
+               pnt = (ecom->val + (i * ECOMMUNITY_SIZE));
+               eval = (struct ecommunity_val *)(ecom->val
+                                                + (i * ECOMMUNITY_SIZE));
+               type = *pnt++;
+               sub_type = *pnt++;
+               if (sub_type != ECOMMUNITY_ROUTE_TARGET)
+                       continue;
+
+               /* See if this RT matches specified VNIs import RTs */
+               irt = lookup_vrf_import_rt(eval);
+               if (irt && irt->vrfs)
+                       if (is_vrf_present_in_irt_vrfs(irt->vrfs, bgp_vrf))
+                               return 1;
+
+               /* Also check for non-exact match. In this, we mask out the AS
+                * and
+                * only check on the local-admin sub-field. This is to
+                * facilitate using
+                * VNI as the RT for EBGP peering too.
+                */
+               irt = NULL;
+               if (type == ECOMMUNITY_ENCODE_AS
+                   || type == ECOMMUNITY_ENCODE_AS4
+                   || type == ECOMMUNITY_ENCODE_IP) {
+                       memcpy(&eval_tmp, eval, ECOMMUNITY_SIZE);
+                       mask_ecom_global_admin(&eval_tmp, eval);
+                       irt = lookup_vrf_import_rt(&eval_tmp);
+               }
+               if (irt && irt->vrfs)
+                       if (is_vrf_present_in_irt_vrfs(irt->vrfs, bgp_vrf))
+                               return 1;
+       }
+
+       return 0;
+}
+
 /*
  * Given a route entry and a VNI, see if this route entry should be
  * imported into the VNI i.e., RTs match.
@@ -1391,6 +2161,88 @@ static int is_route_matching_for_vni(struct bgp *bgp, struct bgpevpn *vpn,
        return 0;
 }
 
+/*
+ * Install or uninstall mac-ip routes are appropriate for this
+ * particular VRF.
+ */
+static int install_uninstall_routes_for_vrf(struct bgp *bgp_vrf,
+                                           int install)
+{
+       afi_t afi;
+       safi_t safi;
+       struct bgp_node *rd_rn, *rn;
+       struct bgp_table *table;
+       struct bgp_info *ri;
+       int ret;
+       char buf[PREFIX_STRLEN];
+       struct bgp *bgp_def = NULL;
+
+       afi = AFI_L2VPN;
+       safi = SAFI_EVPN;
+       bgp_def = bgp_get_default();
+       if (!bgp_def)
+               return -1;
+
+       /* Walk entire global routing table and evaluate routes which could be
+        * imported into this VRF. Note that we need to loop through all global
+        * routes to determine which route matches the import rt on vrf
+        */
+       for (rd_rn = bgp_table_top(bgp_def->rib[afi][safi]); rd_rn;
+            rd_rn = bgp_route_next(rd_rn)) {
+               table = (struct bgp_table *)(rd_rn->info);
+               if (!table)
+                       continue;
+
+               for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) {
+                       struct prefix_evpn *evp = (struct prefix_evpn *)&rn->p;
+
+                       /* if not mac-ip route skip this route */
+                       if (!(evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE ||
+                             evp->prefix.route_type == BGP_EVPN_IP_PREFIX_ROUTE))
+                               continue;
+
+                       /* if not a mac+ip route skip this route */
+                       if (!(IS_EVPN_PREFIX_IPADDR_V4(evp) ||
+                             IS_EVPN_PREFIX_IPADDR_V6(evp)))
+                               continue;
+
+                       for (ri = rn->info; ri; ri = ri->next) {
+                               /* Consider "valid" remote routes applicable for
+                                * this VRF.
+                                */
+                               if (!(CHECK_FLAG(ri->flags, BGP_INFO_VALID)
+                                     && ri->type == ZEBRA_ROUTE_BGP
+                                     && ri->sub_type == BGP_ROUTE_NORMAL))
+                                       continue;
+
+                               if (is_route_matching_for_vrf(bgp_vrf, ri)) {
+                                       if (install)
+                                               ret =
+                                               install_evpn_route_entry_in_vrf(
+                                                       bgp_vrf, evp, ri);
+                                       else
+                                               ret =
+                                               uninstall_evpn_route_entry_in_vrf(
+                                                       bgp_vrf, evp, ri);
+
+                                       if (ret) {
+                                               zlog_err(
+                                                       "Failed to %s EVPN %s route in VRF %s",
+                                                       install ? "install"
+                                                               : "uninstall",
+                                                       prefix2str(evp, buf,
+                                                                  sizeof(buf)),
+                                                       vrf_id_to_name(bgp_vrf->vrf_id));
+                                               return ret;
+                                       }
+                               }
+                       }
+               }
+       }
+
+       return 0;
+}
+
 /*
  * Install or uninstall routes of specified type that are appropriate for this
  * particular VNI.
@@ -1465,6 +2317,15 @@ static int install_uninstall_routes_for_vni(struct bgp *bgp,
        return 0;
 }
 
+/* Install any existing remote routes applicable for this VRF into VRF RIB. This
+ * is invoked upon l3vni-add or l3vni import rt change
+ */
+static int install_routes_for_vrf(struct bgp *bgp_vrf)
+{
+       install_uninstall_routes_for_vrf(bgp_vrf, 1);
+       return 0;
+}
+
 /*
  * Install any existing remote routes applicable for this VNI into its
  * routing table. This is invoked when a VNI becomes "live" or its Import
@@ -1486,6 +2347,13 @@ static int install_routes_for_vni(struct bgp *bgp, struct bgpevpn *vpn)
                                                1);
 }
 
+/* uninstall routes from l3vni vrf. */
+static int uninstall_routes_for_vrf(struct bgp *bgp_vrf)
+{
+       install_uninstall_routes_for_vrf(bgp_vrf, 0);
+       return 0;
+}
+
 /*
  * Uninstall any existing remote routes for this VNI. One scenario in which
  * this is invoked is upon an import RT change.
@@ -1507,6 +2375,51 @@ static int uninstall_routes_for_vni(struct bgp *bgp, struct bgpevpn *vpn)
                                                0);
 }
 
+/*
+ * Install or uninstall route in matching VRFs (list).
+ */
+static int install_uninstall_route_in_vrfs(struct bgp *bgp_def, afi_t afi,
+                                          safi_t safi, struct prefix_evpn *evp,
+                                          struct bgp_info *ri,
+                                          struct list *vrfs, int install)
+{
+       char buf[PREFIX2STR_BUFFER];
+       struct bgp *bgp_vrf;
+       struct listnode *node, *nnode;
+
+       /* Only type-2/type-5 routes go into a VRF */
+       if (!(evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE ||
+             evp->prefix.route_type == BGP_EVPN_IP_PREFIX_ROUTE))
+               return 0;
+
+       /* if it is type-2 route and not a mac+ip route skip this route */
+       if ((evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) &&
+           !(IS_EVPN_PREFIX_IPADDR_V4(evp) || IS_EVPN_PREFIX_IPADDR_V6(evp)))
+               return 0;
+
+       for (ALL_LIST_ELEMENTS(vrfs, node, nnode, bgp_vrf)) {
+               int ret;
+
+               if (install)
+                       ret = install_evpn_route_entry_in_vrf(bgp_vrf,
+                                                             evp, ri);
+               else
+                       ret = uninstall_evpn_route_entry_in_vrf(bgp_vrf,
+                                                               evp, ri);
+
+               if (ret) {
+                       zlog_err("%u: Failed to %s prefix %s in VRF %s",
+                                bgp_def->vrf_id,
+                                install ? "install" : "uninstall",
+                                prefix2str(evp, buf, sizeof(buf)),
+                                vrf_id_to_name(bgp_vrf->vrf_id));
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
 /*
  * Install or uninstall route in matching VNIs (list).
  */
@@ -1557,9 +2470,10 @@ static int install_uninstall_evpn_route(struct bgp *bgp, afi_t afi, safi_t safi,
 
        assert(attr);
 
-       /* Only type-2 and type-3 routes go into a L2 VNI. */
+       /* Only type-2 and type-3 and type-5 are supported currently */
        if (!(evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE
-             || evp->prefix.route_type == BGP_EVPN_IMET_ROUTE))
+             || evp->prefix.route_type == BGP_EVPN_IMET_ROUTE
+             || evp->prefix.route_type == BGP_EVPN_IP_PREFIX_ROUTE))
                return 0;
 
        /* If we don't have Route Target, nothing much to do. */
@@ -1570,15 +2484,16 @@ static int install_uninstall_evpn_route(struct bgp *bgp, afi_t afi, safi_t safi,
        if (!ecom || !ecom->size)
                return -1;
 
-       /* For each extended community RT, see which VNIs match and import
-        * the route into matching VNIs.
+       /* For each extended community RT, see which VNIs/VRFs match and import
+        * the route into matching VNIs/VRFs.
         */
        for (i = 0; i < ecom->size; i++) {
                u_char *pnt;
                u_char type, sub_type;
                struct ecommunity_val *eval;
                struct ecommunity_val eval_tmp;
-               struct irt_node *irt;
+               struct irt_node *irt; /* import rt for l2vni */
+               struct vrf_irt_node *vrf_irt; /* import rt for l3vni */
 
                /* Only deal with RTs */
                pnt = (ecom->val + (i * ECOMMUNITY_SIZE));
@@ -1589,34 +2504,106 @@ static int install_uninstall_evpn_route(struct bgp *bgp, afi_t afi, safi_t safi,
                if (sub_type != ECOMMUNITY_ROUTE_TARGET)
                        continue;
 
-               /* Are we interested in this RT? */
+               /* Import route into matching l2-vnis (type-2/type-3 routes go
+                * into l2vni table)
+                */
                irt = lookup_import_rt(bgp, eval);
                if (irt && irt->vnis)
                        install_uninstall_route_in_vnis(bgp, afi, safi, evp, ri,
                                                        irt->vnis, import);
 
-               /* Also check for non-exact match. In this, we mask out the AS
-                * and
-                * only check on the local-admin sub-field. This is to
-                * facilitate using
+               /* Import route into matching l3-vnis (type-2/type-5 routes go
+                * into l3vni/vrf table)
+                */
+               vrf_irt = lookup_vrf_import_rt(eval);
+               if (vrf_irt && vrf_irt->vrfs)
+                       install_uninstall_route_in_vrfs(bgp, afi, safi, evp, ri,
+                                                       vrf_irt->vrfs, import);
+
+               /* Also check for non-exact match. In this,
+                *  we mask out the AS and
+                * only check on the local-admin sub-field.
+                * This is to facilitate using
                 * VNI as the RT for EBGP peering too.
                 */
                irt = NULL;
+               vrf_irt = NULL;
                if (type == ECOMMUNITY_ENCODE_AS
                    || type == ECOMMUNITY_ENCODE_AS4
                    || type == ECOMMUNITY_ENCODE_IP) {
                        memcpy(&eval_tmp, eval, ECOMMUNITY_SIZE);
                        mask_ecom_global_admin(&eval_tmp, eval);
                        irt = lookup_import_rt(bgp, &eval_tmp);
+                       vrf_irt = lookup_vrf_import_rt(&eval_tmp);
                }
                if (irt && irt->vnis)
                        install_uninstall_route_in_vnis(bgp, afi, safi, evp, ri,
                                                        irt->vnis, import);
+               if (vrf_irt && vrf_irt->vrfs)
+                       install_uninstall_route_in_vrfs(bgp, afi, safi, evp,
+                                                       ri, vrf_irt->vrfs,
+                                                       import);
        }
 
        return 0;
 }
 
+/* delete and withdraw all ipv4 and ipv6 routes in the vrf table as type-5
+ * routes */
+static void delete_withdraw_vrf_routes(struct bgp *bgp_vrf)
+{
+       /* delete all ipv4 routes and withdraw from peers */
+       bgp_evpn_withdraw_type5_routes(bgp_vrf, AFI_IP, SAFI_UNICAST);
+
+       /* delete all ipv6 routes and withdraw from peers */
+       bgp_evpn_withdraw_type5_routes(bgp_vrf, AFI_IP6, SAFI_UNICAST);
+}
+
+/* update and advertise all ipv4 and ipv6 routes in thr vrf table as type-5
+ * routes */
+static void update_advertise_vrf_routes(struct bgp *bgp_vrf)
+{
+       /* update all ipv4 routes */
+       bgp_evpn_advertise_type5_routes(bgp_vrf, AFI_IP, SAFI_UNICAST);
+
+       /* update all ipv6 routes */
+       bgp_evpn_advertise_type5_routes(bgp_vrf, AFI_IP6, SAFI_UNICAST);
+}
+
+/*
+ * update and advertise local routes for a VRF as type-5 routes.
+ * This is invoked upon RD change for a VRF. Note taht the processing is only
+ * done in the global route table using the routes which already exist in the
+ * VRF routing table
+ */
+static void update_router_id_vrf(struct bgp *bgp_vrf)
+{
+       /* skip if the RD is configured */
+       if (is_vrf_rd_configured(bgp_vrf))
+               return;
+
+       /* derive the RD for the VRF based on new router-id */
+       bgp_evpn_derive_auto_rd_for_vrf(bgp_vrf);
+
+       /* update advertise ipv4|ipv6 routes as type-5 routes */
+       update_advertise_vrf_routes(bgp_vrf);
+}
+
+/*
+ * Delete and withdraw all type-5 routes  for the RD corresponding to VRF.
+ * This is invoked upon VRF RD change. The processing is done only from global
+ * table.
+ */
+static void withdraw_router_id_vrf(struct bgp *bgp_vrf)
+{
+       /* skip if the RD is configured */
+       if (is_vrf_rd_configured(bgp_vrf))
+               return;
+
+       /* delete/withdraw ipv4|ipv6 routes as type-5 routes */
+       delete_withdraw_vrf_routes(bgp_vrf);
+}
+
 /*
  * Update and advertise local routes for a VNI. Invoked upon router-id
  * change. Note that the processing is done only on the global route table
@@ -1792,7 +2779,8 @@ static int process_type2_route(struct peer *peer, afi_t afi, safi_t safi,
        struct prefix_evpn p;
        u_char ipaddr_len;
        u_char macaddr_len;
-       mpls_label_t *label_pnt;
+       mpls_label_t label[BGP_MAX_LABELS]; /* holds the VNI(s) as in packet */
+       u_int32_t num_labels = 0;
        int ret;
 
        /* Type-2 route should be either 33, 37 or 49 bytes or an
@@ -1860,19 +2848,31 @@ static int process_type2_route(struct peer *peer, afi_t afi, safi_t safi,
        }
        pfx += ipaddr_len;
 
-       /* Get the VNI (in MPLS label field). */
-       /* Note: We ignore the second VNI, if any. */
-       label_pnt = (mpls_label_t *)pfx;
+       /* Get the VNI(s). Stored as bytes here. */
+       num_labels++;
+       memset(label, 0, sizeof(label));
+       memcpy(&label[0], pfx, BGP_LABEL_BYTES);
+       pfx += BGP_LABEL_BYTES;
+       psize -= (33 + ipaddr_len);
+       /* Do we have a second VNI? */
+       if (psize) {
+               num_labels++;
+               memcpy(&label[1], pfx, BGP_LABEL_BYTES);
+               /*
+                * If in future, we are required to access additional fields,
+                * we MUST increment pfx by BGP_LABEL_BYTES in before reading the next field
+                */
+       }
 
        /* Process the route. */
        if (attr)
                ret = bgp_update(peer, (struct prefix *)&p, addpath_id, attr,
                                 afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL,
-                                &prd, label_pnt, 0, NULL);
+                                &prd, &label[0], num_labels, 0, NULL);
        else
                ret = bgp_withdraw(peer, (struct prefix *)&p, addpath_id, attr,
                                   afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL,
-                                  &prd, label_pnt, NULL);
+                                  &prd, &label[0], num_labels, NULL);
        return ret;
 }
 
@@ -1928,11 +2928,11 @@ static int process_type3_route(struct peer *peer, afi_t afi, safi_t safi,
        if (attr)
                ret = bgp_update(peer, (struct prefix *)&p, addpath_id, attr,
                                 afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL,
-                                &prd, NULL, 0, NULL);
+                                &prd, NULL, 0, 0, NULL);
        else
                ret = bgp_withdraw(peer, (struct prefix *)&p, addpath_id, attr,
                                   afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL,
-                                  &prd, NULL, NULL);
+                                  &prd, NULL, 0, NULL);
        return ret;
 }
 
@@ -1948,7 +2948,7 @@ static int process_type5_route(struct peer *peer, afi_t afi, safi_t safi,
        struct bgp_route_evpn evpn;
        u_char ippfx_len;
        u_int32_t eth_tag;
-       mpls_label_t *label_pnt;
+       mpls_label_t label; /* holds the VNI as in the packet */
        int ret;
 
        /* Type-5 route should be 34 or 58 bytes:
@@ -1971,6 +2971,7 @@ static int process_type5_route(struct peer *peer, afi_t afi, safi_t safi,
        /* Make EVPN prefix. */
        memset(&p, 0, sizeof(struct prefix_evpn));
        p.family = AF_EVPN;
+       p.prefixlen = EVPN_TYPE_5_ROUTE_PREFIXLEN;
        p.prefix.route_type = BGP_EVPN_IP_PREFIX_ROUTE;
 
        /* Additional information outside of prefix - ESI and GW IP */
@@ -2005,33 +3006,39 @@ static int process_type5_route(struct peer *peer, afi_t afi, safi_t safi,
                pfx += 4;
                memcpy(&evpn.gw_ip.ipv4, pfx, 4);
                pfx += 4;
-               p.prefixlen = PREFIX_LEN_ROUTE_TYPE_5_IPV4;
        } else {
                SET_IPADDR_V6(&p.prefix.ip);
                memcpy(&p.prefix.ip.ipaddr_v6, pfx, 16);
                pfx += 16;
                memcpy(&evpn.gw_ip.ipv6, pfx, 16);
                pfx += 16;
-               p.prefixlen = PREFIX_LEN_ROUTE_TYPE_5_IPV6;
        }
 
-       label_pnt = (mpls_label_t *)pfx;
+       /* Get the VNI (in MPLS label field). Stored as bytes here. */
+       memset(&label, 0, sizeof(label));
+       memcpy(&label, pfx, BGP_LABEL_BYTES);
+
+       /*
+        * If in future, we are required to access additional fields,
+        * we MUST increment pfx by BGP_LABEL_BYTES in before reading the next field
+        */
 
        /* Process the route. */
        if (!withdraw)
                ret = bgp_update(peer, (struct prefix *)&p, addpath_id, attr,
                                 afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL,
-                                &prd, label_pnt, 0, &evpn);
+                                &prd, &label, 1, 0, &evpn);
        else
                ret = bgp_withdraw(peer, (struct prefix *)&p, addpath_id, attr,
                                   afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL,
-                                  &prd, label_pnt, &evpn);
+                                  &prd, &label, 1, &evpn);
 
        return ret;
 }
 
 static void evpn_mpattr_encode_type5(struct stream *s, struct prefix *p,
-                                    struct prefix_rd *prd, mpls_label_t *label,
+                                    struct prefix_rd *prd,
+                                    mpls_label_t *label, u_int32_t num_labels,
                                     struct attr *attr)
 {
        int len;
@@ -2043,10 +3050,13 @@ static void evpn_mpattr_encode_type5(struct stream *s, struct prefix *p,
                return;
        p_evpn_p = &(p->u.prefix_evpn);
 
+       /* len denites the total len of IP and GW-IP in the route
+          IP and GW-IP have to be both ipv4 or ipv6
+        */
        if (IS_IPADDR_V4(&p_evpn_p->ip))
-               len = 8; /* ipv4 */
+               len = 8; /* IP and GWIP are both ipv4 */
        else
-               len = 32; /* ipv6 */
+               len = 32; /* IP and GWIP are both ipv6 */
        /* Prefix contains RD, ESI, EthTag, IP length, IP, GWIP and VNI */
        stream_putc(s, 8 + 10 + 4 + 1 + len + 3);
        stream_put(s, prd->val, 8);
@@ -2073,7 +3083,7 @@ static void evpn_mpattr_encode_type5(struct stream *s, struct prefix *p,
                        stream_put(s, &temp, 16);
        }
 
-       if (label)
+       if (num_labels)
                stream_put(s, label, 3);
        else
                stream_put3(s, 0);
@@ -2107,30 +3117,351 @@ static void free_vni_entry(struct hash_backet *backet, struct bgp *bgp)
        bgp_evpn_free(bgp, vpn);
 }
 
+/*
+ * Derive AUTO import RT for BGP VRF - L3VNI
+ */
+static void evpn_auto_rt_import_add_for_vrf(struct bgp *bgp_vrf)
+{
+       struct bgp *bgp_def = NULL;
+
+       form_auto_rt(bgp_vrf, bgp_vrf->l3vni, bgp_vrf->vrf_import_rtl);
+       UNSET_FLAG(bgp_vrf->vrf_flags, BGP_VRF_IMPORT_RT_CFGD);
+
+       /* Map RT to VRF */
+       bgp_def = bgp_get_default();
+       if (!bgp_def)
+               return;
+       bgp_evpn_map_vrf_to_its_rts(bgp_vrf);
+}
+
+/*
+ * Delete AUTO import RT from BGP VRF - L3VNI
+ */
+static void evpn_auto_rt_import_delete_for_vrf(struct bgp *bgp_vrf)
+{
+       evpn_rt_delete_auto(bgp_vrf, bgp_vrf->l3vni, bgp_vrf->vrf_import_rtl);
+}
+
+/*
+ * Derive AUTO export RT for BGP VRF - L3VNI
+ */
+static void evpn_auto_rt_export_add_for_vrf(struct bgp *bgp_vrf)
+{
+       UNSET_FLAG(bgp_vrf->vrf_flags, BGP_VRF_EXPORT_RT_CFGD);
+       form_auto_rt(bgp_vrf, bgp_vrf->l3vni, bgp_vrf->vrf_export_rtl);
+}
+
+/*
+ * Delete AUTO export RT from BGP VRF - L3VNI
+ */
+static void evpn_auto_rt_export_delete_for_vrf(struct bgp *bgp_vrf)
+{
+       evpn_rt_delete_auto(bgp_vrf, bgp_vrf->l3vni, bgp_vrf->vrf_export_rtl);
+}
+
+static void bgp_evpn_handle_export_rt_change_for_vrf(struct bgp *bgp_vrf)
+{
+       struct bgp *bgp_def = NULL;
+       struct listnode *node = NULL;
+       struct bgpevpn *vpn = NULL;
+
+       bgp_def = bgp_get_default();
+       if (!bgp_def)
+               return;
+
+       /* update all type-5 routes */
+       update_advertise_vrf_routes(bgp_vrf);
+
+       /* update all type-2 routes */
+       for (ALL_LIST_ELEMENTS_RO(bgp_vrf->l2vnis, node, vpn))
+               update_routes_for_vni(bgp_def, vpn);
+}
 
 /*
  * Public functions.
  */
 
+/* withdraw type-5 route corresponding to ip prefix */
+void bgp_evpn_withdraw_type5_route(struct bgp *bgp_vrf, struct prefix *p,
+                                  afi_t afi, safi_t safi)
+{
+       int ret = 0;
+       struct prefix_evpn evp;
+       char buf[PREFIX_STRLEN];
+
+       /* NOTE: Check needed as this is called per-route also. */
+       if (!advertise_type5_routes(bgp_vrf, afi))
+               return;
+
+       build_type5_prefix_from_ip_prefix(&evp, p);
+       ret = delete_evpn_type5_route(bgp_vrf, &evp);
+       if (ret) {
+               zlog_err(
+                        "%u failed to delete type-5 route for prefix %s in vrf %s",
+                        bgp_vrf->vrf_id,
+                        prefix2str(p, buf, sizeof(buf)),
+                        vrf_id_to_name(bgp_vrf->vrf_id));
+       }
+}
+
+/* withdraw all type-5 routes for an address family */
+void bgp_evpn_withdraw_type5_routes(struct bgp *bgp_vrf,
+                                   afi_t afi, safi_t safi)
+{
+       struct bgp_table *table = NULL;
+       struct bgp_node *rn = NULL;
+
+       /* Bail out early if we don't have to advertise type-5 routes. */
+       if (!advertise_type5_routes(bgp_vrf, afi))
+               return;
+
+       table = bgp_vrf->rib[afi][safi];
+       for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn))
+               bgp_evpn_withdraw_type5_route(bgp_vrf, &rn->p, afi, safi);
+
+}
+
+/*
+ * Advertise IP prefix as type-5 route. The afi/safi and src_attr passed
+ * to this function correspond to those of the source IP prefix (best
+ * path in the case of the attr. In the case of a local prefix (when we
+ * are advertising local subnets), the src_attr will be NULL.
+ */
+void bgp_evpn_advertise_type5_route(struct bgp *bgp_vrf, struct prefix *p,
+                                   struct attr *src_attr,
+                                   afi_t afi, safi_t safi)
+{
+       int ret = 0;
+       struct prefix_evpn evp;
+       char buf[PREFIX_STRLEN];
+
+       /* NOTE: Check needed as this is called per-route also. */
+       if (!advertise_type5_routes(bgp_vrf, afi))
+               return;
+
+       /* only advertise subnet routes as type-5 */
+       if (is_host_route(p))
+               return;
+
+       build_type5_prefix_from_ip_prefix(&evp, p);
+       ret = update_evpn_type5_route(bgp_vrf, &evp, src_attr);
+       if (ret)
+               zlog_err(
+                        "%u: Failed to create type-5 route for prefix %s",
+                        bgp_vrf->vrf_id,
+                        prefix2str(p, buf, sizeof(buf)));
+}
+
+/* Inject all prefixes of a particular address-family (currently, IPv4 or
+ * IPv6 unicast) into EVPN as type-5 routes. This is invoked when the
+ * advertisement is enabled.
+ */
+void bgp_evpn_advertise_type5_routes(struct bgp *bgp_vrf,
+                                    afi_t afi, safi_t safi)
+{
+       struct bgp_table *table = NULL;
+       struct bgp_node *rn = NULL;
+       struct bgp_info *ri;
+
+       /* Bail out early if we don't have to advertise type-5 routes. */
+       if (!advertise_type5_routes(bgp_vrf, afi))
+               return;
+
+       table = bgp_vrf->rib[afi][safi];
+       for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) {
+               /* Need to identify the "selected" route entry to use its
+                * attribute.
+                * TODO: Support for AddPath for EVPN.
+                */
+               for (ri = rn->info; ri; ri = ri->next) {
+                       if (CHECK_FLAG(ri->flags, BGP_INFO_SELECTED)) {
+
+                               /* apply the route-map */
+                               if (bgp_vrf->adv_cmd_rmap[afi][safi].map) {
+                                       int ret = 0;
+
+                                       ret =
+                                               route_map_apply(
+                                                       bgp_vrf->adv_cmd_rmap[afi][safi].map,
+                                                       &rn->p, RMAP_BGP, ri);
+                                       if (ret == RMAP_DENYMATCH)
+                                               continue;
+                               }
+
+                               bgp_evpn_advertise_type5_route(bgp_vrf, &rn->p,
+                                                              ri->attr,
+                                                              afi, safi);
+                               break;
+                       }
+               }
+       }
+}
+
+void evpn_rt_delete_auto(struct bgp *bgp, vni_t vni,
+                               struct list *rtl)
+{
+       struct listnode *node, *nnode, *node_to_del;
+       struct ecommunity *ecom, *ecom_auto;
+       struct ecommunity_val eval;
+
+       encode_route_target_as((bgp->as & 0xFFFF), vni, &eval);
+
+       ecom_auto = ecommunity_new();
+       ecommunity_add_val(ecom_auto, &eval);
+       node_to_del = NULL;
+
+       for (ALL_LIST_ELEMENTS(rtl, node, nnode, ecom)) {
+               if (ecommunity_match(ecom, ecom_auto)) {
+                       ecommunity_free(&ecom);
+                       node_to_del = node;
+               }
+       }
+
+       if (node_to_del)
+               list_delete_node(rtl, node_to_del);
+
+       ecommunity_free(&ecom_auto);
+}
+
+void bgp_evpn_configure_import_rt_for_vrf(struct bgp *bgp_vrf,
+                                         struct ecommunity *ecomadd)
+{
+       /* uninstall routes from vrf */
+       uninstall_routes_for_vrf(bgp_vrf);
+
+       /* Cleanup the RT to VRF mapping */
+       bgp_evpn_unmap_vrf_from_its_rts(bgp_vrf);
+
+       /* Remove auto generated RT */
+       evpn_auto_rt_import_delete_for_vrf(bgp_vrf);
+
+       /* Add the newly configured RT to RT list */
+       listnode_add_sort(bgp_vrf->vrf_import_rtl, ecomadd);
+       SET_FLAG(bgp_vrf->vrf_flags, BGP_VRF_IMPORT_RT_CFGD);
+
+       /* map VRF to its RTs */
+       bgp_evpn_map_vrf_to_its_rts(bgp_vrf);
+
+       /* install routes matching the new VRF */
+       install_routes_for_vrf(bgp_vrf);
+}
+
+void bgp_evpn_unconfigure_import_rt_for_vrf(struct bgp *bgp_vrf,
+                                           struct ecommunity *ecomdel)
+{
+       struct listnode *node = NULL, *nnode = NULL, *node_to_del = NULL;
+       struct ecommunity *ecom = NULL;
+
+       /* uninstall routes from vrf */
+       uninstall_routes_for_vrf(bgp_vrf);
+
+       /* Cleanup the RT to VRF mapping */
+       bgp_evpn_unmap_vrf_from_its_rts(bgp_vrf);
+
+       /* remove the RT from the RT list */
+       for (ALL_LIST_ELEMENTS(bgp_vrf->vrf_import_rtl, node, nnode, ecom)) {
+               if (ecommunity_match(ecom, ecomdel)) {
+                       ecommunity_free(&ecom);
+                       node_to_del = node;
+                       break;
+               }
+       }
+
+       if (node_to_del)
+               list_delete_node(bgp_vrf->vrf_import_rtl, node_to_del);
+
+       /* fallback to auto import rt, if this was the last RT */
+       if (list_isempty(bgp_vrf->vrf_import_rtl)) {
+               UNSET_FLAG(bgp_vrf->vrf_flags, BGP_VRF_IMPORT_RT_CFGD);
+               evpn_auto_rt_import_add_for_vrf(bgp_vrf);
+       }
+
+       /* map VRFs to its RTs */
+       bgp_evpn_map_vrf_to_its_rts(bgp_vrf);
+
+       /* install routes matching this new RT */
+       install_routes_for_vrf(bgp_vrf);
+}
+
+void bgp_evpn_configure_export_rt_for_vrf(struct bgp *bgp_vrf,
+                                         struct ecommunity *ecomadd)
+{
+       /* remove auto-generated RT */
+       evpn_auto_rt_export_delete_for_vrf(bgp_vrf);
+
+       /* Add the new RT to the RT list */
+       listnode_add_sort(bgp_vrf->vrf_export_rtl, ecomadd);
+       SET_FLAG(bgp_vrf->vrf_flags, BGP_VRF_EXPORT_RT_CFGD);
+
+       bgp_evpn_handle_export_rt_change_for_vrf(bgp_vrf);
+
+}
+
+void bgp_evpn_unconfigure_export_rt_for_vrf(struct bgp *bgp_vrf,
+                                           struct ecommunity *ecomdel)
+{
+       struct listnode *node = NULL, *nnode = NULL, *node_to_del = NULL;
+       struct ecommunity *ecom = NULL;
+
+       /* Remove the RT from the RT list */
+       for (ALL_LIST_ELEMENTS(bgp_vrf->vrf_export_rtl, node, nnode, ecom)) {
+               if (ecommunity_match(ecom, ecomdel)) {
+                       ecommunity_free(&ecom);
+                       node_to_del = node;
+                       break;
+               }
+       }
+
+       if (node_to_del)
+               list_delete_node(bgp_vrf->vrf_export_rtl, node_to_del);
+
+       /* fall back to auto-generated RT if this was the last RT */
+       if (bgp_vrf->vrf_export_rtl && list_isempty(bgp_vrf->vrf_export_rtl)) {
+               UNSET_FLAG(bgp_vrf->vrf_flags, BGP_VRF_EXPORT_RT_CFGD);
+               evpn_auto_rt_export_add_for_vrf(bgp_vrf);
+       }
+
+       bgp_evpn_handle_export_rt_change_for_vrf(bgp_vrf);
+}
+
 /*
  * Handle change to BGP router id. This is invoked twice by the change
  * handler, first before the router id has been changed and then after
  * the router id has been changed. The first invocation will result in
- * local routes for all VNIs being deleted and withdrawn and the next
+ * local routes for all VNIs/VRF being deleted and withdrawn and the next
  * will result in the routes being re-advertised.
  */
 void bgp_evpn_handle_router_id_update(struct bgp *bgp, int withdraw)
 {
-       if (withdraw)
+       if (withdraw) {
+
+               /* delete and withdraw all the type-5 routes
+                  stored in the global table for this vrf
+                */
+               withdraw_router_id_vrf(bgp);
+
+               /* delete all the VNI routes (type-2/type-3) routes for all the
+                * L2-VNIs
+                */
                hash_iterate(bgp->vnihash,
                             (void (*)(struct hash_backet *,
                                       void *))withdraw_router_id_vni,
                             bgp);
-       else
+       } else {
+
+               /* advertise all routes in the vrf as type-5 routes with the new
+                * RD
+                */
+               update_router_id_vrf(bgp);
+
+               /* advertise all the VNI routes (type-2/type-3) routes with the
+                * new RD
+                */
                hash_iterate(bgp->vnihash,
                             (void (*)(struct hash_backet *,
                                       void *))update_router_id_vni,
                             bgp);
+       }
 }
 
 /*
@@ -2141,6 +3472,15 @@ int bgp_evpn_handle_export_rt_change(struct bgp *bgp, struct bgpevpn *vpn)
        return update_routes_for_vni(bgp, vpn);
 }
 
+void bgp_evpn_handle_vrf_rd_change(struct bgp *bgp_vrf,
+                                  int withdraw)
+{
+       if (withdraw)
+               delete_withdraw_vrf_routes(bgp_vrf);
+       else
+               update_advertise_vrf_routes(bgp_vrf);
+}
+
 /*
  * Handle change to RD. This is invoked twice by the change handler,
  * first before the RD has been changed and then after the RD has
@@ -2175,14 +3515,19 @@ int bgp_evpn_uninstall_routes(struct bgp *bgp, struct bgpevpn *vpn)
 }
 
 /*
- * Function to display "tag" in route as a VNI.
+ * TODO: Hardcoded for a maximum of 2 VNIs right now
  */
-char *bgp_evpn_label2str(mpls_label_t *label, char *buf, int len)
+char *bgp_evpn_label2str(mpls_label_t *label, u_int32_t num_labels,
+                        char *buf, int len)
 {
-       vni_t vni;
-
-       vni = label2vni(label);
-       snprintf(buf, len, "%u", vni);
+       vni_t vni1, vni2;
+
+       vni1 = label2vni(label);
+       if (num_labels == 2) {
+               vni2 = label2vni(label+1);
+               snprintf(buf, len, "%u/%u", vni1, vni2);
+       } else
+               snprintf(buf, len, "%u", vni1);
        return buf;
 }
 
@@ -2285,6 +3630,13 @@ char *bgp_evpn_route2str(struct prefix_evpn *p, char *buf, int len)
                                 inet_ntop(family, &p->prefix.ip.ip.addr, buf2,
                                           PREFIX2STR_BUFFER));
                }
+       } else if (p->prefix.route_type == BGP_EVPN_IP_PREFIX_ROUTE) {
+               snprintf(buf, len, "[%d]:[0]:[0]:[%d]:[%s]",
+                        p->prefix.route_type,
+                        p->prefix.ip_prefix_length,
+                        IS_EVPN_PREFIX_IPADDR_V4(p) ?
+                               inet_ntoa(p->prefix.ip.ipaddr_v4) :
+                               inet6_ntoa(p->prefix.ip.ipaddr_v6));
        } else {
                /* For EVPN route types not supported yet. */
                snprintf(buf, len, "(unsupported route type %d)",
@@ -2298,12 +3650,13 @@ char *bgp_evpn_route2str(struct prefix_evpn *p, char *buf, int len)
  * Encode EVPN prefix in Update (MP_REACH)
  */
 void bgp_evpn_encode_prefix(struct stream *s, struct prefix *p,
-                           struct prefix_rd *prd, mpls_label_t *label,
+                           struct prefix_rd *prd,
+                           mpls_label_t *label, u_int32_t num_labels,
                            struct attr *attr, int addpath_encode,
                            u_int32_t addpath_tx_id)
 {
        struct prefix_evpn *evp = (struct prefix_evpn *)p;
-       int ipa_len = 0;
+       int len, ipa_len = 0;
 
        if (addpath_encode)
                stream_putl(s, addpath_tx_id);
@@ -2317,18 +3670,24 @@ void bgp_evpn_encode_prefix(struct stream *s, struct prefix *p,
                        ipa_len = IPV4_MAX_BYTELEN;
                else if (IS_EVPN_PREFIX_IPADDR_V6(evp))
                        ipa_len = IPV6_MAX_BYTELEN;
-               stream_putc(s, 33 + ipa_len);       // 1 VNI
+               /* RD, ESI, EthTag, MAC+len, IP len, [IP], 1 VNI */
+               len = 8 + 10 + 4 + 1 + 6 + 1 + ipa_len + 3;
+               if (ipa_len && num_labels > 1) /* There are 2 VNIs */
+                       len += 3;
+               stream_putc(s, len);
                stream_put(s, prd->val, 8);      /* RD */
                stream_put(s, 0, 10);               /* ESI */
                stream_putl(s, 0);                  /* Ethernet Tag ID */
                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)
-                       stream_put(s, &evp->prefix.ip.ip.addr,
-                                  ipa_len); /* IP */
-               stream_put(s, label,
-                          BGP_LABEL_BYTES); /* VNI is contained in 'tag' */
+               if (ipa_len) /* IP */
+                       stream_put(s, &evp->prefix.ip.ip.addr, ipa_len);
+               /* 1st label is the L2 VNI */
+               stream_put(s, label, BGP_LABEL_BYTES);
+               /* Include 2nd label (L3 VNI) if advertising MAC+IP */
+               if (ipa_len && num_labels > 1)
+                       stream_put(s, label+1, BGP_LABEL_BYTES);
                break;
 
        case BGP_EVPN_IMET_ROUTE:
@@ -2342,7 +3701,7 @@ void bgp_evpn_encode_prefix(struct stream *s, struct prefix *p,
 
        case BGP_EVPN_IP_PREFIX_ROUTE:
                /* TODO: AddPath support. */
-               evpn_mpattr_encode_type5(s, p, prd, label, attr);
+               evpn_mpattr_encode_type5(s, p, prd, label, num_labels, attr);
                break;
 
        default:
@@ -2453,6 +3812,65 @@ int bgp_nlri_parse_evpn(struct peer *peer, struct attr *attr,
        return 0;
 }
 
+/*
+ * Map the RTs (configured or automatically derived) of a VRF to the VRF.
+ * The mapping will be used during route processing.
+ * bgp_def: default bgp instance
+ * bgp_vrf: specific bgp vrf instance on which RT is configured
+ */
+void bgp_evpn_map_vrf_to_its_rts(struct bgp *bgp_vrf)
+{
+       int i = 0;
+       struct ecommunity_val *eval = NULL;
+       struct listnode *node = NULL, *nnode = NULL;
+       struct ecommunity *ecom = NULL;
+
+       for (ALL_LIST_ELEMENTS(bgp_vrf->vrf_import_rtl, node, nnode, ecom)) {
+               for (i = 0; i < ecom->size; i++) {
+                       eval = (struct ecommunity_val *)(ecom->val
+                                                        + (i
+                                                           * ECOMMUNITY_SIZE));
+                       map_vrf_to_rt(bgp_vrf, eval);
+               }
+       }
+}
+
+/*
+ * Unmap the RTs (configured or automatically derived) of a VRF from the VRF.
+ */
+void bgp_evpn_unmap_vrf_from_its_rts(struct bgp *bgp_vrf)
+{
+       int i;
+       struct ecommunity_val *eval;
+       struct listnode *node, *nnode;
+       struct ecommunity *ecom;
+
+       for (ALL_LIST_ELEMENTS(bgp_vrf->vrf_import_rtl, node, nnode, ecom)) {
+               for (i = 0; i < ecom->size; i++) {
+                       struct vrf_irt_node *irt;
+                       struct ecommunity_val eval_tmp;
+
+                       eval = (struct ecommunity_val *)(ecom->val
+                                                        + (i
+                                                           * ECOMMUNITY_SIZE));
+                       /* If using "automatic" RT, we only care about the
+                        * local-admin sub-field.
+                        * This is to facilitate using VNI as the RT for EBGP
+                        * peering too.
+                        */
+                       memcpy(&eval_tmp, eval, ECOMMUNITY_SIZE);
+                       if (!CHECK_FLAG(bgp_vrf->vrf_flags,
+                                       BGP_VRF_IMPORT_RT_CFGD))
+                               mask_ecom_global_admin(&eval_tmp, eval);
+
+                       irt = lookup_vrf_import_rt(&eval_tmp);
+                       if (irt)
+                               unmap_vrf_from_rt(bgp_vrf, irt);
+               }
+       }
+}
+
+
 
 /*
  * Map the RTs (configured or automatically derived) of a VNI to the VNI.
@@ -2515,7 +3933,7 @@ void bgp_evpn_unmap_vni_from_its_rts(struct bgp *bgp, struct bgpevpn *vpn)
  */
 void bgp_evpn_derive_auto_rt_import(struct bgp *bgp, struct bgpevpn *vpn)
 {
-       form_auto_rt(bgp, vpn, vpn->import_rtl);
+       form_auto_rt(bgp, vpn->vni, vpn->import_rtl);
        UNSET_FLAG(vpn->flags, VNI_FLAG_IMPRT_CFGD);
 
        /* Map RT to VNI */
@@ -2527,10 +3945,24 @@ void bgp_evpn_derive_auto_rt_import(struct bgp *bgp, struct bgpevpn *vpn)
  */
 void bgp_evpn_derive_auto_rt_export(struct bgp *bgp, struct bgpevpn *vpn)
 {
-       form_auto_rt(bgp, vpn, vpn->export_rtl);
+       form_auto_rt(bgp, vpn->vni, vpn->export_rtl);
        UNSET_FLAG(vpn->flags, VNI_FLAG_EXPRT_CFGD);
 }
 
+/*
+ * Derive RD automatically for VNI using passed information - it
+ * is of the form RouterId:unique-id-for-vni.
+ */
+void bgp_evpn_derive_auto_rd_for_vrf(struct bgp *bgp)
+{
+       char buf[100];
+
+       bgp->vrf_prd.family = AF_UNSPEC;
+       bgp->vrf_prd.prefixlen = 64;
+       sprintf(buf, "%s:%hu", inet_ntoa(bgp->router_id), bgp->vrf_rd_id);
+       str2prefix_rd(buf, &bgp->vrf_prd);
+}
+
 /*
  * Derive RD automatically for VNI using passed information - it
  * is of the form RouterId:unique-id-for-vni.
@@ -2564,7 +3996,8 @@ struct bgpevpn *bgp_evpn_lookup_vni(struct bgp *bgp, vni_t vni)
  * Create a new vpn - invoked upon configuration or zebra notification.
  */
 struct bgpevpn *bgp_evpn_new(struct bgp *bgp, vni_t vni,
-                            struct in_addr originator_ip)
+                            struct in_addr originator_ip,
+                            vrf_id_t tenant_vrf_id)
 {
        struct bgpevpn *vpn;
 
@@ -2578,13 +4011,14 @@ struct bgpevpn *bgp_evpn_new(struct bgp *bgp, vni_t vni,
        /* Set values - RD and RT set to defaults. */
        vpn->vni = vni;
        vpn->originator_ip = originator_ip;
+       vpn->tenant_vrf_id = tenant_vrf_id;
 
        /* Initialize route-target import and export lists */
        vpn->import_rtl = list_new();
        vpn->import_rtl->cmp = (int (*)(void *, void *))evpn_route_target_cmp;
        vpn->export_rtl = list_new();
        vpn->export_rtl->cmp = (int (*)(void *, void *))evpn_route_target_cmp;
-       bf_assign_index(bgp->rd_idspace, vpn->rd_id);
+       bf_assign_index(bm->rd_idspace, vpn->rd_id);
        derive_rd_rt_for_vni(bgp, vpn);
 
        /* Initialize EVPN route table. */
@@ -2595,6 +4029,10 @@ struct bgpevpn *bgp_evpn_new(struct bgp *bgp, vni_t vni,
                XFREE(MTYPE_BGP_EVPN, vpn);
                return NULL;
        }
+
+       /* add to l2vni list on corresponding vrf */
+       bgpevpn_link_to_l3vni(vpn);
+
        QOBJ_REG(vpn, bgpevpn);
        return vpn;
 }
@@ -2607,11 +4045,12 @@ struct bgpevpn *bgp_evpn_new(struct bgp *bgp, vni_t vni,
  */
 void bgp_evpn_free(struct bgp *bgp, struct bgpevpn *vpn)
 {
+       bgpevpn_unlink_from_l3vni(vpn);
        bgp_table_unlock(vpn->route_table);
        bgp_evpn_unmap_vni_from_its_rts(bgp, vpn);
        list_delete_and_null(&vpn->import_rtl);
        list_delete_and_null(&vpn->export_rtl);
-       bf_release_index(bgp->rd_idspace, vpn->rd_id);
+       bf_release_index(bm->rd_idspace, vpn->rd_id);
        hash_release(bgp->vnihash, vpn);
        QOBJ_UNREG(vpn);
        XFREE(MTYPE_BGP_EVPN, vpn);
@@ -2758,15 +4197,170 @@ int bgp_evpn_local_macip_add(struct bgp *bgp, vni_t vni, struct ethaddr *mac,
                char buf2[INET6_ADDRSTRLEN];
 
                zlog_err(
-                       "%u:Failed to create Type-2 route, VNI %u %s MAC %s IP %s",
+                       "%u:Failed to create Type-2 route, VNI %u %s MAC %s IP %s (flags: 0x%x)",
                        bgp->vrf_id, vpn->vni,
-                       CHECK_FLAG(flags, ZEBRA_MAC_TYPE_STICKY) ? "sticky gateway"
+                       CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY) ? "sticky gateway"
                                                                 : "",
                        prefix_mac2str(mac, buf, sizeof(buf)),
-                       ipaddr2str(ip, buf2, sizeof(buf2)));
+                       ipaddr2str(ip, buf2, sizeof(buf2)),
+                       flags);
+               return -1;
+       }
+
+       return 0;
+}
+
+static void link_l2vni_hash_to_l3vni(struct hash_backet *backet,
+                                    struct bgp *bgp_vrf)
+{
+       struct bgpevpn *vpn = NULL;
+       struct bgp *bgp_def = NULL;
+
+       bgp_def = bgp_get_default();
+       assert(bgp_def);
+
+       vpn = (struct bgpevpn *)backet->data;
+       if (vpn->tenant_vrf_id == bgp_vrf->vrf_id)
+               bgpevpn_link_to_l3vni(vpn);
+}
+
+int bgp_evpn_local_l3vni_add(vni_t l3vni,
+                            vrf_id_t vrf_id,
+                            struct ethaddr *rmac,
+                            struct in_addr originator_ip)
+{
+       struct bgp *bgp_vrf = NULL; /* bgp VRF instance */
+       struct bgp *bgp_def = NULL; /* default bgp instance */
+       struct listnode *node = NULL;
+       struct bgpevpn *vpn = NULL;
+       as_t as = 0;
+
+       /* get the default instamce - required to get the AS number for VRF
+        * auto-creatio
+        */
+       bgp_def = bgp_get_default();
+       if (!bgp_def) {
+               zlog_err("Cannot process L3VNI  %u ADD - default BGP instance not yet created",
+                        l3vni);
+               return -1;
+       }
+       as = bgp_def->as;
+
+       /* if the BGP vrf instance doesnt exist - create one */
+       bgp_vrf = bgp_lookup_by_name(vrf_id_to_name(vrf_id));
+       if (!bgp_vrf) {
+
+               int ret = 0;
+
+               ret = bgp_get(&bgp_vrf, &as, vrf_id_to_name(vrf_id),
+                             BGP_INSTANCE_TYPE_VRF);
+               switch (ret) {
+               case BGP_ERR_MULTIPLE_INSTANCE_NOT_SET:
+                       zlog_err("'bgp multiple-instance' not present\n");
+                       return -1;
+               case BGP_ERR_AS_MISMATCH:
+                       zlog_err("BGP is already running; AS is %u\n", as);
+                       return -1;
+               case BGP_ERR_INSTANCE_MISMATCH:
+                       zlog_err("BGP instance name and AS number mismatch\n");
+                       return -1;
+               }
+
+               /* mark as auto created */
+               SET_FLAG(bgp_vrf->vrf_flags, BGP_VRF_AUTO);
+       }
+
+       /* associate with l3vni */
+       bgp_vrf->l3vni = l3vni;
+
+       /* set the router mac - to be used in mac-ip routes for this vrf */
+       memcpy(&bgp_vrf->rmac, rmac, sizeof(struct ethaddr));
+
+       /* set the originator ip */
+       bgp_vrf->originator_ip = originator_ip;
+
+       /* auto derive RD/RT */
+       if (!CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_IMPORT_RT_CFGD))
+               evpn_auto_rt_import_add_for_vrf(bgp_vrf);
+       if (!CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_EXPORT_RT_CFGD))
+               evpn_auto_rt_export_add_for_vrf(bgp_vrf);
+       bgp_evpn_derive_auto_rd_for_vrf(bgp_vrf);
+
+       /* link all corresponding l2vnis */
+       hash_iterate(bgp_def->vnihash,
+                    (void (*)(struct hash_backet *, void *))
+                       link_l2vni_hash_to_l3vni,
+                    bgp_vrf);
+
+       /* updates all corresponding local mac-ip routes */
+       for (ALL_LIST_ELEMENTS_RO(bgp_vrf->l2vnis, node, vpn))
+               update_routes_for_vni(bgp_def, vpn);
+
+       /* advertise type-5 routes if needed */
+       update_advertise_vrf_routes(bgp_vrf);
+
+       /* install all remote routes belonging to this l3vni into correspondng
+        * vrf */
+       install_routes_for_vrf(bgp_vrf);
+
+       return 0;
+}
+
+int bgp_evpn_local_l3vni_del(vni_t l3vni,
+                            vrf_id_t vrf_id)
+{
+       struct bgp *bgp_vrf = NULL; /* bgp vrf instance */
+       struct bgp *bgp_def = NULL; /* default bgp instance */
+       struct listnode *node = NULL;
+       struct bgpevpn *vpn = NULL;
+
+       bgp_vrf = bgp_lookup_by_vrf_id(vrf_id);
+       if (!bgp_vrf) {
+               zlog_err("Cannot process L3VNI %u Del - Could not find BGP instance",
+                        l3vni);
+               return -1;
+       }
+
+       bgp_def = bgp_get_default();
+       if (!bgp_def) {
+               zlog_err("Cannot process L3VNI %u Del - Could not find default BGP instance",
+                        l3vni);
                return -1;
        }
 
+       /* unimport remote routes from VRF, if it is AUTO vrf bgp_delete will
+        * take care of uninstalling the routes from zebra
+        */
+       if (!CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_AUTO))
+               uninstall_routes_for_vrf(bgp_vrf);
+
+       /* delete/withdraw all type-5 routes */
+       delete_withdraw_vrf_routes(bgp_vrf);
+
+       /* remove the l3vni from vrf instance */
+       bgp_vrf->l3vni = 0;
+
+       /* remove the Rmac from the BGP vrf */
+       memset(&bgp_vrf->rmac, 0, sizeof(struct ethaddr));
+
+       /* delete RD/RT */
+       if (bgp_vrf->vrf_import_rtl && !list_isempty(bgp_vrf->vrf_import_rtl)) {
+               bgp_evpn_unmap_vrf_from_its_rts(bgp_vrf);
+               list_delete_all_node(bgp_vrf->vrf_import_rtl);
+       }
+       if (bgp_vrf->vrf_export_rtl && !list_isempty(bgp_vrf->vrf_export_rtl)) {
+               list_delete_all_node(bgp_vrf->vrf_export_rtl);
+       }
+
+       /* update all corresponding local mac-ip routes */
+       for (ALL_LIST_ELEMENTS_RO(bgp_vrf->l2vnis, node, vpn))
+               update_routes_for_vni(bgp_def, vpn);
+
+
+       /* Delete the instance if it was autocreated */
+       if (CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_AUTO))
+               bgp_delete(bgp_vrf);
+
        return 0;
 }
 
@@ -2813,7 +4407,8 @@ int bgp_evpn_local_vni_del(struct bgp *bgp, vni_t vni)
  * about is change to local-tunnel-ip.
  */
 int bgp_evpn_local_vni_add(struct bgp *bgp, vni_t vni,
-                          struct in_addr originator_ip)
+                          struct in_addr originator_ip,
+                          vrf_id_t tenant_vrf_id)
 {
        struct bgpevpn *vpn;
        struct prefix_evpn p;
@@ -2826,6 +4421,17 @@ int bgp_evpn_local_vni_add(struct bgp *bgp, vni_t vni,
        /* Lookup VNI. If present and no change, exit. */
        vpn = bgp_evpn_lookup_vni(bgp, vni);
        if (vpn) {
+
+               /* update tenant_vrf_id if required */
+               if (vpn->tenant_vrf_id != tenant_vrf_id) {
+                       bgpevpn_unlink_from_l3vni(vpn);
+                       vpn->tenant_vrf_id = tenant_vrf_id;
+                       bgpevpn_link_to_l3vni(vpn);
+
+                       /* update all routes with new export RT for VRFs */
+                       update_routes_for_vni(bgp, vpn);
+               }
+
                if (is_vni_live(vpn)
                    && IPV4_ADDR_SAME(&vpn->originator_ip, &originator_ip))
                        /* Probably some other param has changed that we don't
@@ -2838,7 +4444,7 @@ int bgp_evpn_local_vni_add(struct bgp *bgp, vni_t vni,
 
        /* Create or update as appropriate. */
        if (!vpn) {
-               vpn = bgp_evpn_new(bgp, vni, originator_ip);
+               vpn = bgp_evpn_new(bgp, vni, originator_ip, tenant_vrf_id);
                if (!vpn) {
                        zlog_err(
                                "%u: Failed to allocate VNI entry for VNI %u - at Add",
@@ -2905,10 +4511,19 @@ void bgp_evpn_cleanup(struct bgp *bgp)
        if (bgp->import_rt_hash)
                hash_free(bgp->import_rt_hash);
        bgp->import_rt_hash = NULL;
+       if (bgp->vrf_import_rt_hash)
+               hash_free(bgp->vrf_import_rt_hash);
+       bgp->vrf_import_rt_hash = NULL;
        if (bgp->vnihash)
                hash_free(bgp->vnihash);
        bgp->vnihash = NULL;
-       bf_free(bgp->rd_idspace);
+       if (bgp->vrf_import_rtl)
+               list_delete_and_null(&bgp->vrf_import_rtl);
+       if (bgp->vrf_export_rtl)
+               list_delete_and_null(&bgp->vrf_export_rtl);
+       if (bgp->l2vnis)
+               list_delete_and_null(&bgp->l2vnis);
+       bf_release_index(bm->rd_idspace, bgp->vrf_rd_id);
 }
 
 /*
@@ -2916,7 +4531,7 @@ void bgp_evpn_cleanup(struct bgp *bgp)
  * Create
  *  VNI hash table
  *  hash for RT to VNI
- *  unique rd id space for auto derivation of RD for VNIs
+ *  assign a unique rd id for auto derivation of vrf_prd
  */
 void bgp_evpn_init(struct bgp *bgp)
 {
@@ -2925,7 +4540,24 @@ void bgp_evpn_init(struct bgp *bgp)
        bgp->import_rt_hash =
                hash_create(import_rt_hash_key_make, import_rt_hash_cmp,
                            "BGP Import RT Hash");
-       bf_init(bgp->rd_idspace, UINT16_MAX);
-       /*assign 0th index in the bitfield, so that we start with id 1*/
-       bf_assign_zero_index(bgp->rd_idspace);
+       bgp->vrf_import_rt_hash =
+               hash_create(vrf_import_rt_hash_key_make, vrf_import_rt_hash_cmp,
+                           "BGP VRF Import RT Hash");
+       bgp->vrf_import_rtl = list_new();
+       bgp->vrf_import_rtl->cmp =
+               (int (*)(void *, void *))evpn_route_target_cmp;
+
+       bgp->vrf_export_rtl = list_new();
+       bgp->vrf_export_rtl->cmp =
+               (int (*)(void *, void *))evpn_route_target_cmp;
+       bgp->l2vnis = list_new();
+       bgp->l2vnis->cmp =
+               (int (*)(void *, void *))vni_hash_cmp;
+       bf_assign_index(bm->rd_idspace, bgp->vrf_rd_id);
+
+}
+
+void bgp_evpn_vrf_delete(struct bgp *bgp_vrf)
+{
+       bgp_evpn_unmap_vrf_from_its_rts(bgp_vrf);
 }
index 985f41f58675c1ea084bbcca4086fae38e91cb1a..a8dcbc112b1cc18b4313bec527e4f4d0ecd95403 100644 (file)
 #define _QUAGGA_BGP_EVPN_H
 
 #include "vxlan.h"
+#include "bgpd.h"
 
 #define EVPN_ROUTE_STRLEN 200 /* Must be >> MAC + IPv6 strings. */
 
+static inline int is_evpn_enabled(void)
+{
+       struct bgp *bgp = NULL;
+
+       bgp = bgp_get_default();
+       return bgp ? bgp->advertise_all_vni : 0;
+}
+
+static inline void vni2label(vni_t vni, mpls_label_t *label)
+{
+       u_char *tag = (u_char *)label;
+
+       tag[0] = (vni >> 16) & 0xFF;
+       tag[1] = (vni >> 8) & 0xFF;
+       tag[2] = vni & 0xFF;
+}
+
+static inline vni_t label2vni(mpls_label_t *label)
+{
+       u_char *tag = (u_char *)label;
+       vni_t vni;
+
+       vni = ((u_int32_t)*tag++ << 16);
+       vni |= (u_int32_t)*tag++ << 8;
+       vni |= (u_int32_t)(*tag & 0xFF);
+
+       return vni;
+}
+
+extern void bgp_evpn_advertise_type5_route(struct bgp *bgp_vrf,
+                                          struct prefix *p,
+                                          struct attr *src_attr,
+                                          afi_t afi, safi_t safi);
+extern void bgp_evpn_withdraw_type5_route(struct bgp *bgp_vrf,
+                                         struct prefix *p,
+                                         afi_t afi, safi_t safi);
+extern void bgp_evpn_withdraw_type5_routes(struct bgp *bgp_vrf, afi_t afi,
+                                          safi_t safi);
+extern void bgp_evpn_advertise_type5_routes(struct bgp *bgp_vrf, afi_t afi,
+                                           safi_t safi);
+extern void bgp_evpn_vrf_delete(struct bgp *bgp_vrf);
 extern void bgp_evpn_handle_router_id_update(struct bgp *bgp, int withdraw);
-extern char *bgp_evpn_label2str(mpls_label_t *label, char *buf, int len);
+extern char *bgp_evpn_label2str(mpls_label_t *label, u_int32_t num_labels,
+                               char *buf, int len);
 extern char *bgp_evpn_route2str(struct prefix_evpn *p, char *buf, int len);
 extern void bgp_evpn_route2json(struct prefix_evpn *p, json_object *json);
 extern void bgp_evpn_encode_prefix(struct stream *s, struct prefix *p,
-                                  struct prefix_rd *prd, mpls_label_t *label,
+                                  struct prefix_rd *prd,
+                                  mpls_label_t *label, u_int32_t num_labels,
                                   struct attr *attr, int addpath_encode,
                                   u_int32_t addpath_tx_id);
 extern int bgp_nlri_parse_evpn(struct peer *peer, struct attr *attr,
@@ -45,9 +89,14 @@ extern int bgp_evpn_local_macip_del(struct bgp *bgp, vni_t vni,
 extern int bgp_evpn_local_macip_add(struct bgp *bgp, vni_t vni,
                                    struct ethaddr *mac, struct ipaddr *ip,
                                    u_char flags);
+extern int bgp_evpn_local_l3vni_add(vni_t vni, vrf_id_t vrf_id,
+                                   struct ethaddr *rmac,
+                                   struct in_addr originator_ip);
+extern int bgp_evpn_local_l3vni_del(vni_t vni, vrf_id_t vrf_id);
 extern int bgp_evpn_local_vni_del(struct bgp *bgp, vni_t vni);
 extern int bgp_evpn_local_vni_add(struct bgp *bgp, vni_t vni,
-                                 struct in_addr originator_ip);
+                                 struct in_addr originator_ip,
+                                 vrf_id_t tenant_vrf_id);
 extern void bgp_evpn_cleanup_on_disable(struct bgp *bgp);
 extern void bgp_evpn_cleanup(struct bgp *bgp);
 extern void bgp_evpn_init(struct bgp *bgp);
index a58f73f4bc924a767d21dabcc440ab421188b9e5..cc0ec82344b3f2c03cad7cc7a4fd1ca1806d82c5 100644 (file)
 
 #define RT_ADDRSTRLEN 28
 
-/* EVPN prefix lengths. */
+/* EVPN prefix lengths. This reprsent the sizeof struct prefix_evpn  */
 #define EVPN_TYPE_2_ROUTE_PREFIXLEN      224
 #define EVPN_TYPE_3_ROUTE_PREFIXLEN      224
+#define EVPN_TYPE_5_ROUTE_PREFIXLEN      224
 
 /* EVPN route types. */
 typedef enum {
@@ -53,6 +54,7 @@ typedef enum {
  */
 struct bgpevpn {
        vni_t vni;
+       vrf_id_t tenant_vrf_id;
        u_int32_t flags;
 #define VNI_FLAG_CFGD              0x1  /* VNI is user configured */
 #define VNI_FLAG_LIVE              0x2  /* VNI is "live" */
@@ -63,6 +65,9 @@ struct bgpevpn {
        /* Flag to indicate if we are advertising the g/w mac ip for this VNI*/
        u_int8_t advertise_gw_macip;
 
+       /* Flag to indicate if we are advertising subnet for this VNI */
+       u_int8_t advertise_subnet;
+
        /* Id for deriving the RD automatically for this VNI */
        u_int16_t rd_id;
 
@@ -96,10 +101,99 @@ struct irt_node {
        struct list *vnis;
 };
 
+/* Mapping of Import RT to VRFs.
+ * The Import RTs of all VRFss are maintained in a hash table with each
+ * RT linking to all VRFs that will import routes matching this RT.
+ */
+struct vrf_irt_node {
+       /* RT */
+       struct ecommunity_val rt;
+
+       /* List of VNIs importing routes matching this RT. */
+       struct list *vrfs;
+};
+
+
 #define RT_TYPE_IMPORT 1
 #define RT_TYPE_EXPORT 2
 #define RT_TYPE_BOTH   3
 
+static inline int is_vrf_rd_configured(struct bgp *bgp_vrf)
+{
+       return (CHECK_FLAG(bgp_vrf->vrf_flags,
+                          BGP_VRF_RD_CFGD));
+}
+
+static inline int bgp_evpn_vrf_rd_matches_existing(struct bgp *bgp_vrf,
+                                                  struct prefix_rd *prd)
+{
+       return (memcmp(&bgp_vrf->vrf_prd.val, prd->val, ECOMMUNITY_SIZE) == 0);
+}
+
+static inline vni_t bgpevpn_get_l3vni(struct bgpevpn *vpn)
+{
+       struct bgp *bgp_vrf = NULL;
+
+       bgp_vrf = bgp_lookup_by_vrf_id(vpn->tenant_vrf_id);
+       if (!bgp_vrf)
+               return 0;
+
+       return bgp_vrf->l3vni;
+}
+
+static inline void bgpevpn_get_rmac(struct bgpevpn *vpn, struct ethaddr *rmac)
+{
+       struct bgp *bgp_vrf = NULL;
+
+       memset(rmac, 0, sizeof(struct ethaddr));
+       bgp_vrf = bgp_lookup_by_vrf_id(vpn->tenant_vrf_id);
+       if (!bgp_vrf)
+               return;
+       memcpy(rmac, &bgp_vrf->rmac, sizeof(struct ethaddr));
+}
+
+static inline struct list *bgpevpn_get_vrf_export_rtl(struct bgpevpn *vpn)
+{
+       struct bgp *bgp_vrf = NULL;
+
+       bgp_vrf = bgp_lookup_by_vrf_id(vpn->tenant_vrf_id);
+       if (!bgp_vrf)
+               return NULL;
+
+       return bgp_vrf->vrf_export_rtl;
+}
+
+static inline struct list *bgpevpn_get_vrf_import_rtl(struct bgpevpn *vpn)
+{
+       struct bgp *bgp_vrf = NULL;
+
+       bgp_vrf = bgp_lookup_by_vrf_id(vpn->tenant_vrf_id);
+       if (!bgp_vrf)
+               return NULL;
+
+       return bgp_vrf->vrf_import_rtl;
+}
+
+static inline void bgpevpn_unlink_from_l3vni(struct bgpevpn *vpn)
+{
+       struct bgp *bgp_vrf = NULL;
+
+       bgp_vrf = bgp_lookup_by_vrf_id(vpn->tenant_vrf_id);
+       if (!bgp_vrf || !bgp_vrf->l2vnis)
+               return;
+       listnode_delete(bgp_vrf->l2vnis, vpn);
+}
+
+static inline void bgpevpn_link_to_l3vni(struct bgpevpn *vpn)
+{
+       struct bgp *bgp_vrf = NULL;
+
+       bgp_vrf = bgp_lookup_by_vrf_id(vpn->tenant_vrf_id);
+       if (!bgp_vrf || !bgp_vrf->l2vnis)
+               return;
+       listnode_add_sort(bgp_vrf->l2vnis, vpn);
+}
+
 static inline int is_vni_configured(struct bgpevpn *vpn)
 {
        return (CHECK_FLAG(vpn->flags, VNI_FLAG_CFGD));
@@ -137,24 +231,20 @@ static inline int is_vni_param_configured(struct bgpevpn *vpn)
                || is_export_rt_configured(vpn));
 }
 
-static inline void vni2label(vni_t vni, mpls_label_t *label)
+static inline void encode_rmac_extcomm(struct ecommunity_val *eval,
+                                      struct ethaddr *rmac)
 {
-       u_char *tag = (u_char *)label;
-       tag[0] = (vni >> 16) & 0xFF;
-       tag[1] = (vni >> 8) & 0xFF;
-       tag[2] = vni & 0xFF;
+       memset(eval, 0, sizeof(*eval));
+       eval->val[0] = ECOMMUNITY_ENCODE_EVPN;
+       eval->val[1] = ECOMMUNITY_EVPN_SUBTYPE_ROUTERMAC;
+       memcpy(&eval->val[2], rmac, ETH_ALEN);
 }
 
-static inline vni_t label2vni(mpls_label_t *label)
+static inline void encode_default_gw_extcomm(struct ecommunity_val *eval)
 {
-       u_char *tag = (u_char *)label;
-       vni_t vni;
-
-       vni = ((u_int32_t)*tag++ << 16);
-       vni |= (u_int32_t)*tag++ << 8;
-       vni |= (u_int32_t)(*tag & 0xFF);
-
-       return vni;
+       memset(eval, 0, sizeof(*eval));
+       eval->val[0] = ECOMMUNITY_ENCODE_OPAQUE;
+       eval->val[1] = ECOMMUNITY_EVPN_SUBTYPE_DEF_GW;
 }
 
 static inline void encode_mac_mobility_extcomm(int static_mac, u_int32_t seq,
@@ -171,6 +261,44 @@ static inline void encode_mac_mobility_extcomm(int static_mac, u_int32_t seq,
        eval->val[7] = seq & 0xff;
 }
 
+static inline void ip_prefix_from_type5_prefix(struct prefix_evpn *evp,
+                                              struct prefix *ip)
+{
+       memset(ip, 0, sizeof(struct prefix));
+       if (IS_EVPN_PREFIX_IPADDR_V4(evp)) {
+               ip->family = AF_INET;
+               ip->prefixlen = evp->prefix.ip_prefix_length;
+               memcpy(&(ip->u.prefix4),
+                      &(evp->prefix.ip.ip),
+                      IPV4_MAX_BYTELEN);
+       } else if (IS_EVPN_PREFIX_IPADDR_V6(evp)) {
+               ip->family = AF_INET6;
+               ip->prefixlen = evp->prefix.ip_prefix_length;
+               memcpy(&(ip->u.prefix6),
+                      &(evp->prefix.ip.ip),
+                      IPV6_MAX_BYTELEN);
+       }
+}
+
+static inline void ip_prefix_from_type2_prefix(struct prefix_evpn *evp,
+                                              struct prefix *ip)
+{
+       memset(ip, 0, sizeof(struct prefix));
+       if (IS_EVPN_PREFIX_IPADDR_V4(evp)) {
+               ip->family = AF_INET;
+               ip->prefixlen = IPV4_MAX_BITLEN;
+               memcpy(&(ip->u.prefix4),
+                      &(evp->prefix.ip.ip),
+                      IPV4_MAX_BYTELEN);
+       } else if (IS_EVPN_PREFIX_IPADDR_V6(evp)) {
+               ip->family = AF_INET6;
+               ip->prefixlen = IPV6_MAX_BITLEN;
+               memcpy(&(ip->u.prefix6),
+                      &(evp->prefix.ip.ip),
+                      IPV6_MAX_BYTELEN);
+       }
+}
+
 static inline void build_evpn_type2_prefix(struct prefix_evpn *p,
                                           struct ethaddr *mac,
                                           struct ipaddr *ip)
@@ -185,6 +313,31 @@ static inline void build_evpn_type2_prefix(struct prefix_evpn *p,
                memcpy(&p->prefix.ip, ip, sizeof(*ip));
 }
 
+static inline void build_type5_prefix_from_ip_prefix(struct prefix_evpn *evp,
+                                                    struct prefix *ip_prefix)
+{
+       struct ipaddr ip;
+
+       memset(&ip, 0, sizeof(struct ipaddr));
+       if (ip_prefix->family == AF_INET) {
+               ip.ipa_type = IPADDR_V4;
+               memcpy(&ip.ipaddr_v4, &ip_prefix->u.prefix4,
+                      sizeof(struct in_addr));
+       } else {
+               ip.ipa_type = IPADDR_V6;
+               memcpy(&ip.ipaddr_v6, &ip_prefix->u.prefix6,
+                      sizeof(struct in6_addr));
+       }
+
+       memset(evp, 0, sizeof(struct prefix_evpn));
+       evp->family = AF_EVPN;
+       evp->prefixlen = EVPN_TYPE_5_ROUTE_PREFIXLEN;
+       evp->prefix.ip_prefix_length = ip_prefix->prefixlen;
+       evp->prefix.route_type = BGP_EVPN_IP_PREFIX_ROUTE;
+       evp->prefix.ip.ipa_type = ip.ipa_type;
+       memcpy(&evp->prefix.ip, &ip, sizeof(struct ipaddr));
+}
+
 static inline void build_evpn_type3_prefix(struct prefix_evpn *p,
                                           struct in_addr originator_ip)
 {
@@ -196,13 +349,41 @@ static inline void build_evpn_type3_prefix(struct prefix_evpn *p,
        p->prefix.ip.ipaddr_v4 = originator_ip;
 }
 
+static inline int advertise_type5_routes(struct bgp *bgp_vrf,
+                                        afi_t afi)
+{
+       if (!bgp_vrf->l3vni)
+               return 0;
+
+       if (afi == AFI_IP &&
+           CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_ADVERTISE_IPV4_IN_EVPN))
+               return 1;
+
+       if (afi == AFI_IP6 &&
+           CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_ADVERTISE_IPV6_IN_EVPN))
+               return 1;
+
+       return 0;
+}
 
+extern void evpn_rt_delete_auto(struct bgp*, vni_t, struct list*);
+extern void bgp_evpn_configure_export_rt_for_vrf(struct bgp *bgp_vrf,
+                                                struct ecommunity *ecomadd);
+extern void bgp_evpn_unconfigure_export_rt_for_vrf(struct bgp *bgp_vrf,
+                                                  struct ecommunity *ecomdel);
+extern void bgp_evpn_configure_import_rt_for_vrf(struct bgp *bgp_vrf,
+                                                struct ecommunity *ecomadd);
+extern void bgp_evpn_unconfigure_import_rt_for_vrf(struct bgp *bgp_vrf,
+                                                  struct ecommunity *ecomdel);
 extern int bgp_evpn_handle_export_rt_change(struct bgp *bgp,
                                            struct bgpevpn *vpn);
+extern void bgp_evpn_handle_vrf_rd_change(struct bgp *bgp_vrf, int withdraw);
 extern void bgp_evpn_handle_rd_change(struct bgp *bgp, struct bgpevpn *vpn,
                                      int withdraw);
 extern int bgp_evpn_install_routes(struct bgp *bgp, struct bgpevpn *vpn);
 extern int bgp_evpn_uninstall_routes(struct bgp *bgp, struct bgpevpn *vpn);
+extern void bgp_evpn_map_vrf_to_its_rts(struct bgp *bgp_vrf);
+extern void bgp_evpn_unmap_vrf_from_its_rts(struct bgp *bgp_vrf);
 extern void bgp_evpn_map_vni_to_its_rts(struct bgp *bgp, struct bgpevpn *vpn);
 extern void bgp_evpn_unmap_vni_from_its_rts(struct bgp *bgp,
                                            struct bgpevpn *vpn);
@@ -211,8 +392,10 @@ extern void bgp_evpn_derive_auto_rt_import(struct bgp *bgp,
 extern void bgp_evpn_derive_auto_rt_export(struct bgp *bgp,
                                           struct bgpevpn *vpn);
 extern void bgp_evpn_derive_auto_rd(struct bgp *bgp, struct bgpevpn *vpn);
+extern void bgp_evpn_derive_auto_rd_for_vrf(struct bgp *bgp);
 extern struct bgpevpn *bgp_evpn_lookup_vni(struct bgp *bgp, vni_t vni);
 extern struct bgpevpn *bgp_evpn_new(struct bgp *bgp, vni_t vni,
-                                   struct in_addr originator_ip);
+                                   struct in_addr originator_ip,
+                                   vrf_id_t tenant_vrf_id);
 extern void bgp_evpn_free(struct bgp *bgp, struct bgpevpn *vpn);
 #endif /* _BGP_EVPN_PRIVATE_H */
index f473b4604a778c572e1bb20086f775ea1223aa8f..1373afec4ec280173fbae1b795772de0501ccda2 100644 (file)
@@ -53,6 +53,117 @@ struct vni_walk_ctx {
 };
 
 #if defined(HAVE_CUMULUS)
+static void display_vrf_import_rt(struct vty *vty,
+                                 struct vrf_irt_node *irt,
+                                 json_object *json)
+{
+       u_char *pnt;
+       u_char type, sub_type;
+       struct ecommunity_as eas;
+       struct ecommunity_ip eip;
+       struct listnode *node, *nnode;
+       struct bgp *tmp_bgp_vrf = NULL;
+       json_object *json_rt = NULL;
+       json_object *json_vrfs = NULL;
+       char rt_buf[RT_ADDRSTRLEN];
+
+       if (json) {
+               json_rt = json_object_new_object();
+               json_vrfs = json_object_new_array();
+       }
+
+       pnt = (u_char *)&irt->rt.val;
+       type = *pnt++;
+       sub_type = *pnt++;
+       if (sub_type != ECOMMUNITY_ROUTE_TARGET)
+               return;
+
+       memset(&eas, 0, sizeof(eas));
+       switch (type) {
+       case ECOMMUNITY_ENCODE_AS:
+               eas.as = (*pnt++ << 8);
+               eas.as |= (*pnt++);
+               ptr_get_be32(pnt, &eas.val);
+
+               snprintf(rt_buf, RT_ADDRSTRLEN, "%u:%u", eas.as, eas.val);
+
+               if (json)
+                       json_object_string_add(json_rt, "rt", rt_buf);
+               else
+                       vty_out(vty, "Route-target: %s", rt_buf);
+
+               break;
+
+       case ECOMMUNITY_ENCODE_IP:
+               memcpy(&eip.ip, pnt, 4);
+               pnt += 4;
+               eip.val = (*pnt++ << 8);
+               eip.val |= (*pnt++);
+
+               snprintf(rt_buf, RT_ADDRSTRLEN, "%s:%u", inet_ntoa(eip.ip),
+                        eip.val);
+
+               if (json)
+                       json_object_string_add(json_rt, "rt", rt_buf);
+               else
+                       vty_out(vty, "Route-target: %s", rt_buf);
+
+               break;
+
+       case ECOMMUNITY_ENCODE_AS4:
+               pnt = ptr_get_be32(pnt, &eas.val);
+               eas.val = (*pnt++ << 8);
+               eas.val |= (*pnt++);
+
+               snprintf(rt_buf, RT_ADDRSTRLEN, "%u:%u", eas.as, eas.val);
+
+               if (json)
+                       json_object_string_add(json_rt, "rt", rt_buf);
+               else
+                       vty_out(vty, "Route-target: %s", rt_buf);
+
+               break;
+
+       default:
+               return;
+       }
+
+       if (!json) {
+               vty_out(vty,
+                       "\nList of VRFs importing routes with this route-target:\n");
+       }
+
+       for (ALL_LIST_ELEMENTS(irt->vrfs, node, nnode, tmp_bgp_vrf)) {
+               if (json)
+                       json_object_array_add(
+                               json_vrfs,
+                               json_object_new_string(
+                                               vrf_id_to_name(
+                                                       tmp_bgp_vrf->vrf_id)));
+               else
+                       vty_out(vty, "  %s\n",
+                               vrf_id_to_name(tmp_bgp_vrf->vrf_id));
+       }
+
+       if (json) {
+               json_object_object_add(json_rt, "vrfs", json_vrfs);
+               json_object_object_add(json, rt_buf, json_rt);
+       }
+}
+
+static void show_vrf_import_rt_entry(struct hash_backet *backet,
+                                    void *args[])
+{
+       json_object *json = NULL;
+       struct vty *vty = NULL;
+       struct vrf_irt_node *irt = (struct vrf_irt_node *)backet->data;
+
+       vty = (struct vty *)args[0];
+       json = (struct json_object *)args[1];
+
+       display_vrf_import_rt(vty, irt, json);
+}
+
 static void display_import_rt(struct vty *vty, struct irt_node *irt,
                              json_object *json)
 {
@@ -84,7 +195,7 @@ static void display_import_rt(struct vty *vty, struct irt_node *irt,
        case ECOMMUNITY_ENCODE_AS:
                eas.as = (*pnt++ << 8);
                eas.as |= (*pnt++);
-               pnt = ptr_get_be32(pnt, &eas.val);
+               ptr_get_be32(pnt, &eas.val);
 
                snprintf(rt_buf, RT_ADDRSTRLEN, "%u:%u", eas.as, eas.val);
 
@@ -220,10 +331,88 @@ static void bgp_evpn_show_route_header(struct vty *vty, struct bgp *bgp,
        vty_out(vty, "Origin codes: i - IGP, e - EGP, ? - incomplete\n");
        vty_out(vty,
                "EVPN type-2 prefix: [2]:[ESI]:[EthTag]:[MAClen]:[MAC]:[IPlen]:[IP]\n");
-       vty_out(vty, "EVPN type-3 prefix: [3]:[EthTag]:[IPlen]:[OrigIP]\n\n");
+       vty_out(vty, "EVPN type-3 prefix: [3]:[EthTag]:[IPlen]:[OrigIP]\n");
+       vty_out(vty, "EVPN type-5 prefix: [5]:[ESI]:[EthTag]:[IPlen]:[IP]\n\n");
        vty_out(vty, "%s", ri_header);
 }
 
+static void display_l3vni(struct vty *vty, struct bgp *bgp_vrf,
+                         json_object *json)
+{
+       char buf1[INET6_ADDRSTRLEN];
+       char *ecom_str;
+       struct listnode *node, *nnode;
+       struct ecommunity *ecom;
+       json_object *json_import_rtl = NULL;
+       json_object *json_export_rtl = NULL;
+
+       json_import_rtl = json_export_rtl = 0;
+
+       if (json) {
+               json_import_rtl = json_object_new_array();
+               json_export_rtl = json_object_new_array();
+               json_object_int_add(json, "vni", bgp_vrf->l3vni);
+               json_object_string_add(json, "type", "L3");
+               json_object_string_add(json, "kernelFlag", "Yes");
+               json_object_string_add(
+                       json, "rd",
+                       prefix_rd2str(&bgp_vrf->vrf_prd, buf1, RD_ADDRSTRLEN));
+               json_object_string_add(json, "originatorIp",
+                                      inet_ntoa(bgp_vrf->originator_ip));
+               json_object_string_add(json, "advertiseGatewayMacip", "n/a");
+       } else {
+               vty_out(vty, "VNI: %d", bgp_vrf->l3vni);
+               vty_out(vty, " (known to the kernel)");
+               vty_out(vty, "\n");
+
+               vty_out(vty, "  Type: %s\n", "L3");
+               vty_out(vty, "  Tenant VRF: %s\n",
+                       vrf_id_to_name(bgp_vrf->vrf_id));
+               vty_out(vty, "  RD: %s\n",
+                       prefix_rd2str(&bgp_vrf->vrf_prd, buf1, RD_ADDRSTRLEN));
+               vty_out(vty, "  Originator IP: %s\n",
+                       inet_ntoa(bgp_vrf->originator_ip));
+               vty_out(vty, "  Advertise-gw-macip : %s\n", "n/a");
+       }
+
+       if (!json)
+               vty_out(vty, "  Import Route Target:\n");
+
+       for (ALL_LIST_ELEMENTS(bgp_vrf->vrf_import_rtl, node, nnode, ecom)) {
+               ecom_str = ecommunity_ecom2str(ecom,
+                                              ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
+
+               if (json)
+                       json_object_array_add(json_import_rtl,
+                                             json_object_new_string(ecom_str));
+               else
+                       vty_out(vty, "    %s\n", ecom_str);
+
+               XFREE(MTYPE_ECOMMUNITY_STR, ecom_str);
+       }
+
+       if (json)
+               json_object_object_add(json, "importRts", json_import_rtl);
+       else
+               vty_out(vty, "  Export Route Target:\n");
+
+       for (ALL_LIST_ELEMENTS(bgp_vrf->vrf_export_rtl, node, nnode, ecom)) {
+               ecom_str = ecommunity_ecom2str(ecom,
+                                              ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
+
+               if (json)
+                       json_object_array_add(json_export_rtl,
+                                             json_object_new_string(ecom_str));
+               else
+                       vty_out(vty, "    %s\n", ecom_str);
+
+               XFREE(MTYPE_ECOMMUNITY_STR, ecom_str);
+       }
+
+       if (json)
+               json_object_object_add(json, "exportRts", json_export_rtl);
+}
+
 static void display_vni(struct vty *vty, struct bgpevpn *vpn, json_object *json)
 {
        char buf1[RD_ADDRSTRLEN];
@@ -237,6 +426,7 @@ static void display_vni(struct vty *vty, struct bgpevpn *vpn, json_object *json)
                json_import_rtl = json_object_new_array();
                json_export_rtl = json_object_new_array();
                json_object_int_add(json, "vni", vpn->vni);
+               json_object_string_add(json, "type", "L2");
                json_object_string_add(json, "kernelFlag",
                                       is_vni_live(vpn) ? "Yes" : "No");
                json_object_string_add(
@@ -252,6 +442,9 @@ static void display_vni(struct vty *vty, struct bgpevpn *vpn, json_object *json)
                        vty_out(vty, " (known to the kernel)");
                vty_out(vty, "\n");
 
+               vty_out(vty, "  Type: %s\n", "L2");
+               vty_out(vty, "  Tenant-Vrf: %s\n",
+                       vrf_id_to_name(vpn->tenant_vrf_id));
                vty_out(vty, "  RD: %s\n",
                        prefix_rd2str(&vpn->prd, buf1, sizeof(buf1)));
                vty_out(vty, "  Originator IP: %s\n",
@@ -298,6 +491,53 @@ static void display_vni(struct vty *vty, struct bgpevpn *vpn, json_object *json)
                json_object_object_add(json, "exportRts", json_export_rtl);
 }
 
+static void evpn_show_vrf_routes(struct vty *vty,
+                                struct bgp *bgp_vrf)
+{
+       struct bgp *bgp_def = NULL;
+       struct bgp_node *rn;
+       struct bgp_info *ri;
+       int header = 1;
+       u_int32_t prefix_cnt, path_cnt;
+       struct bgp_table *table;
+
+       prefix_cnt = path_cnt = 0;
+       bgp_def = bgp_get_default();
+       if (!bgp_def)
+               return;
+
+       table = (struct bgp_table *)bgp_vrf->rib[AFI_L2VPN][SAFI_EVPN];
+       for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) {
+               char prefix_str[BUFSIZ];
+
+               bgp_evpn_route2str((struct prefix_evpn *)&rn->p, prefix_str,
+                                  sizeof(prefix_str));
+
+               if (rn->info) {
+                       /* Overall header/legend displayed once. */
+                       if (header) {
+                               bgp_evpn_show_route_header(vty, bgp_def, NULL);
+                               header = 0;
+                       }
+                       prefix_cnt++;
+               }
+
+               /* For EVPN, the prefix is displayed for each path (to fit in
+                * with code that already exists).
+                */
+               for (ri = rn->info; ri; ri = ri->next) {
+                       route_vty_out(vty, &rn->p, ri, 0, SAFI_EVPN, NULL);
+                       path_cnt++;
+               }
+       }
+
+       if (prefix_cnt == 0)
+               vty_out(vty, "No EVPN prefixes exist for this VRF");
+       else
+               vty_out(vty, "\nDisplayed %u prefixes (%u paths)",
+                       prefix_cnt, path_cnt);
+}
+
 static void show_vni_routes(struct bgp *bgp, struct bgpevpn *vpn, int type,
                            struct vty *vty, struct in_addr vtep_ip,
                            json_object *json)
@@ -410,13 +650,117 @@ static void show_vni_routes_hash(struct hash_backet *backet, void *arg)
                json_object_object_add(json, vni_str, json_vni);
 }
 
-static void show_vni_entry(struct hash_backet *backet, void *args[])
+static void show_l3vni_entry(struct vty *vty, struct bgp *bgp,
+                          json_object *json)
 {
-       struct vty *vty;
-       json_object *json;
        json_object *json_vni;
        json_object *json_import_rtl;
        json_object *json_export_rtl;
+       char buf1[10];
+       char buf2[INET6_ADDRSTRLEN];
+       char rt_buf[25];
+       char *ecom_str;
+       struct listnode *node, *nnode;
+       struct ecommunity *ecom;
+
+       if (!bgp->l3vni)
+               return;
+
+       if (json) {
+               json_vni = json_object_new_object();
+               json_import_rtl = json_object_new_array();
+               json_export_rtl = json_object_new_array();
+       }
+
+       /* if an l3vni is present in bgp it is live */
+       buf1[0] = '\0';
+       sprintf(buf1, "*");
+
+       if (json) {
+               json_object_int_add(json_vni, "vni", bgp->l3vni);
+               json_object_string_add(json_vni, "type", "L3");
+               json_object_string_add(json_vni, "inKernel", "True");
+               json_object_string_add(json_vni, "originatorIp",
+                                      inet_ntoa(bgp->originator_ip));
+               json_object_string_add(
+                       json_vni, "rd",
+                       prefix_rd2str(&bgp->vrf_prd, buf2, RD_ADDRSTRLEN));
+       } else {
+               vty_out(vty, "%-1s %-10u %-4s %-21s",
+                       buf1, bgp->l3vni, "L3",
+                       prefix_rd2str(&bgp->vrf_prd, buf2, RD_ADDRSTRLEN));
+       }
+
+       for (ALL_LIST_ELEMENTS(bgp->vrf_import_rtl, node, nnode, ecom)) {
+               ecom_str = ecommunity_ecom2str(ecom,
+                                              ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
+
+               if (json) {
+                       json_object_array_add(json_import_rtl,
+                                             json_object_new_string(ecom_str));
+               } else {
+                       if (listcount(bgp->vrf_import_rtl) > 1)
+                               sprintf(rt_buf, "%s, ...", ecom_str);
+                       else
+                               sprintf(rt_buf, "%s", ecom_str);
+                       vty_out(vty, " %-25s", rt_buf);
+               }
+
+               XFREE(MTYPE_ECOMMUNITY_STR, ecom_str);
+
+               /* If there are multiple import RTs we break here and show only
+                * one */
+               if (!json)
+                       break;
+       }
+
+       if (json)
+               json_object_object_add(json_vni, "importRTs", json_import_rtl);
+
+       for (ALL_LIST_ELEMENTS(bgp->vrf_export_rtl, node, nnode, ecom)) {
+               ecom_str = ecommunity_ecom2str(ecom,
+                                              ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
+
+               if (json) {
+                       json_object_array_add(json_export_rtl,
+                                             json_object_new_string(ecom_str));
+               } else {
+                       if (listcount(bgp->vrf_export_rtl) > 1)
+                               sprintf(rt_buf, "%s, ...", ecom_str);
+                       else
+                               sprintf(rt_buf, "%s", ecom_str);
+                       vty_out(vty, " %-25s", rt_buf);
+               }
+
+               XFREE(MTYPE_ECOMMUNITY_STR, ecom_str);
+
+               /* If there are multiple export RTs we break here and show only
+                * one */
+               if (!json)
+                       break;
+       }
+
+       if (!json)
+               vty_out(vty, "%-37s", vrf_id_to_name(bgp->vrf_id));
+
+       if (json) {
+               char vni_str[VNI_STR_LEN];
+
+               json_object_object_add(json_vni, "exportRTs", json_export_rtl);
+               snprintf(vni_str, VNI_STR_LEN, "%u", bgp->l3vni);
+               json_object_object_add(json, vni_str, json_vni);
+       } else {
+               vty_out(vty, "\n");
+       }
+}
+
+static void show_vni_entry(struct hash_backet *backet, void *args[])
+{
+       struct vty *vty;
+       json_object *json;
+       json_object *json_vni = NULL;
+       json_object *json_import_rtl = NULL;
+       json_object *json_export_rtl = NULL;
        struct bgpevpn *vpn = (struct bgpevpn *)backet->data;
        char buf1[10];
        char buf2[RD_ADDRSTRLEN];
@@ -440,17 +784,20 @@ static void show_vni_entry(struct hash_backet *backet, void *args[])
 
        if (json) {
                json_object_int_add(json_vni, "vni", vpn->vni);
+               json_object_string_add(json_vni, "type", "L2");
                json_object_string_add(json_vni, "inKernel",
                                       is_vni_live(vpn) ? "True" : "False");
                json_object_string_add(json_vni, "originatorIp",
                                       inet_ntoa(vpn->originator_ip));
+               json_object_string_add(json_vni, "originatorIp",
+                                      inet_ntoa(vpn->originator_ip));
                json_object_string_add(
                        json_vni, "rd",
                        prefix_rd2str(&vpn->prd, buf2, sizeof(buf2)));
        } else {
-               vty_out(vty, "%-1s %-10u %-15s %-21s", buf1, vpn->vni,
-                       inet_ntoa(vpn->originator_ip),
-                       prefix_rd2str(&vpn->prd, buf2, sizeof(buf2)));
+               vty_out(vty, "%-1s %-10u %-4s %-21s",
+                       buf1, vpn->vni, "L2",
+                       prefix_rd2str(&vpn->prd, buf2, RD_ADDRSTRLEN));
        }
 
        for (ALL_LIST_ELEMENTS(vpn->import_rtl, node, nnode, ecom)) {
@@ -502,6 +849,9 @@ static void show_vni_entry(struct hash_backet *backet, void *args[])
                        break;
        }
 
+       if (!json)
+               vty_out(vty, "%-37s", vrf_id_to_name(vpn->tenant_vrf_id));
+
        if (json) {
                char vni_str[VNI_STR_LEN];
 
@@ -1166,40 +1516,15 @@ DEFUN(no_evpnrt5_network,
 }
 
 #if defined(HAVE_CUMULUS)
-static void evpn_rt_delete_auto(struct bgp *bgp, struct bgpevpn *vpn,
-                               struct list *rtl)
-{
-       struct listnode *node, *nnode, *node_to_del;
-       struct ecommunity *ecom, *ecom_auto;
-       struct ecommunity_val eval;
-
-       encode_route_target_as((bgp->as & 0xFFFF), vpn->vni, &eval);
-
-       ecom_auto = ecommunity_new();
-       ecommunity_add_val(ecom_auto, &eval);
-       node_to_del = NULL;
-
-       for (ALL_LIST_ELEMENTS(rtl, node, nnode, ecom)) {
-               if (ecommunity_match(ecom, ecom_auto)) {
-                       ecommunity_free(&ecom);
-                       node_to_del = node;
-               }
-       }
-
-       if (node_to_del)
-               list_delete_node(rtl, node_to_del);
-
-       ecommunity_free(&ecom_auto);
-}
 
 static void evpn_import_rt_delete_auto(struct bgp *bgp, struct bgpevpn *vpn)
 {
-       evpn_rt_delete_auto(bgp, vpn, vpn->import_rtl);
+       evpn_rt_delete_auto(bgp, vpn->vni, vpn->import_rtl);
 }
 
 static void evpn_export_rt_delete_auto(struct bgp *bgp, struct bgpevpn *vpn)
 {
-       evpn_rt_delete_auto(bgp, vpn, vpn->export_rtl);
+       evpn_rt_delete_auto(bgp, vpn->vni, vpn->export_rtl);
 }
 
 /*
@@ -1351,6 +1676,46 @@ static void evpn_unconfigure_export_rt(struct bgp *bgp, struct bgpevpn *vpn,
                bgp_evpn_handle_export_rt_change(bgp, vpn);
 }
 
+/*
+ * Configure RD for VRF
+ */
+static void evpn_configure_vrf_rd(struct bgp *bgp_vrf,
+                                 struct prefix_rd *rd)
+{
+       /* If we have already advertise type-5 routes with a diffrent RD, we
+        * have to delete and withdraw them firs
+        */
+       bgp_evpn_handle_vrf_rd_change(bgp_vrf, 1);
+
+       /* update RD */
+       memcpy(&bgp_vrf->vrf_prd, rd, sizeof(struct prefix_rd));
+       SET_FLAG(bgp_vrf->vrf_flags, BGP_VRF_RD_CFGD);
+
+       /* We have a new RD for VRF.
+        * Advertise all type-5 routes again with the new RD
+        */
+       bgp_evpn_handle_vrf_rd_change(bgp_vrf, 0);
+}
+
+/*
+ * Unconfigure RD for VRF
+ */
+static void evpn_unconfigure_vrf_rd(struct bgp *bgp_vrf)
+{
+       /* If we have already advertise type-5 routes with a diffrent RD, we
+        * have to delete and withdraw them firs
+        */
+       bgp_evpn_handle_vrf_rd_change(bgp_vrf, 1);
+
+       /* fall back to default RD */
+       bgp_evpn_derive_auto_rd_for_vrf(bgp_vrf);
+
+       /* We have a new RD for VRF.
+        * Advertise all type-5 routes again with the new RD
+        */
+       bgp_evpn_handle_vrf_rd_change(bgp_vrf, 0);
+}
+
 /*
  * Configure RD for a VNI (vty handler)
  */
@@ -1403,7 +1768,10 @@ static struct bgpevpn *evpn_create_update_vni(struct bgp *bgp, vni_t vni)
 
        vpn = bgp_evpn_lookup_vni(bgp, vni);
        if (!vpn) {
-               vpn = bgp_evpn_new(bgp, vni, bgp->router_id);
+               /* tenant vrf will be updated when we get local_vni_add from
+                * zebra
+                */
+               vpn = bgp_evpn_new(bgp, vni, bgp->router_id, 0);
                if (!vpn) {
                        zlog_err(
                                "%u: Failed to allocate VNI entry for VNI %u - at Config",
@@ -1452,6 +1820,25 @@ static int evpn_delete_vni(struct bgp *bgp, struct bgpevpn *vpn)
        return 0;
 }
 
+/*
+ * Display import RT mapping to VRFs (vty handler)
+ * bgp_def: default bgp instance
+ */
+static void evpn_show_vrf_import_rts(struct vty *vty,
+                                    struct bgp *bgp_def,
+                                    json_object *json)
+{
+       void *args[2];
+
+       args[0] = vty;
+       args[1] = json;
+
+       hash_iterate(bgp_def->vrf_import_rt_hash,
+                    (void (*)(struct hash_backet *, void *))
+                    show_vrf_import_rt_entry,
+                    args);
+}
+
 /*
  * Display import RT mapping to VNIs (vty handler)
  */
@@ -1778,11 +2165,11 @@ static void evpn_show_route_rd(struct vty *vty, struct bgp *bgp,
                        /* RD header and legend - once overall. */
                        if (rd_header && !json) {
                                vty_out(vty,
-                                       "EVPN type-2 prefix: [2]:[ESI]:[EthTag]:[MAClen]:"
-                                       "[MAC]\n");
+                                       "EVPN type-2 prefix: [2]:[ESI]:[EthTag]:[MAClen]:[MAC]\n");
                                vty_out(vty,
-                                       "EVPN type-3 prefix: [3]:[EthTag]:[IPlen]:"
-                                       "[OrigIP]\n\n");
+                                       "EVPN type-3 prefix: [3]:[EthTag]:[IPlen]:[OrigIP]\n");
+                               vty_out(vty,
+                                       "EVPN type-5 prefix: [5]:[ESI]:[EthTag]:[IPlen]:[IP]\n\n");
                                rd_header = 0;
                        }
 
@@ -1981,10 +2368,26 @@ static void evpn_show_all_routes(struct vty *vty, struct bgp *bgp, int type,
 static void evpn_show_vni(struct vty *vty, struct bgp *bgp, vni_t vni,
                          json_object *json)
 {
+       u_char found = 0;
        struct bgpevpn *vpn;
 
        vpn = bgp_evpn_lookup_vni(bgp, vni);
-       if (!vpn) {
+       if (vpn) {
+               found = 1;
+               display_vni(vty, vpn, json);
+       } else {
+               struct bgp *bgp_temp;
+               struct listnode *node = NULL;
+
+               for (ALL_LIST_ELEMENTS_RO(bm->bgp, node, bgp_temp)) {
+                       if (bgp_temp->l3vni == vni) {
+                               found = 1;
+                               display_l3vni(vty, bgp_temp, json);
+                       }
+               }
+       }
+
+       if (!found) {
                if (json) {
                        vty_out(vty, "{}\n");
                } else {
@@ -1992,8 +2395,6 @@ static void evpn_show_vni(struct vty *vty, struct bgp *bgp, vni_t vni,
                        return;
                }
        }
-
-       display_vni(vty, vpn, json);
 }
 
 /*
@@ -2002,27 +2403,29 @@ static void evpn_show_vni(struct vty *vty, struct bgp *bgp, vni_t vni,
 static void evpn_show_all_vnis(struct vty *vty, struct bgp *bgp,
                               json_object *json)
 {
-       u_int32_t num_vnis;
        void *args[2];
+       struct bgp *bgp_temp = NULL;
+       struct listnode *node;
 
-       num_vnis = hashcount(bgp->vnihash);
-       if (!num_vnis)
-               return;
 
-       if (json) {
-               json_object_int_add(json, "numVnis", num_vnis);
-       } else {
-               vty_out(vty, "Number of VNIs: %u\n", num_vnis);
+       if (!json) {
                vty_out(vty, "Flags: * - Kernel\n");
-               vty_out(vty, "  %-10s %-15s %-21s %-25s %-25s\n", "VNI",
-                       "Orig IP", "RD", "Import RT", "Export RT");
+               vty_out(vty, "  %-10s %-4s %-21s %-25s %-25s %-37s\n", "VNI",
+                       "Type", "RD", "Import RT",
+                       "Export RT", "Tenant VRF");
        }
 
+       /* print all L2 VNIS */
        args[0] = vty;
        args[1] = json;
        hash_iterate(bgp->vnihash,
                     (void (*)(struct hash_backet *, void *))show_vni_entry,
                     args);
+
+       /* print all L3 VNIs */
+       for (ALL_LIST_ELEMENTS_RO(bm->bgp, node, bgp_temp))
+               show_l3vni_entry(vty, bgp_temp, json);
+
 }
 
 /*
@@ -2070,6 +2473,32 @@ static void evpn_unset_advertise_default_gw(struct bgp *bgp,
        return;
 }
 
+/*
+ * evpn - enable advertisement of default g/w
+ */
+static void evpn_set_advertise_subnet(struct bgp *bgp,
+                                     struct bgpevpn *vpn)
+{
+       if (vpn->advertise_subnet)
+               return;
+
+       vpn->advertise_subnet = 1;
+       bgp_zebra_advertise_subnet(bgp, vpn->advertise_subnet, vpn->vni);
+}
+
+/*
+ * evpn - disable advertisement of default g/w
+ */
+static void evpn_unset_advertise_subnet(struct bgp *bgp,
+                                       struct bgpevpn *vpn)
+{
+       if (!vpn->advertise_subnet)
+               return;
+
+       vpn->advertise_subnet = 0;
+       bgp_zebra_advertise_subnet(bgp, vpn->advertise_subnet, vpn->vni);
+}
+
 /*
  * EVPN (VNI advertisement) enabled. Register with zebra.
  */
@@ -2129,6 +2558,9 @@ static void write_vni_config(struct vty *vty, struct bgpevpn *vpn)
                if (vpn->advertise_gw_macip)
                        vty_out(vty, "   advertise-default-gw\n");
 
+               if (vpn->advertise_subnet)
+                       vty_out(vty, "   advertise-subnet\n");
+
                vty_out(vty, "  exit-vni\n");
        }
 }
@@ -2239,6 +2671,209 @@ DEFUN (no_bgp_evpn_advertise_all_vni,
        return CMD_SUCCESS;
 }
 
+DEFUN (bgp_evpn_advertise_vni_subnet,
+       bgp_evpn_advertise_vni_subnet_cmd,
+       "advertise-subnet",
+       "Advertise the subnet corresponding to VNI\n")
+{
+       struct bgp *bgp_vrf = NULL;
+       struct bgp *bgp = VTY_GET_CONTEXT(bgp);
+       VTY_DECLVAR_CONTEXT_SUB(bgpevpn, vpn);
+
+       if (!bgp)
+               return CMD_WARNING;
+
+       if (!vpn)
+               return CMD_WARNING;
+
+       bgp_vrf = bgp_lookup_by_vrf_id(vpn->tenant_vrf_id);
+       if (!bgp_vrf)
+               return CMD_WARNING;
+
+       if (!(advertise_type5_routes(bgp_vrf, AFI_IP) ||
+             advertise_type5_routes(bgp_vrf, AFI_IP6))) {
+               vty_out(vty,
+                       "%%Please enable ip prefix advertisement under l2vpn evpn in %s",
+                       vrf_id_to_name(bgp_vrf->vrf_id));
+               return CMD_WARNING;
+       }
+
+       evpn_set_advertise_subnet(bgp, vpn);
+       return CMD_SUCCESS;
+}
+
+DEFUN (no_bgp_evpn_advertise_vni_subnet,
+       no_bgp_evpn_advertise_vni_subnet_cmd,
+       "no advertise-subnet",
+       NO_STR
+       "Advertise All local VNIs\n")
+{
+       struct bgp *bgp = VTY_GET_CONTEXT(bgp);
+       VTY_DECLVAR_CONTEXT_SUB(bgpevpn, vpn);
+
+       if (!bgp)
+               return CMD_WARNING;
+
+       if (!vpn)
+               return CMD_WARNING;
+
+       evpn_unset_advertise_subnet(bgp, vpn);
+       return CMD_SUCCESS;
+}
+
+DEFUN (bgp_evpn_advertise_type5,
+       bgp_evpn_advertise_type5_cmd,
+       "advertise " BGP_AFI_CMD_STR "" BGP_SAFI_CMD_STR " [route-map WORD]",
+       "Advertise prefix routes\n"
+       BGP_AFI_HELP_STR
+       BGP_SAFI_HELP_STR
+       "route-map for filtering specific routes\n"
+       "Name of the route map\n")
+{
+       struct bgp *bgp_vrf = VTY_GET_CONTEXT(bgp); /* bgp vrf instance */
+       int idx_afi = 0;
+       int idx_safi = 0;
+       int idx_rmap = 0;
+       afi_t afi = 0;
+       safi_t safi = 0;
+       int ret = 0;
+       int rmap_changed = 0;
+
+       argv_find_and_parse_afi(argv, argc, &idx_afi, &afi);
+       argv_find_and_parse_safi(argv, argc, &idx_safi, &safi);
+       ret = argv_find(argv, argc, "route-map", &idx_rmap);
+       if (ret) {
+               if (!bgp_vrf->adv_cmd_rmap[afi][safi].name)
+                       rmap_changed = 1;
+               else if (strcmp(argv[idx_rmap + 1]->arg,
+                               bgp_vrf->adv_cmd_rmap[afi][safi].name) != 0)
+                       rmap_changed = 1;
+       } else if (bgp_vrf->adv_cmd_rmap[afi][safi].name) {
+               rmap_changed = 1;
+       }
+
+       if (!(afi == AFI_IP) || (afi == AFI_IP6)) {
+               vty_out(vty,
+                       "%%only ipv4 or ipv6 address families are supported");
+               return CMD_WARNING;
+       }
+
+       if (safi != SAFI_UNICAST) {
+               vty_out(vty,
+                       "%%only ipv4 unicast or ipv6 unicast are supported");
+               return CMD_WARNING;
+       }
+
+       if (afi == AFI_IP) {
+
+               /* if we are already advertising ipv4 prefix as type-5
+                * nothing to do
+                */
+               if (!rmap_changed && CHECK_FLAG(bgp_vrf->vrf_flags,
+                                               BGP_VRF_ADVERTISE_IPV4_IN_EVPN))
+                       return CMD_WARNING;
+               SET_FLAG(bgp_vrf->vrf_flags,
+                        BGP_VRF_ADVERTISE_IPV4_IN_EVPN);
+       } else {
+
+               /* if we are already advertising ipv6 prefix as type-5
+                * nothing to do
+                */
+               if (!rmap_changed && CHECK_FLAG(bgp_vrf->vrf_flags,
+                                               BGP_VRF_ADVERTISE_IPV6_IN_EVPN))
+                       return CMD_WARNING;
+               SET_FLAG(bgp_vrf->vrf_flags,
+                        BGP_VRF_ADVERTISE_IPV6_IN_EVPN);
+       }
+
+       if (rmap_changed) {
+               bgp_evpn_withdraw_type5_routes(bgp_vrf, afi, safi);
+               if (bgp_vrf->adv_cmd_rmap[afi][safi].name) {
+                       XFREE(MTYPE_ROUTE_MAP_NAME,
+                             bgp_vrf->adv_cmd_rmap[afi][safi].name);
+                       bgp_vrf->adv_cmd_rmap[afi][safi].name = NULL;
+                       bgp_vrf->adv_cmd_rmap[afi][safi].map = NULL;
+               }
+       }
+
+       /* set the route-map for advertise command */
+       if (ret && argv[idx_rmap + 1]->arg) {
+               bgp_vrf->adv_cmd_rmap[afi][safi].name =
+                       XSTRDUP(MTYPE_ROUTE_MAP_NAME,
+                               argv[idx_rmap + 1]->arg);
+               bgp_vrf->adv_cmd_rmap[afi][safi].map =
+                       route_map_lookup_by_name(argv[idx_rmap + 1]->arg);
+       }
+
+       /* advertise type-5 routes */
+       bgp_evpn_advertise_type5_routes(bgp_vrf, afi, safi);
+       return CMD_SUCCESS;
+}
+
+DEFUN (no_bgp_evpn_advertise_type5,
+       no_bgp_evpn_advertise_type5_cmd,
+       "no advertise " BGP_AFI_CMD_STR "" BGP_SAFI_CMD_STR,
+       NO_STR
+       "Advertise prefix routes\n"
+       BGP_AFI_HELP_STR
+       BGP_SAFI_HELP_STR)
+{
+       struct bgp *bgp_vrf = VTY_GET_CONTEXT(bgp); /* bgp vrf instance */
+       int idx_afi = 0;
+       int idx_safi = 0;
+       afi_t afi = 0;
+       safi_t safi = 0;
+
+       argv_find_and_parse_afi(argv, argc, &idx_afi, &afi);
+       argv_find_and_parse_safi(argv, argc, &idx_safi, &safi);
+
+       if (!(afi == AFI_IP) || (afi == AFI_IP6)) {
+               vty_out(vty,
+                       "%%only ipv4 or ipv6 address families are supported");
+               return CMD_WARNING;
+       }
+
+       if (safi != SAFI_UNICAST) {
+               vty_out(vty,
+                       "%%only ipv4 unicast or ipv6 unicast are supported");
+               return CMD_WARNING;
+       }
+
+       if (afi == AFI_IP) {
+
+               /* if we are already advertising ipv4 prefix as type-5
+                * nothing to do
+                */
+               if (CHECK_FLAG(bgp_vrf->vrf_flags,
+                              BGP_VRF_ADVERTISE_IPV4_IN_EVPN)) {
+                       bgp_evpn_withdraw_type5_routes(bgp_vrf, afi, safi);
+                       UNSET_FLAG(bgp_vrf->vrf_flags,
+                                  BGP_VRF_ADVERTISE_IPV4_IN_EVPN);
+               }
+       } else {
+
+               /* if we are already advertising ipv6 prefix as type-5
+                * nothing to do
+                */
+               if (CHECK_FLAG(bgp_vrf->vrf_flags,
+                              BGP_VRF_ADVERTISE_IPV6_IN_EVPN)) {
+                       bgp_evpn_withdraw_type5_routes(bgp_vrf, afi, safi);
+                       UNSET_FLAG(bgp_vrf->vrf_flags,
+                                  BGP_VRF_ADVERTISE_IPV6_IN_EVPN);
+               }
+       }
+
+       /* clear the route-map information for advertise ipv4/ipv6 unicast */
+       if (bgp_vrf->adv_cmd_rmap[afi][safi].name) {
+               XFREE(MTYPE_ROUTE_MAP_NAME,
+                     bgp_vrf->adv_cmd_rmap[afi][safi].name);
+               bgp_vrf->adv_cmd_rmap[afi][safi].name = NULL;
+               bgp_vrf->adv_cmd_rmap[afi][safi].map = NULL;
+       }
+
+       return CMD_SUCCESS;
+}
+
 /*
  * Display VNI information - for all or a specific VNI
  */
@@ -2253,16 +2888,21 @@ DEFUN(show_bgp_l2vpn_evpn_vni,
       "VNI number\n"
       JSON_STR)
 {
-       struct bgp *bgp;
+       struct bgp *bgp_def;
        vni_t vni;
        int idx = 0;
        u_char uj = 0;
        json_object *json = NULL;
+       u_int32_t num_l2vnis = 0;
+       u_int32_t num_l3vnis = 0;
+       uint32_t num_vnis = 0;
+       struct listnode *node = NULL;
+       struct bgp *bgp_temp = NULL;
 
        uj = use_json(argc, argv);
 
-       bgp = bgp_get_default();
-       if (!bgp)
+       bgp_def = bgp_get_default();
+       if (!bgp_def)
                return CMD_WARNING;
 
        if (!argv_find(argv, argc, "evpn", &idx))
@@ -2272,27 +2912,36 @@ DEFUN(show_bgp_l2vpn_evpn_vni,
                json = json_object_new_object();
 
        if ((uj && argc == ((idx + 1) + 2)) || (!uj && argc == (idx + 1) + 1)) {
+
+               num_l2vnis = hashcount(bgp_def->vnihash);
+
+               for (ALL_LIST_ELEMENTS_RO(bm->bgp, node, bgp_temp)) {
+                       if (bgp_temp->l3vni)
+                               num_l3vnis++;
+               }
+               num_vnis = num_l2vnis + num_l3vnis;
                if (uj) {
                        json_object_string_add(json, "advertiseGatewayMacip",
-                                              bgp->advertise_gw_macip
+                                              bgp_def->advertise_gw_macip
                                                       ? "Enabled"
                                                       : "Disabled");
                        json_object_string_add(json, "advertiseAllVnis",
-                                              bgp->advertise_all_vni
+                                              is_evpn_enabled()
                                                       ? "Enabled"
                                                       : "Disabled");
+                       json_object_int_add(json, "numVnis", num_vnis);
+                       json_object_int_add(json, "numL2Vnis", num_l2vnis);
+                       json_object_int_add(json, "numL3Vnis", num_l3vnis);
                } else {
                        vty_out(vty, "Advertise Gateway Macip: %s\n",
-                               bgp->advertise_gw_macip ? "Enabled"
+                               bgp_def->advertise_gw_macip ? "Enabled"
                                                        : "Disabled");
-
-                       /* Display all VNIs */
                        vty_out(vty, "Advertise All VNI flag: %s\n",
-                               bgp->advertise_all_vni ? "Enabled"
-                                                      : "Disabled");
+                               is_evpn_enabled() ? "Enabled" : "Disabled");
+                       vty_out(vty, "Number of L2 VNIs: %u\n", num_l2vnis);
+                       vty_out(vty, "Number of L3 VNIs: %u\n", num_l3vnis);
                }
-
-               evpn_show_all_vnis(vty, bgp, json);
+               evpn_show_all_vnis(vty, bgp_def, json);
        } else {
                int vni_idx = 0;
 
@@ -2301,7 +2950,7 @@ DEFUN(show_bgp_l2vpn_evpn_vni,
 
                /* Display specific VNI */
                vni = strtoul(argv[vni_idx + 1]->arg, NULL, 10);
-               evpn_show_vni(vty, bgp, vni, json);
+               evpn_show_vni(vty, bgp_def, vni, json);
        }
 
        if (uj) {
@@ -2335,7 +2984,7 @@ DEFUN(show_bgp_l2vpn_evpn_summary,
  */
 DEFUN(show_bgp_l2vpn_evpn_route,
       show_bgp_l2vpn_evpn_route_cmd,
-      "show bgp l2vpn evpn route [type <macip|multicast>] [json]",
+      "show bgp l2vpn evpn route [type <macip|multicast|prefix>] [json]",
       SHOW_STR
       BGP_STR
       L2VPN_HELP_STR
@@ -2344,6 +2993,7 @@ DEFUN(show_bgp_l2vpn_evpn_route,
       "Specify Route type\n"
       "MAC-IP (Type-2) route\n"
       "Multicast (Type-3) route\n"
+      "Prefix route\n"
       JSON_STR)
 {
        struct bgp *bgp;
@@ -2368,6 +3018,8 @@ DEFUN(show_bgp_l2vpn_evpn_route,
                        type = BGP_EVPN_MAC_IP_ROUTE;
                else if (strncmp(argv[type_idx + 1]->arg, "mu", 2) == 0)
                        type = BGP_EVPN_IMET_ROUTE;
+               else if (strncmp(argv[type_idx + 1]->arg, "pr", 2) == 0)
+                       type = BGP_EVPN_IP_PREFIX_ROUTE;
                else
                        return CMD_WARNING;
        }
@@ -2379,7 +3031,6 @@ DEFUN(show_bgp_l2vpn_evpn_route,
                                             json, JSON_C_TO_STRING_PRETTY));
                json_object_free(json);
        }
-
        return CMD_SUCCESS;
 }
 
@@ -2388,7 +3039,7 @@ DEFUN(show_bgp_l2vpn_evpn_route,
  */
 DEFUN(show_bgp_l2vpn_evpn_route_rd,
       show_bgp_l2vpn_evpn_route_rd_cmd,
-      "show bgp l2vpn evpn route rd ASN:NN_OR_IP-ADDRESS:NN [type <macip|multicast>] [json]",
+      "show bgp l2vpn evpn route rd ASN:NN_OR_IP-ADDRESS:NN [type <macip|multicast|prefix>] [json]",
       SHOW_STR
       BGP_STR
       L2VPN_HELP_STR
@@ -2399,6 +3050,7 @@ DEFUN(show_bgp_l2vpn_evpn_route_rd,
       "Specify Route type\n"
       "MAC-IP (Type-2) route\n"
       "Multicast (Type-3) route\n"
+      "Prefix route\n"
       JSON_STR)
 {
        struct bgp *bgp;
@@ -2436,6 +3088,8 @@ DEFUN(show_bgp_l2vpn_evpn_route_rd,
                        type = BGP_EVPN_MAC_IP_ROUTE;
                else if (strncmp(argv[type_idx + 1]->arg, "mu", 2) == 0)
                        type = BGP_EVPN_IMET_ROUTE;
+               else if (strncmp(argv[type_idx + 1]->arg, "pr", 2) == 0)
+                       type = BGP_EVPN_IP_PREFIX_ROUTE;
                else
                        return CMD_WARNING;
        }
@@ -2518,13 +3172,40 @@ DEFUN(show_bgp_l2vpn_evpn_route_rd_macip,
                }
        }
 
-       evpn_show_route_rd_macip(vty, bgp, &prd, &mac, &ip, json);
+       evpn_show_route_rd_macip(vty, bgp, &prd, &mac, &ip, json);
+
+       if (uj) {
+               vty_out(vty, "%s\n", json_object_to_json_string_ext(
+                                            json, JSON_C_TO_STRING_PRETTY));
+               json_object_free(json);
+       }
+
+       return CMD_SUCCESS;
+}
+
+/*
+ * Display per-VRF EVPN routing table.
+ */
+DEFUN(show_bgp_l2vpn_evpn_route_vrf, show_bgp_l2vpn_evpn_route_vrf_cmd,
+      "show bgp l2vpn evpn route vrf VRFNAME",
+      SHOW_STR
+      BGP_STR
+      L2VPN_HELP_STR
+      EVPN_HELP_STR
+      "EVPN route information\n"
+      "VRF\n"
+      "VRF Name\n")
+{
+       int vrf_idx = 6;
+       char *vrf_name = NULL;
+       struct bgp *bgp_vrf = NULL;
+
+       vrf_name = argv[vrf_idx]->arg;
+       bgp_vrf = bgp_lookup_by_name(vrf_name);
+       if (!bgp_vrf)
+               return CMD_WARNING;
 
-       if (uj) {
-               vty_out(vty, "%s\n", json_object_to_json_string_ext(
-                                            json, JSON_C_TO_STRING_PRETTY));
-               json_object_free(json);
-       }
+       evpn_show_vrf_routes(vty, bgp_vrf);
 
        return CMD_SUCCESS;
 }
@@ -2784,6 +3465,42 @@ DEFUN(show_bgp_l2vpn_evpn_route_vni_all,
        return CMD_SUCCESS;
 }
 
+/*
+ * Display EVPN import route-target hash table
+ */
+DEFUN(show_bgp_l2vpn_evpn_vrf_import_rt,
+      show_bgp_l2vpn_evpn_vrf_import_rt_cmd,
+      "show bgp l2vpn evpn vrf-import-rt [json]",
+      SHOW_STR
+      BGP_STR
+      L2VPN_HELP_STR
+      EVPN_HELP_STR
+      "Show vrf import route target\n"
+      JSON_STR)
+{
+       u_char uj = 0;
+       struct bgp *bgp_def = NULL;
+       json_object *json = NULL;
+
+       bgp_def = bgp_get_default();
+       if (!bgp_def)
+               return CMD_WARNING;
+
+       uj = use_json(argc, argv);
+       if (uj)
+               json = json_object_new_object();
+
+       evpn_show_vrf_import_rts(vty, bgp_def, json);
+
+       if (uj) {
+               vty_out(vty, "%s\n", json_object_to_json_string_ext(
+                                            json, JSON_C_TO_STRING_PRETTY));
+               json_object_free(json);
+       }
+
+       return CMD_SUCCESS;
+}
+
 /*
  * Display EVPN import route-target hash table
  */
@@ -2978,6 +3695,91 @@ DEFUN_NOSH (exit_vni,
        return CMD_SUCCESS;
 }
 
+DEFUN (bgp_evpn_vrf_rd,
+       bgp_evpn_vrf_rd_cmd,
+       "rd ASN:NN_OR_IP-ADDRESS:NN",
+       "Route Distinguisher\n"
+       "ASN:XX or A.B.C.D:XX\n")
+{
+       int ret;
+       struct prefix_rd prd;
+       struct bgp *bgp_vrf = VTY_GET_CONTEXT(bgp);
+
+       if (!bgp_vrf)
+               return CMD_WARNING;
+
+       ret = str2prefix_rd(argv[1]->arg, &prd);
+       if (!ret) {
+               vty_out(vty, "%% Malformed Route Distinguisher\n");
+               return CMD_WARNING;
+       }
+
+       /* If same as existing value, there is nothing more to do. */
+       if (bgp_evpn_vrf_rd_matches_existing(bgp_vrf, &prd))
+               return CMD_SUCCESS;
+
+       /* Configure or update the RD. */
+       evpn_configure_vrf_rd(bgp_vrf, &prd);
+       return CMD_SUCCESS;
+}
+
+DEFUN (no_bgp_evpn_vrf_rd,
+       no_bgp_evpn_vrf_rd_cmd,
+       "no rd ASN:NN_OR_IP-ADDRESS:NN",
+       NO_STR
+       "Route Distinguisher\n"
+       "ASN:XX or A.B.C.D:XX\n")
+{
+       int ret;
+       struct prefix_rd prd;
+       struct bgp *bgp_vrf = VTY_GET_CONTEXT(bgp);
+
+       if (!bgp_vrf)
+               return CMD_WARNING;
+
+       ret = str2prefix_rd(argv[2]->arg, &prd);
+       if (!ret) {
+               vty_out(vty, "%% Malformed Route Distinguisher\n");
+               return CMD_WARNING;
+       }
+
+       /* Check if we should disallow. */
+       if (!is_vrf_rd_configured(bgp_vrf)) {
+               vty_out(vty, "%% RD is not configured for this VRF\n");
+               return CMD_WARNING;
+       }
+
+       if (!bgp_evpn_vrf_rd_matches_existing(bgp_vrf, &prd)) {
+               vty_out(vty,
+                       "%% RD specified does not match configuration for this VRF\n");
+               return CMD_WARNING;
+       }
+
+       evpn_unconfigure_vrf_rd(bgp_vrf);
+       return CMD_SUCCESS;
+}
+
+DEFUN (no_bgp_evpn_vrf_rd_without_val,
+       no_bgp_evpn_vrf_rd_without_val_cmd,
+       "no rd",
+       NO_STR
+       "Route Distinguisher\n")
+{
+       struct bgp *bgp_vrf = VTY_GET_CONTEXT(bgp);
+
+       if (!bgp_vrf)
+               return CMD_WARNING;
+
+       /* Check if we should disallow. */
+       if (!is_vrf_rd_configured(bgp_vrf)) {
+               vty_out(vty, "%% RD is not configured for this VRF\n");
+               return CMD_WARNING;
+       }
+
+       evpn_unconfigure_vrf_rd(bgp_vrf);
+       return CMD_SUCCESS;
+}
+
 DEFUN (bgp_evpn_vni_rd,
        bgp_evpn_vni_rd_cmd,
        "rd ASN:NN_OR_IP-ADDRESS:NN",
@@ -3084,6 +3886,278 @@ static int bgp_evpn_rt_matches_existing(struct list *rtl,
        return 0;
 }
 
+/* display L3VNI related info for a VRF instance */
+DEFUN (show_bgp_vrf_l3vni_info,
+       show_bgp_vrf_l3vni_info_cmd,
+       "show bgp vrf VRFNAME vni [json]",
+       SHOW_STR
+       BGP_STR
+       "show bgp vrf\n"
+       "VRF Name\n"
+       "L3-VNI\n"
+       JSON_STR)
+{
+       char buf[ETHER_ADDR_STRLEN];
+       char buf1[INET6_ADDRSTRLEN];
+       int idx_vrf = 3;
+       const char *name = NULL;
+       struct bgp *bgp = NULL;
+       struct listnode *node = NULL;
+       struct bgpevpn *vpn = NULL;
+       struct ecommunity *ecom = NULL;
+       json_object *json = NULL;
+       json_object *json_vnis = NULL;
+       json_object *json_export_rts = NULL;
+       json_object *json_import_rts = NULL;
+       u_char uj = use_json(argc, argv);
+
+       if (uj) {
+               json = json_object_new_object();
+               json_vnis = json_object_new_array();
+               json_export_rts = json_object_new_array();
+               json_import_rts = json_object_new_array();
+       }
+
+       name = argv[idx_vrf]->arg;
+       bgp = bgp_lookup_by_name(name);
+       if (!bgp) {
+               if (!uj)
+                       vty_out(vty, "BGP instance for VRF %s not found",
+                               name);
+               else {
+                       json_object_string_add(json, "warning",
+                                              "BGP instance not found");
+                       vty_out(vty, "%s\n",
+                               json_object_to_json_string(json));
+                       json_object_free(json);
+               }
+               return CMD_WARNING;
+       }
+
+       if (!json) {
+               vty_out(vty, "BGP VRF: %s\n", name);
+               vty_out(vty, "  Local-Ip: %s\n",
+                       inet_ntoa(bgp->originator_ip));
+               vty_out(vty, "  L3-VNI: %u\n", bgp->l3vni);
+               vty_out(vty, "  Rmac: %s\n",
+                       prefix_mac2str(&bgp->rmac, buf, sizeof(buf)));
+               vty_out(vty, "  L2-VNI List:\n");
+               vty_out(vty, "    ");
+               for (ALL_LIST_ELEMENTS_RO(bgp->l2vnis, node, vpn))
+                       vty_out(vty, "%u  ", vpn->vni);
+               vty_out(vty, "\n");
+               vty_out(vty, "  Export-RTs:\n");
+               vty_out(vty, "    ");
+               for (ALL_LIST_ELEMENTS_RO(bgp->vrf_export_rtl, node, ecom))
+                       vty_out(vty, "%s  ", ecommunity_str(ecom));
+               vty_out(vty, "\n");
+               vty_out(vty, "  Import-RTs:\n");
+               vty_out(vty, "    ");
+               for (ALL_LIST_ELEMENTS_RO(bgp->vrf_import_rtl, node, ecom))
+                       vty_out(vty, "%s  ", ecommunity_str(ecom));
+               vty_out(vty, "\n");
+               vty_out(vty, "  RD: %s\n",
+                       prefix_rd2str(&bgp->vrf_prd, buf1, RD_ADDRSTRLEN));
+       } else {
+               json_object_string_add(json, "vrf", name);
+               json_object_string_add(json, "local-ip",
+                                      inet_ntoa(bgp->originator_ip));
+               json_object_int_add(json, "l3vni", bgp->l3vni);
+               json_object_string_add(json, "rmac",
+                                      prefix_mac2str(&bgp->rmac, buf,
+                                                     sizeof(buf)));
+               /* list of l2vnis */
+               for (ALL_LIST_ELEMENTS_RO(bgp->l2vnis, node, vpn))
+                       json_object_array_add(json_vnis,
+                                             json_object_new_int(vpn->vni));
+               json_object_object_add(json, "l2vnis", json_vnis);
+
+               /* export rts */
+               for (ALL_LIST_ELEMENTS_RO(bgp->vrf_export_rtl, node, ecom))
+                       json_object_array_add(json_export_rts,
+                                             json_object_new_string(
+                                                       ecommunity_str(ecom)));
+               json_object_object_add(json, "export-rts", json_export_rts);
+
+               /* import rts */
+               for (ALL_LIST_ELEMENTS_RO(bgp->vrf_import_rtl, node, ecom))
+                       json_object_array_add(json_import_rts,
+                                             json_object_new_string(
+                                                       ecommunity_str(ecom)));
+               json_object_object_add(json, "import-rts", json_import_rts);
+               json_object_string_add(
+                       json, "rd",
+                       prefix_rd2str(&bgp->vrf_prd, buf1, RD_ADDRSTRLEN));
+
+       }
+
+       if (uj) {
+               vty_out(vty, "%s\n", json_object_to_json_string_ext(
+                                            json, JSON_C_TO_STRING_PRETTY));
+               json_object_free(json);
+       }
+       return CMD_SUCCESS;
+}
+
+/* import/export rt for l3vni-vrf */
+DEFUN (bgp_evpn_vrf_rt,
+       bgp_evpn_vrf_rt_cmd,
+       "route-target <both|import|export> RT",
+       "Route Target\n"
+       "import and export\n"
+       "import\n"
+       "export\n"
+       "Route target (A.B.C.D:MN|EF:OPQR|GHJK:MN)\n")
+{
+       int rt_type;
+       struct bgp *bgp = VTY_GET_CONTEXT(bgp);
+       struct ecommunity *ecomadd = NULL;
+
+       if (!bgp)
+               return CMD_WARNING;
+
+       if (!strcmp(argv[1]->arg, "import"))
+               rt_type = RT_TYPE_IMPORT;
+       else if (!strcmp(argv[1]->arg, "export"))
+               rt_type = RT_TYPE_EXPORT;
+       else if (!strcmp(argv[1]->arg, "both"))
+               rt_type = RT_TYPE_BOTH;
+       else {
+               vty_out(vty, "%% Invalid Route Target type\n");
+               return CMD_WARNING;
+       }
+
+       /* Add/update the import route-target */
+       if (rt_type == RT_TYPE_BOTH || rt_type == RT_TYPE_IMPORT) {
+               ecomadd = ecommunity_str2com(argv[2]->arg,
+                                            ECOMMUNITY_ROUTE_TARGET, 0);
+               if (!ecomadd) {
+                       vty_out(vty, "%% Malformed Route Target list\n");
+                       return CMD_WARNING;
+               }
+               ecommunity_str(ecomadd);
+
+               /* Do nothing if we already have this import route-target */
+               if (!bgp_evpn_rt_matches_existing(bgp->vrf_import_rtl,
+                                                 ecomadd))
+                       bgp_evpn_configure_import_rt_for_vrf(bgp, ecomadd);
+       }
+
+       /* Add/update the export route-target */
+       if (rt_type == RT_TYPE_BOTH || rt_type == RT_TYPE_EXPORT) {
+               ecomadd = ecommunity_str2com(argv[2]->arg,
+                                            ECOMMUNITY_ROUTE_TARGET, 0);
+               if (!ecomadd) {
+                       vty_out(vty, "%% Malformed Route Target list\n");
+                       return CMD_WARNING;
+               }
+               ecommunity_str(ecomadd);
+
+               /* Do nothing if we already have this export route-target */
+               if (!bgp_evpn_rt_matches_existing(bgp->vrf_export_rtl,
+                                                 ecomadd))
+                       bgp_evpn_configure_export_rt_for_vrf(bgp, ecomadd);
+       }
+
+       return CMD_SUCCESS;
+}
+
+DEFUN (no_bgp_evpn_vrf_rt,
+       no_bgp_evpn_vrf_rt_cmd,
+       "no route-target <both|import|export> RT",
+       NO_STR
+       "Route Target\n"
+       "import and export\n"
+       "import\n"
+       "export\n"
+       "ASN:XX or A.B.C.D:XX\n")
+{
+       struct bgp *bgp = VTY_GET_CONTEXT(bgp);
+       int rt_type, found_ecomdel;
+       struct ecommunity *ecomdel = NULL;
+
+       if (!bgp)
+               return CMD_WARNING;
+
+       if (!strcmp(argv[2]->arg, "import"))
+               rt_type = RT_TYPE_IMPORT;
+       else if (!strcmp(argv[2]->arg, "export"))
+               rt_type = RT_TYPE_EXPORT;
+       else if (!strcmp(argv[2]->arg, "both"))
+               rt_type = RT_TYPE_BOTH;
+       else {
+               vty_out(vty, "%% Invalid Route Target type\n");
+               return CMD_WARNING;
+       }
+
+       if (rt_type == RT_TYPE_IMPORT) {
+               if (!CHECK_FLAG(bgp->vrf_flags, BGP_VRF_IMPORT_RT_CFGD)) {
+                       vty_out(vty,
+                               "%% Import RT is not configured for this VRF\n");
+                       return CMD_WARNING;
+               }
+       } else if (rt_type == RT_TYPE_EXPORT) {
+               if (!CHECK_FLAG(bgp->vrf_flags, BGP_VRF_EXPORT_RT_CFGD)) {
+                       vty_out(vty,
+                               "%% Export RT is not configured for this VRF\n");
+                       return CMD_WARNING;
+               }
+       } else if (rt_type == RT_TYPE_BOTH) {
+               if (!CHECK_FLAG(bgp->vrf_flags, BGP_VRF_IMPORT_RT_CFGD)
+                   && !CHECK_FLAG(bgp->vrf_flags, BGP_VRF_EXPORT_RT_CFGD)) {
+                       vty_out(vty,
+                               "%% Import/Export RT is not configured for this VRF\n");
+                       return CMD_WARNING;
+               }
+       }
+
+       ecomdel = ecommunity_str2com(argv[3]->arg, ECOMMUNITY_ROUTE_TARGET, 0);
+       if (!ecomdel) {
+               vty_out(vty, "%% Malformed Route Target list\n");
+               return CMD_WARNING;
+       }
+       ecommunity_str(ecomdel);
+
+       if (rt_type == RT_TYPE_IMPORT) {
+               if (!bgp_evpn_rt_matches_existing(bgp->vrf_import_rtl,
+                                                 ecomdel)) {
+                       vty_out(vty,
+                               "%% RT specified does not match configuration for this VRF\n");
+                       return CMD_WARNING;
+               }
+               bgp_evpn_unconfigure_import_rt_for_vrf(bgp, ecomdel);
+       } else if (rt_type == RT_TYPE_EXPORT) {
+               if (!bgp_evpn_rt_matches_existing(bgp->vrf_export_rtl,
+                                                 ecomdel)) {
+                       vty_out(vty,
+                               "%% RT specified does not match configuration for this VRF\n");
+                       return CMD_WARNING;
+               }
+               bgp_evpn_unconfigure_export_rt_for_vrf(bgp, ecomdel);
+       } else if (rt_type == RT_TYPE_BOTH) {
+               found_ecomdel = 0;
+
+               if (bgp_evpn_rt_matches_existing(bgp->vrf_import_rtl,
+                                                ecomdel)) {
+                       bgp_evpn_unconfigure_import_rt_for_vrf(bgp, ecomdel);
+                       found_ecomdel = 1;
+               }
+
+               if (bgp_evpn_rt_matches_existing(bgp->vrf_export_rtl,
+                                                ecomdel)) {
+                       bgp_evpn_unconfigure_export_rt_for_vrf(bgp, ecomdel);
+                       found_ecomdel = 1;
+               }
+
+               if (!found_ecomdel) {
+                       vty_out(vty,
+                               "%% RT specified does not match configuration for this VRF\n");
+                       return CMD_WARNING;
+               }
+       }
+
+       return CMD_SUCCESS;
+}
 
 DEFUN (bgp_evpn_vni_rt,
        bgp_evpn_vni_rt_cmd,
@@ -3306,6 +4380,12 @@ void bgp_config_write_evpn_info(struct vty *vty, struct bgp *bgp, afi_t afi,
 
        if (bgp->advertise_gw_macip)
                vty_out(vty, "  advertise-default-gw\n");
+
+       if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_ADVERTISE_IPV4_IN_EVPN))
+               vty_out(vty, "  advertise ipv4 unicast\n");
+
+       if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_ADVERTISE_IPV6_IN_EVPN))
+               vty_out(vty, "  advertise ipv6 unicast\n");
 }
 
 void bgp_ethernetvpn_init(void)
@@ -3333,6 +4413,8 @@ void bgp_ethernetvpn_init(void)
        install_element(BGP_EVPN_NODE, &no_bgp_evpn_advertise_all_vni_cmd);
        install_element(BGP_EVPN_NODE, &bgp_evpn_advertise_default_gw_cmd);
        install_element(BGP_EVPN_NODE, &no_bgp_evpn_advertise_default_gw_cmd);
+       install_element(BGP_EVPN_NODE, &bgp_evpn_advertise_type5_cmd);
+       install_element(BGP_EVPN_NODE, &no_bgp_evpn_advertise_type5_cmd);
 
        /* "show bgp l2vpn evpn" commands. */
        install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_vni_cmd);
@@ -3341,11 +4423,13 @@ void bgp_ethernetvpn_init(void)
        install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_route_rd_cmd);
        install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_route_rd_macip_cmd);
        install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_route_vni_cmd);
+       install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_route_vrf_cmd);
        install_element(VIEW_NODE,
                        &show_bgp_l2vpn_evpn_route_vni_multicast_cmd);
        install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_route_vni_macip_cmd);
        install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_route_vni_all_cmd);
        install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_import_rt_cmd);
+       install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_vrf_import_rt_cmd);
 
        /* "show bgp evpn" commands. */
        install_element(VIEW_NODE, &show_bgp_evpn_vni_cmd);
@@ -3358,6 +4442,7 @@ void bgp_ethernetvpn_init(void)
        install_element(VIEW_NODE, &show_bgp_evpn_route_vni_macip_cmd);
        install_element(VIEW_NODE, &show_bgp_evpn_route_vni_all_cmd);
        install_element(VIEW_NODE, &show_bgp_evpn_import_rt_cmd);
+       install_element(VIEW_NODE, &show_bgp_vrf_l3vni_info_cmd);
 
        install_element(BGP_EVPN_NODE, &bgp_evpn_vni_cmd);
        install_element(BGP_EVPN_NODE, &no_bgp_evpn_vni_cmd);
@@ -3368,9 +4453,17 @@ void bgp_ethernetvpn_init(void)
        install_element(BGP_EVPN_VNI_NODE, &bgp_evpn_vni_rt_cmd);
        install_element(BGP_EVPN_VNI_NODE, &no_bgp_evpn_vni_rt_cmd);
        install_element(BGP_EVPN_VNI_NODE, &no_bgp_evpn_vni_rt_without_val_cmd);
+       install_element(BGP_EVPN_NODE, &bgp_evpn_vrf_rd_cmd);
+       install_element(BGP_EVPN_NODE, &no_bgp_evpn_vrf_rd_cmd);
+       install_element(BGP_NODE, &no_bgp_evpn_vrf_rd_without_val_cmd);
+       install_element(BGP_EVPN_NODE, &bgp_evpn_vrf_rt_cmd);
+       install_element(BGP_EVPN_NODE, &no_bgp_evpn_vrf_rt_cmd);
        install_element(BGP_EVPN_VNI_NODE,
                        &bgp_evpn_advertise_default_gw_vni_cmd);
        install_element(BGP_EVPN_VNI_NODE,
                        &no_bgp_evpn_advertise_default_gw_vni_cmd);
+       install_element(BGP_EVPN_VNI_NODE, &bgp_evpn_advertise_vni_subnet_cmd);
+       install_element(BGP_EVPN_VNI_NODE,
+                       &no_bgp_evpn_advertise_vni_subnet_cmd);
 #endif
 }
index 9e58e466e1b010674dc0fe54766036153c0f47c7..de453de0c82676328a60e024931f34ae66fdfcf3 100644 (file)
@@ -27,6 +27,7 @@
 #include "thread.h"
 #include "log.h"
 #include "stream.h"
+#include "ringbuf.h"
 #include "memory.h"
 #include "plist.h"
 #include "workqueue.h"
@@ -155,7 +156,6 @@ static struct peer *peer_xfer_conn(struct peer *from_peer)
 
                stream_fifo_clean(peer->ibuf);
                stream_fifo_clean(peer->obuf);
-               stream_reset(peer->ibuf_work);
 
                /*
                 * this should never happen, since bgp_process_packet() is the
@@ -183,7 +183,9 @@ static struct peer *peer_xfer_conn(struct peer *from_peer)
                        stream_fifo_push(peer->ibuf,
                                         stream_fifo_pop(from_peer->ibuf));
 
-               stream_copy(peer->ibuf_work, from_peer->ibuf_work);
+               ringbuf_wipe(peer->ibuf_work);
+               ringbuf_copy(peer->ibuf_work, from_peer->ibuf_work,
+                            ringbuf_remain(from_peer->ibuf_work));
        }
        pthread_mutex_unlock(&from_peer->io_mtx);
        pthread_mutex_unlock(&peer->io_mtx);
@@ -264,14 +266,16 @@ static struct peer *peer_xfer_conn(struct peer *from_peer)
                }
        }
 
+
+       // Note: peer_xfer_stats() must be called with I/O turned OFF
+       if (from_peer)
+               peer_xfer_stats(peer, from_peer);
+
        bgp_reads_on(peer);
        bgp_writes_on(peer);
        thread_add_timer_msec(bm->master, bgp_process_packet, peer, 0,
                              &peer->t_process_packet);
 
-       if (from_peer)
-               peer_xfer_stats(peer, from_peer);
-
        return (peer);
 }
 
@@ -1097,7 +1101,7 @@ int bgp_stop(struct peer *peer)
                        stream_fifo_clean(peer->obuf);
 
                if (peer->ibuf_work)
-                       stream_reset(peer->ibuf_work);
+                       ringbuf_wipe(peer->ibuf_work);
                if (peer->obuf_work)
                        stream_reset(peer->obuf_work);
 
index 548167b3a38878cb301617fdb69ef82c1c0eed5f..59b2d1cdaa49c35c07fc614889c11206ca99f186 100644 (file)
@@ -29,6 +29,7 @@
 #include "memory.h"            // for MTYPE_TMP, XCALLOC, XFREE
 #include "network.h"           // for ERRNO_IO_RETRY
 #include "stream.h"            // for stream_get_endp, stream_getw_from, str...
+#include "ringbuf.h"           // for ringbuf_remain, ringbuf_peek, ringbuf_...
 #include "thread.h"            // for THREAD_OFF, THREAD_ARG, thread, thread...
 #include "zassert.h"           // for assert
 
@@ -50,71 +51,12 @@ static bool validate_header(struct peer *);
 #define BGP_IO_TRANS_ERR (1 << 0) // EAGAIN or similar occurred
 #define BGP_IO_FATAL_ERR (1 << 1) // some kind of fatal TCP error
 
-/* Start and stop routines for I/O pthread + control variables
- * ------------------------------------------------------------------------ */
-_Atomic bool bgp_io_thread_run;
-_Atomic bool bgp_io_thread_started;
-
-void bgp_io_init()
-{
-       bgp_io_thread_run = false;
-       bgp_io_thread_started = false;
-}
-
-/* Unused callback for thread_add_read() */
-static int bgp_io_dummy(struct thread *thread) { return 0; }
-
-void *bgp_io_start(void *arg)
-{
-       struct frr_pthread *fpt = frr_pthread_get(PTHREAD_IO);
-       fpt->master->owner = pthread_self();
-
-       // fd so we can sleep in poll()
-       int sleeper[2];
-       pipe(sleeper);
-       thread_add_read(fpt->master, &bgp_io_dummy, NULL, sleeper[0], NULL);
-
-       // we definitely don't want to handle signals
-       fpt->master->handle_signals = false;
-
-       struct thread task;
-
-       atomic_store_explicit(&bgp_io_thread_run, true, memory_order_seq_cst);
-       atomic_store_explicit(&bgp_io_thread_started, true,
-                             memory_order_seq_cst);
-
-       while (bgp_io_thread_run) {
-               if (thread_fetch(fpt->master, &task)) {
-                       thread_call(&task);
-               }
-       }
-
-       close(sleeper[1]);
-       close(sleeper[0]);
-
-       return NULL;
-}
-
-static int bgp_io_finish(struct thread *thread)
-{
-       atomic_store_explicit(&bgp_io_thread_run, false, memory_order_seq_cst);
-       return 0;
-}
-
-int bgp_io_stop(void **result, struct frr_pthread *fpt)
-{
-       thread_add_event(fpt->master, &bgp_io_finish, NULL, 0, NULL);
-       pthread_join(fpt->thread, result);
-       return 0;
-}
-
-/* Extern API -------------------------------------------------------------- */
+/* Thread external API ----------------------------------------------------- */
 
 void bgp_writes_on(struct peer *peer)
 {
-       while (
-           !atomic_load_explicit(&bgp_io_thread_started, memory_order_seq_cst))
-               ;
+       struct frr_pthread *fpt = frr_pthread_get(PTHREAD_IO);
+       assert(fpt->running);
 
        assert(peer->status != Deleted);
        assert(peer->obuf);
@@ -124,8 +66,6 @@ void bgp_writes_on(struct peer *peer)
        assert(!peer->t_connect_check_w);
        assert(peer->fd);
 
-       struct frr_pthread *fpt = frr_pthread_get(PTHREAD_IO);
-
        thread_add_write(fpt->master, bgp_process_writes, peer, peer->fd,
                         &peer->t_write);
        SET_FLAG(peer->thread_flags, PEER_THREAD_WRITES_ON);
@@ -133,11 +73,8 @@ void bgp_writes_on(struct peer *peer)
 
 void bgp_writes_off(struct peer *peer)
 {
-       while (
-           !atomic_load_explicit(&bgp_io_thread_started, memory_order_seq_cst))
-               ;
-
        struct frr_pthread *fpt = frr_pthread_get(PTHREAD_IO);
+       assert(fpt->running);
 
        thread_cancel_async(fpt->master, &peer->t_write, NULL);
        THREAD_OFF(peer->t_generate_updgrp_packets);
@@ -147,9 +84,8 @@ void bgp_writes_off(struct peer *peer)
 
 void bgp_reads_on(struct peer *peer)
 {
-       while (
-           !atomic_load_explicit(&bgp_io_thread_started, memory_order_seq_cst))
-               ;
+       struct frr_pthread *fpt = frr_pthread_get(PTHREAD_IO);
+       assert(fpt->running);
 
        assert(peer->status != Deleted);
        assert(peer->ibuf);
@@ -160,8 +96,6 @@ void bgp_reads_on(struct peer *peer)
        assert(!peer->t_connect_check_w);
        assert(peer->fd);
 
-       struct frr_pthread *fpt = frr_pthread_get(PTHREAD_IO);
-
        thread_add_read(fpt->master, bgp_process_reads, peer, peer->fd,
                        &peer->t_read);
 
@@ -170,11 +104,8 @@ void bgp_reads_on(struct peer *peer)
 
 void bgp_reads_off(struct peer *peer)
 {
-       while (
-           !atomic_load_explicit(&bgp_io_thread_started, memory_order_seq_cst))
-               ;
-
        struct frr_pthread *fpt = frr_pthread_get(PTHREAD_IO);
+       assert(fpt->running);
 
        thread_cancel_async(fpt->master, &peer->t_read, NULL);
        THREAD_OFF(peer->t_process_packet);
@@ -182,9 +113,9 @@ void bgp_reads_off(struct peer *peer)
        UNSET_FLAG(peer->thread_flags, PEER_THREAD_READS_ON);
 }
 
-/* Internal functions ------------------------------------------------------- */
+/* Thread internal functions ----------------------------------------------- */
 
-/**
+/*
  * Called from I/O pthread when a file descriptor has become ready for writing.
  */
 static int bgp_process_writes(struct thread *thread)
@@ -207,11 +138,13 @@ static int bgp_process_writes(struct thread *thread)
        }
        pthread_mutex_unlock(&peer->io_mtx);
 
-       if (CHECK_FLAG(status, BGP_IO_TRANS_ERR)) { /* no problem */
+       /* no problem */
+       if (CHECK_FLAG(status, BGP_IO_TRANS_ERR)) {
        }
 
+       /* problem */
        if (CHECK_FLAG(status, BGP_IO_FATAL_ERR)) {
-               reschedule = false; /* problem */
+               reschedule = false;
                fatal = true;
        }
 
@@ -226,7 +159,7 @@ static int bgp_process_writes(struct thread *thread)
        return 0;
 }
 
-/**
+/*
  * Called from I/O pthread when a file descriptor has become ready for reading,
  * or has hung up.
  *
@@ -273,14 +206,12 @@ static int bgp_process_reads(struct thread *thread)
                /* static buffer for transferring packets */
                static unsigned char pktbuf[BGP_MAX_PACKET_SIZE];
                /* shorter alias to peer's input buffer */
-               struct stream *ibw = peer->ibuf_work;
-               /* offset of start of current packet */
-               size_t offset = stream_get_getp(ibw);
+               struct ringbuf *ibw = peer->ibuf_work;
                /* packet size as given by header */
-               u_int16_t pktsize = 0;
+               uint16_t pktsize = 0;
 
                /* check that we have enough data for a header */
-               if (STREAM_READABLE(ibw) < BGP_HEADER_SIZE)
+               if (ringbuf_remain(ibw) < BGP_HEADER_SIZE)
                        break;
 
                /* validate header */
@@ -292,16 +223,20 @@ static int bgp_process_reads(struct thread *thread)
                }
 
                /* header is valid; retrieve packet size */
-               pktsize = stream_getw_from(ibw, offset + BGP_MARKER_SIZE);
+               ringbuf_peek(ibw, BGP_MARKER_SIZE, &pktsize, sizeof(pktsize));
+
+               pktsize = ntohs(pktsize);
 
                /* if this fails we are seriously screwed */
                assert(pktsize <= BGP_MAX_PACKET_SIZE);
 
-               /* If we have that much data, chuck it into its own
-                * stream and append to input queue for processing. */
-               if (STREAM_READABLE(ibw) >= pktsize) {
+               /*
+                * If we have that much data, chuck it into its own
+                * stream and append to input queue for processing.
+                */
+               if (ringbuf_remain(ibw) >= pktsize) {
                        struct stream *pkt = stream_new(pktsize);
-                       stream_get(pktbuf, ibw, pktsize);
+                       assert(ringbuf_get(ibw, pktbuf, pktsize) == pktsize);
                        stream_put(pkt, pktbuf, pktsize);
 
                        pthread_mutex_lock(&peer->io_mtx);
@@ -315,28 +250,12 @@ static int bgp_process_reads(struct thread *thread)
                        break;
        }
 
-       /*
-        * After reading:
-        * 1. Move unread data to stream start to make room for more.
-        * 2. Reschedule and return when we have additional data.
-        *
-        * XXX: Heavy abuse of stream API. This needs a ring buffer.
-        */
-       if (more && STREAM_WRITEABLE(peer->ibuf_work) < BGP_MAX_PACKET_SIZE) {
-               void *from = stream_pnt(peer->ibuf_work);
-               void *to = peer->ibuf_work->data;
-               size_t siz = STREAM_READABLE(peer->ibuf_work);
-               memmove(to, from, siz);
-               stream_set_getp(peer->ibuf_work, 0);
-               stream_set_endp(peer->ibuf_work, siz);
-       }
-
-       assert(STREAM_WRITEABLE(peer->ibuf_work) >= BGP_MAX_PACKET_SIZE);
+       assert(ringbuf_space(peer->ibuf_work) >= BGP_MAX_PACKET_SIZE);
 
        /* handle invalid header */
        if (fatal) {
                /* wipe buffer just in case someone screwed up */
-               stream_reset(peer->ibuf_work);
+               ringbuf_wipe(peer->ibuf_work);
        } else {
                thread_add_read(fpt->master, bgp_process_reads, peer, peer->fd,
                                &peer->t_read);
@@ -348,7 +267,7 @@ static int bgp_process_reads(struct thread *thread)
        return 0;
 }
 
-/**
+/*
  * Flush peer output buffer.
  *
  * This function pops packets off of peer->obuf and writes them to peer->fd.
@@ -367,15 +286,10 @@ static uint16_t bgp_write(struct peer *peer)
        int num;
        int update_last_write = 0;
        unsigned int count = 0;
-       uint32_t oc;
-       uint32_t uo;
+       uint32_t uo = 0;
        uint16_t status = 0;
        uint32_t wpkt_quanta_old;
 
-       // save current # updates sent
-       oc = atomic_load_explicit(&peer->update_out, memory_order_relaxed);
-
-       // cache current write quanta
        wpkt_quanta_old =
            atomic_load_explicit(&peer->bgp->wpkt_quanta, memory_order_relaxed);
 
@@ -394,7 +308,7 @@ static uint16_t bgp_write(struct peer *peer)
                                }
 
                                goto done;
-                       } else if (num != writenum) // incomplete write
+                       } else if (num != writenum)
                                stream_forward_getp(s, num);
 
                } while (num != writenum);
@@ -411,6 +325,7 @@ static uint16_t bgp_write(struct peer *peer)
                case BGP_MSG_UPDATE:
                        atomic_fetch_add_explicit(&peer->update_out, 1,
                                                  memory_order_relaxed);
+                       uo++;
                        break;
                case BGP_MSG_NOTIFY:
                        atomic_fetch_add_explicit(&peer->notify_out, 1,
@@ -422,8 +337,10 @@ static uint16_t bgp_write(struct peer *peer)
                        if (peer->v_start >= (60 * 2))
                                peer->v_start = (60 * 2);
 
-                       /* Handle Graceful Restart case where the state changes
-                        * to Connect instead of Idle */
+                       /*
+                        * Handle Graceful Restart case where the state changes
+                        * to Connect instead of Idle.
+                        */
                        BGP_EVENT_ADD(peer, BGP_Stop);
                        goto done;
 
@@ -449,9 +366,12 @@ static uint16_t bgp_write(struct peer *peer)
        }
 
 done : {
-       /* Update last_update if UPDATEs were written. */
-       uo = atomic_load_explicit(&peer->update_out, memory_order_relaxed);
-       if (uo > oc)
+       /*
+        * Update last_update if UPDATEs were written.
+        * Note: that these are only updated at end,
+        *       not per message (i.e., per loop)
+        */
+       if (uo)
                atomic_store_explicit(&peer->last_update, bgp_clock(),
                                      memory_order_relaxed);
 
@@ -464,7 +384,7 @@ done : {
        return status;
 }
 
-/**
+/*
  * Reads a chunk of data from peer->fd into peer->ibuf_work.
  *
  * @return status flag (see top-of-file)
@@ -474,14 +394,16 @@ static uint16_t bgp_read(struct peer *peer)
        size_t readsize; // how many bytes we want to read
        ssize_t nbytes;  // how many bytes we actually read
        uint16_t status = 0;
+       static uint8_t ibw[BGP_MAX_PACKET_SIZE * BGP_READ_PACKET_MAX];
 
-       readsize = STREAM_WRITEABLE(peer->ibuf_work);
+       readsize = MIN(ringbuf_space(peer->ibuf_work), sizeof(ibw));
+       nbytes = read(peer->fd, ibw, readsize);
 
-       nbytes = stream_read_try(peer->ibuf_work, peer->fd, readsize);
-
-       switch (nbytes) {
+       /* EAGAIN or EWOULDBLOCK; come back later */
+       if (nbytes < 0 && ERRNO_IO_RETRY(errno)) {
+               SET_FLAG(status, BGP_IO_TRANS_ERR);
        /* Fatal error; tear down session */
-       case -1:
+       } else if (nbytes < 0) {
                zlog_err("%s [Error] bgp_read_packet error: %s", peer->host,
                         safe_strerror(errno));
 
@@ -495,10 +417,8 @@ static uint16_t bgp_read(struct peer *peer)
 
                BGP_EVENT_ADD(peer, TCP_fatal_error);
                SET_FLAG(status, BGP_IO_FATAL_ERR);
-               break;
-
        /* Received EOF / TCP session closed */
-       case 0:
+       } else if (nbytes == 0) {
                if (bgp_debug_neighbor_events(peer))
                        zlog_debug("%s [Event] BGP connection closed fd %d",
                                   peer->host, peer->fd);
@@ -513,14 +433,9 @@ static uint16_t bgp_read(struct peer *peer)
 
                BGP_EVENT_ADD(peer, TCP_connection_closed);
                SET_FLAG(status, BGP_IO_FATAL_ERR);
-               break;
-
-       /* EAGAIN or EWOULDBLOCK; come back later */
-       case -2:
-               SET_FLAG(status, BGP_IO_TRANS_ERR);
-               break;
-       default:
-               break;
+       } else {
+               assert(ringbuf_put(peer->ibuf_work, ibw, nbytes)
+                      == (size_t)nbytes);
        }
 
        return status;
@@ -529,27 +444,35 @@ static uint16_t bgp_read(struct peer *peer)
 /*
  * Called after we have read a BGP packet header. Validates marker, message
  * type and packet length. If any of these aren't correct, sends a notify.
+ *
+ * Assumes that there are at least BGP_HEADER_SIZE readable bytes in the input
+ * buffer.
  */
 static bool validate_header(struct peer *peer)
 {
        uint16_t size;
        uint8_t type;
-       struct stream *pkt = peer->ibuf_work;
-       size_t getp = stream_get_getp(pkt);
+       struct ringbuf *pkt = peer->ibuf_work;
 
-       static uint8_t marker[BGP_MARKER_SIZE] = {
-           0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-           0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+       static uint8_t m_correct[BGP_MARKER_SIZE] = {
+               0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+               0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+       uint8_t m_rx[BGP_MARKER_SIZE] = {0x00};
 
-       if (memcmp(marker, stream_pnt(pkt), BGP_MARKER_SIZE) != 0) {
+       if (ringbuf_peek(pkt, 0, m_rx, BGP_MARKER_SIZE) != BGP_MARKER_SIZE)
+               return false;
+
+       if (memcmp(m_correct, m_rx, BGP_MARKER_SIZE) != 0) {
                bgp_notify_send(peer, BGP_NOTIFY_HEADER_ERR,
                                BGP_NOTIFY_HEADER_NOT_SYNC);
                return false;
        }
 
-       /* Get size and type in host byte order. */
-       size = stream_getw_from(pkt, getp + BGP_MARKER_SIZE);
-       type = stream_getc_from(pkt, getp + BGP_MARKER_SIZE + 2);
+       /* Get size and type in network byte order. */
+       ringbuf_peek(pkt, BGP_MARKER_SIZE, &size, sizeof(size));
+       ringbuf_peek(pkt, BGP_MARKER_SIZE + 2, &type, sizeof(type));
+
+       size = ntohs(size);
 
        /* BGP type check. */
        if (type != BGP_MSG_OPEN && type != BGP_MSG_UPDATE
index c4bd3c2dd97cf8bad382f37fe8e3b8fcfd9f4eeb..14a12d3705b977dc2395e35cea293ac3f5db91fa 100644 (file)
 #include "bgpd/bgpd.h"
 #include "frr_pthread.h"
 
-/**
- * Initializes data structures and flags for the write thread.
- *
- * This function should be called from the main thread before
- * bgp_writes_start() is invoked.
- */
-extern void bgp_io_init(void);
-
 /**
  * Start function for write thread.
  *
index afa280a799ff7db01569228a465ebb217c2e0490..5a48c7013e63d55425cc7d9d94e76abc3afc263f 100644 (file)
 #include "bgpd/bgp_keepalives.h"
 /* clang-format on */
 
-/**
+/*
  * Peer KeepAlive Timer.
  * Associates a peer with the time of its last keepalive.
  */
 struct pkat {
-       // the peer to send keepalives to
+       /* the peer to send keepalives to */
        struct peer *peer;
-       // absolute time of last keepalive sent
+       /* absolute time of last keepalive sent */
        struct timeval last;
 };
 
@@ -52,9 +52,6 @@ static pthread_mutex_t *peerhash_mtx;
 static pthread_cond_t *peerhash_cond;
 static struct hash *peerhash;
 
-/* Thread control flag. */
-bool bgp_keepalives_thread_run = false;
-
 static struct pkat *pkat_new(struct peer *peer)
 {
        struct pkat *pkat = XMALLOC(MTYPE_TMP, sizeof(struct pkat));
@@ -100,10 +97,10 @@ static void peer_process(struct hash_backet *hb, void *arg)
 
        static struct timeval tolerance = {0, 100000};
 
-       // calculate elapsed time since last keepalive
+       /* calculate elapsed time since last keepalive */
        monotime_since(&pkat->last, &elapsed);
 
-       // calculate difference between elapsed time and configured time
+       /* calculate difference between elapsed time and configured time */
        ka.tv_sec = pkat->peer->v_keepalive;
        timersub(&ka, &elapsed, &diff);
 
@@ -118,10 +115,10 @@ static void peer_process(struct hash_backet *hb, void *arg)
                bgp_keepalive_send(pkat->peer);
                monotime(&pkat->last);
                memset(&elapsed, 0x00, sizeof(struct timeval));
-               diff = ka; // time until next keepalive == peer keepalive time
+               diff = ka;
        }
 
-       // if calculated next update for this peer < current delay, use it
+       /* if calculated next update for this peer < current delay, use it */
        if (next_update->tv_sec <= 0 || timercmp(&diff, next_update, <))
                *next_update = diff;
 }
@@ -139,29 +136,9 @@ static unsigned int peer_hash_key(void *arg)
        return (uintptr_t)pkat->peer;
 }
 
-void bgp_keepalives_init()
-{
-       peerhash_mtx = XCALLOC(MTYPE_TMP, sizeof(pthread_mutex_t));
-       peerhash_cond = XCALLOC(MTYPE_TMP, sizeof(pthread_cond_t));
-
-       // initialize mutex
-       pthread_mutex_init(peerhash_mtx, NULL);
-
-       // use monotonic clock with condition variable
-       pthread_condattr_t attrs;
-       pthread_condattr_init(&attrs);
-       pthread_condattr_setclock(&attrs, CLOCK_MONOTONIC);
-       pthread_cond_init(peerhash_cond, &attrs);
-       pthread_condattr_destroy(&attrs);
-
-       // initialize peer hashtable
-       peerhash = hash_create_size(2048, peer_hash_key, peer_hash_cmp, NULL);
-}
-
+/* Cleanup handler / deinitializer. */
 static void bgp_keepalives_finish(void *arg)
 {
-       bgp_keepalives_thread_run = false;
-
        if (peerhash) {
                hash_clean(peerhash, pkat_del);
                hash_free(peerhash);
@@ -177,32 +154,50 @@ static void bgp_keepalives_finish(void *arg)
        XFREE(MTYPE_TMP, peerhash_cond);
 }
 
-/**
+/*
  * Entry function for peer keepalive generation pthread.
- *
- * bgp_keepalives_init() must be called prior to this.
  */
 void *bgp_keepalives_start(void *arg)
 {
+       struct frr_pthread *fpt = arg;
+       fpt->master->owner = pthread_self();
+
        struct timeval currtime = {0, 0};
        struct timeval aftertime = {0, 0};
        struct timeval next_update = {0, 0};
        struct timespec next_update_ts = {0, 0};
 
+       peerhash_mtx = XCALLOC(MTYPE_TMP, sizeof(pthread_mutex_t));
+       peerhash_cond = XCALLOC(MTYPE_TMP, sizeof(pthread_cond_t));
+
+       /* initialize mutex */
+       pthread_mutex_init(peerhash_mtx, NULL);
+
+       /* use monotonic clock with condition variable */
+       pthread_condattr_t attrs;
+       pthread_condattr_init(&attrs);
+       pthread_condattr_setclock(&attrs, CLOCK_MONOTONIC);
+       pthread_cond_init(peerhash_cond, &attrs);
+       pthread_condattr_destroy(&attrs);
+
+       /* initialize peer hashtable */
+       peerhash = hash_create_size(2048, peer_hash_key, peer_hash_cmp, NULL);
        pthread_mutex_lock(peerhash_mtx);
 
-       // register cleanup handler
+       /* register cleanup handler */
        pthread_cleanup_push(&bgp_keepalives_finish, NULL);
 
-       bgp_keepalives_thread_run = true;
+       /* notify anybody waiting on us that we are done starting up */
+       frr_pthread_notify_running(fpt);
 
-       while (bgp_keepalives_thread_run) {
+       while (atomic_load_explicit(&fpt->running, memory_order_relaxed)) {
                if (peerhash->count > 0)
                        pthread_cond_timedwait(peerhash_cond, peerhash_mtx,
                                               &next_update_ts);
                else
                        while (peerhash->count == 0
-                              && bgp_keepalives_thread_run)
+                              && atomic_load_explicit(&fpt->running,
+                                                      memory_order_relaxed))
                                pthread_cond_wait(peerhash_cond, peerhash_mtx);
 
                monotime(&currtime);
@@ -219,7 +214,7 @@ void *bgp_keepalives_start(void *arg)
                TIMEVAL_TO_TIMESPEC(&next_update, &next_update_ts);
        }
 
-       // clean up
+       /* clean up */
        pthread_cleanup_pop(1);
 
        return NULL;
@@ -229,6 +224,12 @@ void *bgp_keepalives_start(void *arg)
 
 void bgp_keepalives_on(struct peer *peer)
 {
+       if (CHECK_FLAG(peer->thread_flags, PEER_THREAD_KEEPALIVES_ON))
+               return;
+
+       struct frr_pthread *fpt = frr_pthread_get(PTHREAD_KEEPALIVES);
+       assert(fpt->running);
+
        /* placeholder bucket data to use for fast key lookups */
        static struct pkat holder = {0};
 
@@ -253,6 +254,12 @@ void bgp_keepalives_on(struct peer *peer)
 
 void bgp_keepalives_off(struct peer *peer)
 {
+       if (!CHECK_FLAG(peer->thread_flags, PEER_THREAD_KEEPALIVES_ON))
+               return;
+
+       struct frr_pthread *fpt = frr_pthread_get(PTHREAD_KEEPALIVES);
+       assert(fpt->running);
+
        /* placeholder bucket data to use for fast key lookups */
        static struct pkat holder = {0};
 
@@ -283,10 +290,13 @@ void bgp_keepalives_wake()
        pthread_mutex_unlock(peerhash_mtx);
 }
 
-int bgp_keepalives_stop(void **result, struct frr_pthread *fpt)
+int bgp_keepalives_stop(struct frr_pthread *fpt, void **result)
 {
-       bgp_keepalives_thread_run = false;
+       assert(fpt->running);
+
+       atomic_store_explicit(&fpt->running, false, memory_order_relaxed);
        bgp_keepalives_wake();
+
        pthread_join(fpt->thread, result);
        return 0;
 }
index 1fbd035b9edd5d7ccea5387ed7c7b514f73fd051..d1cb7d2462ac5c3cea0f6eac52e1ff6aebe882da 100644 (file)
@@ -88,6 +88,6 @@ extern void bgp_keepalives_wake(void);
 /**
  * Stops the thread and blocks until it terminates.
  */
-int bgp_keepalives_stop(void **result, struct frr_pthread *fpt);
+int bgp_keepalives_stop(struct frr_pthread *fpt, void **result);
 
 #endif /* _FRR_BGP_KEEPALIVES_H */
index 60250513b678eeff506b0bb8e0a14ac48a17703b..38b39075be376b51aecdc46d1f61050b0274175e 100644 (file)
@@ -103,7 +103,7 @@ mpls_label_t bgp_adv_label(struct bgp_node *rn, struct bgp_info *ri,
        if (!rn || !ri || !to)
                return MPLS_INVALID_LABEL;
 
-       remote_label = ri->extra ? ri->extra->label : MPLS_INVALID_LABEL;
+       remote_label = ri->extra ? ri->extra->label[0] : MPLS_INVALID_LABEL;
        from = ri->peer;
        reflect =
                ((from->sort == BGP_PEER_IBGP) && (to->sort == BGP_PEER_IBGP));
@@ -325,11 +325,11 @@ int bgp_nlri_parse_label(struct peer *peer, struct attr *attr,
                if (attr) {
                        bgp_update(peer, &p, addpath_id, attr, packet->afi,
                                   SAFI_UNICAST, ZEBRA_ROUTE_BGP,
-                                  BGP_ROUTE_NORMAL, NULL, &label, 0, NULL);
+                                  BGP_ROUTE_NORMAL, NULL, &label, 1, 0, NULL);
                } else {
                        bgp_withdraw(peer, &p, addpath_id, attr, packet->afi,
                                     SAFI_UNICAST, ZEBRA_ROUTE_BGP,
-                                    BGP_ROUTE_NORMAL, NULL, &label, NULL);
+                                    BGP_ROUTE_NORMAL, NULL, &label, 1, NULL);
                }
        }
 
index 7dd4253b2e8eb58b73ccc2587df235c7d7b8c48c..0508f4846de40d5933d3cbe3ecb7984399c8e74a 100644 (file)
@@ -221,6 +221,7 @@ static __attribute__((__noreturn__)) void bgp_exit(int status)
 #endif
        bgp_zebra_destroy();
 
+       bf_free(bm->rd_idspace);
        list_delete_and_null(&bm->bgp);
        memset(bm, 0, sizeof(*bm));
 
@@ -231,7 +232,7 @@ static __attribute__((__noreturn__)) void bgp_exit(int status)
 static int bgp_vrf_new(struct vrf *vrf)
 {
        if (BGP_DEBUG(zebra, ZEBRA))
-               zlog_debug("VRF Created: %s(%d)", vrf->name, vrf->vrf_id);
+               zlog_debug("VRF Created: %s(%u)", vrf->name, vrf->vrf_id);
 
        return 0;
 }
@@ -239,7 +240,7 @@ static int bgp_vrf_new(struct vrf *vrf)
 static int bgp_vrf_delete(struct vrf *vrf)
 {
        if (BGP_DEBUG(zebra, ZEBRA))
-               zlog_debug("VRF Deletion: %s(%d)", vrf->name, vrf->vrf_id);
+               zlog_debug("VRF Deletion: %s(%u)", vrf->name, vrf->vrf_id);
 
        return 0;
 }
@@ -250,7 +251,7 @@ static int bgp_vrf_enable(struct vrf *vrf)
        vrf_id_t old_vrf_id;
 
        if (BGP_DEBUG(zebra, ZEBRA))
-               zlog_debug("VRF enable add %s id %d", vrf->name, vrf->vrf_id);
+               zlog_debug("VRF enable add %s id %u", vrf->name, vrf->vrf_id);
 
        bgp = bgp_lookup_by_name(vrf->name);
        if (bgp) {
index 37054ce4258360d01af93b8a5266947da7ba31c2..64543ff01997baabb3ca008e80fc42253bfe79fa 100644 (file)
@@ -117,4 +117,5 @@ DEFINE_MTYPE(BGPD, LCOMMUNITY_VAL, "Large Community value")
 
 DEFINE_MTYPE(BGPD, BGP_EVPN, "BGP EVPN Information")
 DEFINE_MTYPE(BGPD, BGP_EVPN_IMPORT_RT, "BGP EVPN Import RT")
+DEFINE_MTYPE(BGPD, BGP_EVPN_VRF_IMPORT_RT, "BGP EVPN VRF Import RT")
 DEFINE_MTYPE(BGPD, BGP_EVPN_MACIP, "BGP EVPN MAC IP")
index 35b83a040153e003d8baaf62a0c5773914dc0d97..fae98329c68c9af7f384b602591bbc28a1dd53a6 100644 (file)
@@ -113,5 +113,6 @@ DECLARE_MTYPE(LCOMMUNITY_VAL)
 
 DECLARE_MTYPE(BGP_EVPN)
 DECLARE_MTYPE(BGP_EVPN_IMPORT_RT)
+DECLARE_MTYPE(BGP_EVPN_VRF_IMPORT_RT)
 DECLARE_MTYPE(BGP_EVPN_MACIP)
 #endif /* _QUAGGA_BGP_MEMORY_H */
index 472b9d200a4bca98930065baefb5910d4a111b24..ec4989de8fc5d87d108d124c2198217574659488 100644 (file)
@@ -214,11 +214,11 @@ int bgp_nlri_parse_vpn(struct peer *peer, struct attr *attr,
                if (attr) {
                        bgp_update(peer, &p, addpath_id, attr, packet->afi,
                                   SAFI_MPLS_VPN, ZEBRA_ROUTE_BGP,
-                                  BGP_ROUTE_NORMAL, &prd, &label, 0, NULL);
+                                  BGP_ROUTE_NORMAL, &prd, &label, 1, 0, NULL);
                } else {
                        bgp_withdraw(peer, &p, addpath_id, attr, packet->afi,
                                     SAFI_MPLS_VPN, ZEBRA_ROUTE_BGP,
-                                    BGP_ROUTE_NORMAL, &prd, &label, NULL);
+                                    BGP_ROUTE_NORMAL, &prd, &label, 1, NULL);
                }
        }
        /* Packet length consistency check. */
@@ -366,8 +366,8 @@ int bgp_show_mpls_vpn(struct vty *vty, afi_t afi, struct prefix_rd *prd,
                return CMD_WARNING;
        }
        table = bgp->rib[afi][SAFI_MPLS_VPN];
-       return bgp_show_table_rd(vty, bgp, SAFI_MPLS_VPN,
-                                table, prd, type, output_arg, use_json);
+       return bgp_show_table_rd(vty, bgp, SAFI_MPLS_VPN, table, prd, type,
+                                output_arg, use_json);
 }
 
 DEFUN (show_bgp_ip_vpn_all_rd,
@@ -389,7 +389,7 @@ DEFUN (show_bgp_ip_vpn_all_rd,
 
        if (argv_find_and_parse_afi(argv, argc, &idx, &afi)) {
                if (argv_find(argv, argc, "rd", &idx)) {
-                       ret = str2prefix_rd(argv[idx+1]->arg, &prd);
+                       ret = str2prefix_rd(argv[idx + 1]->arg, &prd);
                        if (!ret) {
                                vty_out(vty,
                                        "%% Malformed Route Distinguisher\n");
index 3b37aadbf8c14f836e32a5f5c8a68e97f9c90396..5c11f7526cea7db720ed6bbe7abdf4a6c81dc794 100644 (file)
 #include "bgpd/bgp_route.h"
 #include "bgpd/bgp_rd.h"
 
-#ifdef MPLS_LABEL_MAX
-#undef MPLS_LABEL_MAX
-#endif
-
-typedef enum {
-       MPLS_LABEL_IPV4_EXPLICIT_NULL = 0, /* [RFC3032] */
-       MPLS_LABEL_ROUTER_ALERT = 1,       /* [RFC3032] */
-       MPLS_LABEL_IPV6_EXPLICIT_NULL = 2, /* [RFC3032] */
-       MPLS_LABEL_IMPLICIT_NULL = 3,      /* [RFC3032] */
-       MPLS_LABEL_UNASSIGNED4 = 4,
-       MPLS_LABEL_UNASSIGNED5 = 5,
-       MPLS_LABEL_UNASSIGNED6 = 6,
-       MPLS_LABEL_ELI = 7, /* Entropy Indicator [RFC6790] */
-       MPLS_LABEL_UNASSIGNED8 = 8,
-       MPLS_LABEL_UNASSIGNED9 = 9,
-       MPLS_LABEL_UNASSIGNED10 = 10,
-       MPLS_LABEL_UNASSIGNED11 = 11,
-       MPLS_LABEL_GAL = 13,       /* [RFC5586] */
-       MPLS_LABEL_OAM_ALERT = 14, /* [RFC3429] */
-       MPLS_LABEL_EXTENSION = 15, /* [RFC7274] */
-       MPLS_LABEL_MAX = 1048575,
-       MPLS_LABEL_ILLEGAL = 0xFFFFFFFF /* for internal use only */
-} mpls_special_label_t;
-
 #define MPLS_LABEL_IS_SPECIAL(label) ((label) <= MPLS_LABEL_EXTENSION)
 #define MPLS_LABEL_IS_NULL(label)                                              \
        ((label) == MPLS_LABEL_IPV4_EXPLICIT_NULL                              \
index 625d4f844260d03bb0c58977f7b2a979d074d974..d39fbec86dedffa88d5543308c9ffc9e868b6804 100644 (file)
@@ -320,54 +320,44 @@ void bgp_delete_connected_nexthop(afi_t afi, struct peer *peer)
 
 void bgp_parse_nexthop_update(int command, vrf_id_t vrf_id)
 {
-       struct stream *s;
        struct bgp_node *rn = NULL;
        struct bgp_nexthop_cache *bnc;
        struct nexthop *nexthop;
        struct nexthop *oldnh;
        struct nexthop *nhlist_head = NULL;
        struct nexthop *nhlist_tail = NULL;
-       uint32_t metric;
-       u_char nexthop_num;
-       struct prefix p;
        int i;
        struct bgp *bgp;
+       struct zapi_route nhr;
 
        bgp = bgp_lookup_by_vrf_id(vrf_id);
        if (!bgp) {
                zlog_err(
-                       "parse nexthop update: instance not found for vrf_id %d",
+                       "parse nexthop update: instance not found for vrf_id %u",
                        vrf_id);
                return;
        }
 
-       s = zclient->ibuf;
-
-       memset(&p, 0, sizeof(struct prefix));
-       p.family = stream_getw(s);
-       p.prefixlen = stream_getc(s);
-       switch (p.family) {
-       case AF_INET:
-               p.u.prefix4.s_addr = stream_get_ipv4(s);
-               break;
-       case AF_INET6:
-               stream_get(&p.u.prefix6, s, 16);
-               break;
-       default:
-               break;
+       if (!zapi_nexthop_update_decode(zclient->ibuf, &nhr)) {
+               if (BGP_DEBUG(nht, NHT))
+                       zlog_debug("%s: Failure to decode nexthop update",
+                                  __PRETTY_FUNCTION__);
+               return;
        }
 
        if (command == ZEBRA_NEXTHOP_UPDATE)
                rn = bgp_node_lookup(
-                       bgp->nexthop_cache_table[family2afi(p.family)], &p);
+                       bgp->nexthop_cache_table[family2afi(nhr.prefix.family)],
+                       &nhr.prefix);
        else if (command == ZEBRA_IMPORT_CHECK_UPDATE)
                rn = bgp_node_lookup(
-                       bgp->import_check_table[family2afi(p.family)], &p);
+                       bgp->import_check_table[family2afi(nhr.prefix.family)],
+                       &nhr.prefix);
 
        if (!rn || !rn->info) {
                if (BGP_DEBUG(nht, NHT)) {
                        char buf[PREFIX2STR_BUFFER];
-                       prefix2str(&p, buf, sizeof(buf));
+                       prefix2str(&nhr.prefix, buf, sizeof(buf));
                        zlog_debug("parse nexthop update(%s): rn not found",
                                   buf);
                }
@@ -380,62 +370,34 @@ void bgp_parse_nexthop_update(int command, vrf_id_t vrf_id)
        bgp_unlock_node(rn);
        bnc->last_update = bgp_clock();
        bnc->change_flags = 0;
-       stream_getc(s); // Distance but not currently used
-       metric = stream_getl(s);
-       nexthop_num = stream_getc(s);
 
        /* debug print the input */
        if (BGP_DEBUG(nht, NHT)) {
                char buf[PREFIX2STR_BUFFER];
-               prefix2str(&p, buf, sizeof(buf));
+               prefix2str(&nhr.prefix, buf, sizeof(buf));
                zlog_debug(
-                       "%d: Rcvd NH update %s - metric %d/%d #nhops %d/%d flags 0x%x",
-                       vrf_id, buf, metric, bnc->metric, nexthop_num,
+                       "%u: Rcvd NH update %s - metric %d/%d #nhops %d/%d flags 0x%x",
+                       vrf_id, buf, nhr.metric, bnc->metric, nhr.nexthop_num,
                        bnc->nexthop_num, bnc->flags);
        }
 
-       if (metric != bnc->metric)
+       if (nhr.metric != bnc->metric)
                bnc->change_flags |= BGP_NEXTHOP_METRIC_CHANGED;
 
-       if (nexthop_num != bnc->nexthop_num)
+       if (nhr.nexthop_num != bnc->nexthop_num)
                bnc->change_flags |= BGP_NEXTHOP_CHANGED;
 
-       if (nexthop_num) {
+       if (nhr.nexthop_num) {
                /* notify bgp fsm if nbr ip goes from invalid->valid */
                if (!bnc->nexthop_num)
                        UNSET_FLAG(bnc->flags, BGP_NEXTHOP_PEER_NOTIFIED);
 
                bnc->flags |= BGP_NEXTHOP_VALID;
-               bnc->metric = metric;
-               bnc->nexthop_num = nexthop_num;
-
-               for (i = 0; i < nexthop_num; i++) {
-                       nexthop = nexthop_new();
-                       nexthop->type = stream_getc(s);
-                       switch (nexthop->type) {
-                       case NEXTHOP_TYPE_IPV4:
-                               nexthop->gate.ipv4.s_addr = stream_get_ipv4(s);
-                               nexthop->ifindex = stream_getl(s);
-                               break;
-                       case NEXTHOP_TYPE_IFINDEX:
-                               nexthop->ifindex = stream_getl(s);
-                               break;
-                       case NEXTHOP_TYPE_IPV4_IFINDEX:
-                               nexthop->gate.ipv4.s_addr = stream_get_ipv4(s);
-                               nexthop->ifindex = stream_getl(s);
-                               break;
-                       case NEXTHOP_TYPE_IPV6:
-                               stream_get(&nexthop->gate.ipv6, s, 16);
-                               nexthop->ifindex = stream_getl(s);
-                               break;
-                       case NEXTHOP_TYPE_IPV6_IFINDEX:
-                               stream_get(&nexthop->gate.ipv6, s, 16);
-                               nexthop->ifindex = stream_getl(s);
-                               break;
-                       default:
-                               /* do nothing */
-                               break;
-                       }
+               bnc->metric = nhr.metric;
+               bnc->nexthop_num = nhr.nexthop_num;
+
+               for (i = 0; i < nhr.nexthop_num; i++) {
+                       nexthop = nexthop_from_zapi_nexthop(&nhr.nexthops[i]);
 
                        if (BGP_DEBUG(nht, NHT)) {
                                char buf[NEXTHOP_STRLEN];
@@ -470,7 +432,7 @@ void bgp_parse_nexthop_update(int command, vrf_id_t vrf_id)
                bnc->nexthop = nhlist_head;
        } else {
                bnc->flags &= ~BGP_NEXTHOP_VALID;
-               bnc->nexthop_num = nexthop_num;
+               bnc->nexthop_num = nhr.nexthop_num;
 
                /* notify bgp fsm if nbr ip goes from valid->invalid */
                UNSET_FLAG(bnc->flags, BGP_NEXTHOP_PEER_NOTIFIED);
@@ -572,12 +534,11 @@ static int make_prefix(int afi, struct bgp_info *ri, struct prefix *p)
  */
 static void sendmsg_zebra_rnh(struct bgp_nexthop_cache *bnc, int command)
 {
-       struct stream *s;
        struct prefix *p;
+       bool exact_match = false;
        int ret;
 
-       /* Check socket. */
-       if (!zclient || zclient->sock < 0)
+       if (!zclient)
                return;
 
        /* Don't try to register if Zebra doesn't know of this instance. */
@@ -585,32 +546,14 @@ static void sendmsg_zebra_rnh(struct bgp_nexthop_cache *bnc, int command)
                return;
 
        p = &(bnc->node->p);
-       s = zclient->obuf;
-       stream_reset(s);
-       zclient_create_header(s, command, bnc->bgp->vrf_id);
        if ((command == ZEBRA_NEXTHOP_REGISTER ||
             command == ZEBRA_IMPORT_ROUTE_REGISTER) &&
            (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED)
             || CHECK_FLAG(bnc->flags, BGP_STATIC_ROUTE_EXACT_MATCH)))
-               stream_putc(s, 1);
-       else
-               stream_putc(s, 0);
-
-       stream_putw(s, PREFIX_FAMILY(p));
-       stream_putc(s, p->prefixlen);
-       switch (PREFIX_FAMILY(p)) {
-       case AF_INET:
-               stream_put_in_addr(s, &p->u.prefix4);
-               break;
-       case AF_INET6:
-               stream_put(s, &(p->u.prefix6), 16);
-               break;
-       default:
-               break;
-       }
-       stream_putw_at(s, 0, stream_get_endp(s));
+               exact_match = true;
 
-       ret = zclient_send_message(zclient);
+       ret = zclient_send_rnh(zclient, command, p,
+                              exact_match, bnc->bgp->vrf_id);
        /* TBD: handle the failure */
        if (ret < 0)
                zlog_warn("sendmsg_nexthop: zclient_send_message() failed");
index 4b018aef4d54eb0011d8e17e6c26026fd39801ed..0ce2466f52aa9e9f97b9ca411034df528aad1248 100644 (file)
@@ -545,19 +545,26 @@ void bgp_open_send(struct peer *peer)
        bgp_writes_on(peer);
 }
 
-/* This is only for sending NOTIFICATION message to neighbor. */
+/*
+ * Writes NOTIFICATION message directly to a peer socket without waiting for
+ * the I/O thread.
+ *
+ * There must be exactly one stream on the peer->obuf FIFO, and the data within
+ * this stream must match the format of a BGP NOTIFICATION message.
+ * Transmission is best-effort.
+ *
+ * @requires peer->io_mtx
+ * @param peer
+ * @return 0
+ */
 static int bgp_write_notify(struct peer *peer)
 {
        int ret, val;
        u_char type;
        struct stream *s;
 
-       pthread_mutex_lock(&peer->io_mtx);
-       {
-               /* There should be at least one packet. */
-               s = stream_fifo_pop(peer->obuf);
-       }
-       pthread_mutex_unlock(&peer->io_mtx);
+       /* There should be at least one packet. */
+       s = stream_fifo_pop(peer->obuf);
 
        if (!s)
                return 0;
@@ -595,6 +602,7 @@ static int bgp_write_notify(struct peer *peer)
        assert(type == BGP_MSG_NOTIFY);
 
        /* Type should be notify. */
+       atomic_fetch_add_explicit(&peer->notify_out, 1, memory_order_relaxed);
        peer->notify_out++;
 
        /* Double start timer. */
@@ -621,6 +629,14 @@ static int bgp_write_notify(struct peer *peer)
  * This function attempts to write the packet from the thread it is called
  * from, to ensure the packet gets out ASAP.
  *
+ * This function may be called from multiple threads. Since the function
+ * modifies I/O buffer(s) in the peer, these are locked for the duration of the
+ * call to prevent tampering from other threads.
+ *
+ * Delivery of the NOTIFICATION is attempted once and is best-effort. After
+ * return, the peer structure *must* be reset; no assumptions about session
+ * state are valid.
+ *
  * @param peer
  * @param code      BGP error code
  * @param sub_code  BGP error subcode
@@ -633,6 +649,10 @@ void bgp_notify_send_with_data(struct peer *peer, u_char code, u_char sub_code,
        struct stream *s;
        int length;
 
+       /* Lock I/O mutex to prevent other threads from pushing packets */
+       pthread_mutex_lock(&peer->io_mtx);
+       /* ============================================== */
+
        /* Allocate new stream. */
        s = stream_new(BGP_MAX_PACKET_SIZE);
 
@@ -650,20 +670,8 @@ void bgp_notify_send_with_data(struct peer *peer, u_char code, u_char sub_code,
        /* Set BGP packet length. */
        length = bgp_packet_set_size(s);
 
-       /*
-        * Turn off keepalive generation for peer. This is necessary because
-        * otherwise between the time we wipe the output buffer and the time we
-        * push the NOTIFY onto it, the KA generation thread could have pushed
-        * a KEEPALIVE in the middle.
-        */
-       bgp_keepalives_off(peer);
-
        /* wipe output buffer */
-       pthread_mutex_lock(&peer->io_mtx);
-       {
-               stream_fifo_clean(peer->obuf);
-       }
-       pthread_mutex_unlock(&peer->io_mtx);
+       stream_fifo_clean(peer->obuf);
 
        /*
         * If possible, store last packet for debugging purposes. This check is
@@ -727,9 +735,12 @@ void bgp_notify_send_with_data(struct peer *peer, u_char code, u_char sub_code,
                peer->last_reset = PEER_DOWN_NOTIFY_SEND;
 
        /* Add packet to peer's output queue */
-       bgp_packet_add(peer, s);
+       stream_fifo_push(peer->obuf, s);
 
        bgp_write_notify(peer);
+
+       /* ============================================== */
+       pthread_mutex_unlock(&peer->io_mtx);
 }
 
 /*
@@ -1682,7 +1693,7 @@ static int bgp_notify_receive(struct peer *peer, bgp_size_t size)
        }
 
        /* peer count update */
-       peer->notify_in++;
+       atomic_fetch_add_explicit(&peer->notify_in, 1, memory_order_relaxed);
 
        peer->last_reset = PEER_DOWN_NOTIFY_RECEIVED;
 
@@ -2192,7 +2203,8 @@ int bgp_process_packet(struct thread *thread)
                 */
                switch (type) {
                case BGP_MSG_OPEN:
-                       peer->open_in++;
+                       atomic_fetch_add_explicit(&peer->open_in, 1,
+                                                 memory_order_relaxed);
                        mprc = bgp_open_receive(peer, size);
                        if (mprc == BGP_Stop)
                                zlog_err(
@@ -2200,7 +2212,8 @@ int bgp_process_packet(struct thread *thread)
                                        __FUNCTION__, peer->host);
                        break;
                case BGP_MSG_UPDATE:
-                       peer->update_in++;
+                       atomic_fetch_add_explicit(&peer->update_in, 1,
+                                                 memory_order_relaxed);
                        peer->readtime = monotime(NULL);
                        mprc = bgp_update_receive(peer, size);
                        if (mprc == BGP_Stop)
@@ -2209,7 +2222,8 @@ int bgp_process_packet(struct thread *thread)
                                        __FUNCTION__, peer->host);
                        break;
                case BGP_MSG_NOTIFY:
-                       peer->notify_in++;
+                       atomic_fetch_add_explicit(&peer->notify_in, 1,
+                                                 memory_order_relaxed);
                        mprc = bgp_notify_receive(peer, size);
                        if (mprc == BGP_Stop)
                                zlog_err(
@@ -2218,7 +2232,8 @@ int bgp_process_packet(struct thread *thread)
                        break;
                case BGP_MSG_KEEPALIVE:
                        peer->readtime = monotime(NULL);
-                       peer->keepalive_in++;
+                       atomic_fetch_add_explicit(&peer->keepalive_in, 1,
+                                                 memory_order_relaxed);
                        mprc = bgp_keepalive_receive(peer, size);
                        if (mprc == BGP_Stop)
                                zlog_err(
@@ -2227,7 +2242,8 @@ int bgp_process_packet(struct thread *thread)
                        break;
                case BGP_MSG_ROUTE_REFRESH_NEW:
                case BGP_MSG_ROUTE_REFRESH_OLD:
-                       peer->refresh_in++;
+                       atomic_fetch_add_explicit(&peer->refresh_in, 1,
+                                                 memory_order_relaxed);
                        mprc = bgp_route_refresh_receive(peer, size);
                        if (mprc == BGP_Stop)
                                zlog_err(
@@ -2235,7 +2251,8 @@ int bgp_process_packet(struct thread *thread)
                                        __FUNCTION__, peer->host);
                        break;
                case BGP_MSG_CAPABILITY:
-                       peer->dynamic_cap_in++;
+                       atomic_fetch_add_explicit(&peer->dynamic_cap_in, 1,
+                                                 memory_order_relaxed);
                        mprc = bgp_capability_receive(peer, size);
                        if (mprc == BGP_Stop)
                                zlog_err(
index 2323572488ec69688e8d4c24d927162b171774c3..20bf9635a3e040c410038fdc2fd35917d3d54784 100644 (file)
@@ -74,6 +74,9 @@
 #include "bgpd/bgp_evpn.h"
 #include "bgpd/bgp_evpn_vty.h"
 
+#ifndef VTYSH_EXTRACT_PL
+#include "bgpd/bgp_route_clippy.c"
+#endif
 
 /* Extern from bgp_dump.c */
 extern const char *bgp_origin_str[];
@@ -144,7 +147,8 @@ static struct bgp_info_extra *bgp_info_extra_new(void)
 {
        struct bgp_info_extra *new;
        new = XCALLOC(MTYPE_BGP_ROUTE_EXTRA, sizeof(struct bgp_info_extra));
-       new->label = MPLS_INVALID_LABEL;
+       new->label[0] = MPLS_INVALID_LABEL;
+       new->num_labels = 0;
        return new;
 }
 
@@ -767,9 +771,9 @@ static int bgp_info_cmp(struct bgp *bgp, struct bgp_info *new,
                /* If one path has a label but the other does not, do not treat
                 * them as equals for multipath
                 */
-               if ((new->extra &&bgp_is_valid_label(&new->extra->label))
+               if ((new->extra &&bgp_is_valid_label(&new->extra->label[0]))
                    != (exist->extra
-                       && bgp_is_valid_label(&exist->extra->label))) {
+                       && bgp_is_valid_label(&exist->extra->label[0]))) {
                        if (debug)
                                zlog_debug(
                                        "%s: %s and %s cannot be multipath, one has a label while the other does not",
@@ -1282,7 +1286,7 @@ void bgp_attr_add_gshut_community(struct attr *attr)
        if (old) {
                merge = community_merge(community_dup(old), gshut);
 
-               if (old->refcnt== 0)
+               if (old->refcnt == 0)
                        community_free(old);
 
                new = community_uniq_sort(merge);
@@ -1658,7 +1662,8 @@ int subgroup_announce_check(struct bgp_node *rn, struct bgp_info *ri,
        }
 
        if (bgp_flag_check(bgp, BGP_FLAG_GRACEFUL_SHUTDOWN)) {
-               if (peer->sort == BGP_PEER_IBGP || peer->sort == BGP_PEER_CONFED) {
+               if (peer->sort == BGP_PEER_IBGP
+                   || peer->sort == BGP_PEER_CONFED) {
                        attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF);
                        attr->local_pref = BGP_GSHUT_LOCAL_PREF;
                } else {
@@ -1714,8 +1719,8 @@ int subgroup_announce_check(struct bgp_node *rn, struct bgp_info *ri,
                                                             subgrp))
                                subgroup_announce_reset_nhop(
                                        (peer_cap_enhe(peer, afi, safi)
-                                        ? AF_INET6
-                                        : p->family),
+                                                ? AF_INET6
+                                                : p->family),
                                        attr);
                }
                /* If IPv6/MP and nexthop does not have any override and happens
@@ -1962,8 +1967,9 @@ int subgroup_process_announce_selected(struct update_subgroup *subgrp,
                                                 : NULL);
 
        /* First update is deferred until ORF or ROUTE-REFRESH is received */
-       if (onlypeer && CHECK_FLAG(onlypeer->af_sflags[afi][safi],
-                                  PEER_STATUS_ORF_WAIT_REFRESH))
+       if (onlypeer
+           && CHECK_FLAG(onlypeer->af_sflags[afi][safi],
+                         PEER_STATUS_ORF_WAIT_REFRESH))
                return 0;
 
        memset(&attr, 0, sizeof(struct attr));
@@ -2039,7 +2045,7 @@ int bgp_zebra_has_route_changed(struct bgp_node *rn, struct bgp_info *selected)
 
 struct bgp_process_queue {
        struct bgp *bgp;
-       STAILQ_HEAD(, bgp_node)pqueue;
+       STAILQ_HEAD(, bgp_node) pqueue;
 #define BGP_PROCESS_QUEUE_EOIU_MARKER          (1 << 0)
        unsigned int flags;
        unsigned int queued;
@@ -2095,13 +2101,14 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_node *rn,
                                                    rn->flags,
                                                    BGP_NODE_REGISTERED_FOR_LABEL))
                                                bgp_unregister_for_label(rn);
-                                       label_ntop(MPLS_IMP_NULL_LABEL, 1,
+                                       label_ntop(MPLS_LABEL_IMPLICIT_NULL, 1,
                                                   &rn->local_label);
                                        bgp_set_valid_label(&rn->local_label);
                                } else
                                        bgp_register_for_label(rn, new_select);
                        }
-               } else if (CHECK_FLAG(rn->flags, BGP_NODE_REGISTERED_FOR_LABEL)) {
+               } else if (CHECK_FLAG(rn->flags,
+                                     BGP_NODE_REGISTERED_FOR_LABEL)) {
                        bgp_unregister_for_label(rn);
                }
        } else if (CHECK_FLAG(rn->flags, BGP_NODE_REGISTERED_FOR_LABEL)) {
@@ -2219,6 +2226,15 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_node *rn,
                }
        }
 
+       /* advertise/withdraw type-5 routes */
+       if ((afi == AFI_IP || afi == AFI_IP6) && (safi == SAFI_UNICAST)) {
+               if (new_select)
+                       bgp_evpn_advertise_type5_route(
+                               bgp, &rn->p, new_select->attr, afi, safi);
+               else if (old_select)
+                       bgp_evpn_withdraw_type5_route(bgp, &rn->p, afi, safi);
+       }
+
        /* Clear any route change flags. */
        bgp_zebra_clear_route_change_flags(rn);
 
@@ -2293,7 +2309,8 @@ static struct bgp_process_queue *bgp_processq_alloc(struct bgp *bgp)
 {
        struct bgp_process_queue *pqnode;
 
-       pqnode = XCALLOC(MTYPE_BGP_PROCESS_QUEUE, sizeof(struct bgp_process_queue));
+       pqnode = XCALLOC(MTYPE_BGP_PROCESS_QUEUE,
+                        sizeof(struct bgp_process_queue));
 
        /* unlocked in bgp_processq_del */
        pqnode->bgp = bgp_lock(bgp);
@@ -2317,13 +2334,15 @@ void bgp_process(struct bgp *bgp, struct bgp_node *rn, afi_t afi, safi_t safi)
                return;
 
        /* Add route nodes to an existing work queue item until reaching the
-          limit only if is from the same BGP view and it's not an EOIU marker */
+          limit only if is from the same BGP view and it's not an EOIU marker
+        */
        if (work_queue_item_count(wq)) {
                struct work_queue_item *item = work_queue_last_item(wq);
                pqnode = item->data;
 
-               if (CHECK_FLAG(pqnode->flags, BGP_PROCESS_QUEUE_EOIU_MARKER) ||
-                   pqnode->bgp != bgp || pqnode->queued >= ARBITRARY_PROCESS_QLEN)
+               if (CHECK_FLAG(pqnode->flags, BGP_PROCESS_QUEUE_EOIU_MARKER)
+                   || pqnode->bgp != bgp
+                   || pqnode->queued >= ARBITRARY_PROCESS_QLEN)
                        pqnode = bgp_processq_alloc(bgp);
                else
                        pqnode_reuse = 1;
@@ -2660,7 +2679,8 @@ static int bgp_update_martian_nexthop(struct bgp *bgp, afi_t afi, safi_t safi,
 int bgp_update(struct peer *peer, struct prefix *p, u_int32_t addpath_id,
               struct attr *attr, afi_t afi, safi_t safi, int type,
               int sub_type, struct prefix_rd *prd, mpls_label_t *label,
-              int soft_reconfig, struct bgp_route_evpn *evpn)
+              u_int32_t num_labels, int soft_reconfig,
+              struct bgp_route_evpn *evpn)
 {
        int ret;
        int aspath_loop_count = 0;
@@ -2670,9 +2690,9 @@ int bgp_update(struct peer *peer, struct prefix *p, u_int32_t addpath_id,
        struct attr *attr_new;
        struct bgp_info *ri;
        struct bgp_info *new;
+       struct bgp_info_extra *extra;
        const char *reason;
        char pfx_buf[BGP_PRD_PATH_STRLEN];
-       char label_buf[20];
        int connected = 0;
        int do_loop_check = 1;
        int has_valid_label = 0;
@@ -2687,10 +2707,11 @@ int bgp_update(struct peer *peer, struct prefix *p, u_int32_t addpath_id,
 
        bgp = peer->bgp;
        rn = bgp_afi_node_get(bgp->rib[afi][safi], afi, safi, p, prd);
-       has_valid_label = bgp_is_valid_label(label);
-
-       if (has_valid_label)
-               sprintf(label_buf, "label %u", label_pton(label));
+       /* TODO: Check to see if we can get rid of "is_valid_label" */
+       if (afi == AFI_L2VPN && safi == SAFI_EVPN)
+               has_valid_label = (num_labels > 0) ? 1 : 0;
+       else
+               has_valid_label = bgp_is_valid_label(label);
 
        /* When peer's soft reconfiguration enabled.  Record input packet in
           Adj-RIBs-In.  */
@@ -2708,7 +2729,10 @@ int bgp_update(struct peer *peer, struct prefix *p, u_int32_t addpath_id,
 
        /* AS path local-as loop check. */
        if (peer->change_local_as) {
-               if (!CHECK_FLAG(peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND))
+               if (peer->allowas_in[afi][safi])
+                       aspath_loop_count = peer->allowas_in[afi][safi];
+               else if (!CHECK_FLAG(peer->flags,
+                                    PEER_FLAG_LOCAL_AS_NO_PREPEND))
                        aspath_loop_count = 1;
 
                if (aspath_loop_check(attr->aspath, peer->change_local_as)
@@ -2774,23 +2798,24 @@ int bgp_update(struct peer *peer, struct prefix *p, u_int32_t addpath_id,
 
        if (peer->sort == BGP_PEER_EBGP) {
 
-               /* If we receive the graceful-shutdown community from an eBGP peer we
-                * must lower local-preference */
-               if (new_attr.community &&
-                   community_include(new_attr.community, COMMUNITY_GSHUT)) {
+               /* If we receive the graceful-shutdown community from an eBGP
+                * peer we must lower local-preference */
+               if (new_attr.community
+                   && community_include(new_attr.community, COMMUNITY_GSHUT)) {
                        new_attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF);
                        new_attr.local_pref = BGP_GSHUT_LOCAL_PREF;
 
-               /* If graceful-shutdown is configured then add the GSHUT community to
-                * all paths received from eBGP peers */
-               } else if (bgp_flag_check(peer->bgp, BGP_FLAG_GRACEFUL_SHUTDOWN)) {
+                       /* If graceful-shutdown is configured then add the GSHUT
+                        * community to all paths received from eBGP peers */
+               } else if (bgp_flag_check(peer->bgp,
+                                         BGP_FLAG_GRACEFUL_SHUTDOWN)) {
                        bgp_attr_add_gshut_community(&new_attr);
                }
        }
 
        /* next hop check.  */
-       if (!CHECK_FLAG(peer->flags, PEER_FLAG_IS_RFAPI_HD) &&
-           bgp_update_martian_nexthop(bgp, afi, safi, &new_attr)) {
+       if (!CHECK_FLAG(peer->flags, PEER_FLAG_IS_RFAPI_HD)
+           && bgp_update_martian_nexthop(bgp, afi, safi, &new_attr)) {
                reason = "martian or self next-hop;";
                bgp_attr_flush(&new_attr);
                goto filtered;
@@ -2808,7 +2833,7 @@ int bgp_update(struct peer *peer, struct prefix *p, u_int32_t addpath_id,
                    && attrhash_cmp(ri->attr, attr_new)
                    && (!has_valid_label
                        || memcmp(&(bgp_info_extra_get(ri))->label, label,
-                                 BGP_LABEL_BYTES)
+                                 num_labels * sizeof(mpls_label_t))
                                   == 0)
                    && (overlay_index_equal(
                               afi, ri, evpn == NULL ? NULL : &evpn->eth_s_id,
@@ -2820,8 +2845,9 @@ int bgp_update(struct peer *peer, struct prefix *p, u_int32_t addpath_id,
                                if (bgp_debug_update(peer, p, NULL, 1)) {
                                        bgp_debug_rdpfxpath2str(
                                                afi, safi, prd, p, label,
-                                               addpath_id ? 1 : 0, addpath_id,
-                                               pfx_buf, sizeof(pfx_buf));
+                                               num_labels, addpath_id ? 1 : 0,
+                                               addpath_id, pfx_buf,
+                                               sizeof(pfx_buf));
                                        zlog_debug("%s rcvd %s", peer->host,
                                                   pfx_buf);
                                }
@@ -2845,8 +2871,9 @@ int bgp_update(struct peer *peer, struct prefix *p, u_int32_t addpath_id,
 
                                        bgp_debug_rdpfxpath2str(
                                                afi, safi, prd, p, label,
-                                               addpath_id ? 1 : 0, addpath_id,
-                                               pfx_buf, sizeof(pfx_buf));
+                                               num_labels, addpath_id ? 1 : 0,
+                                               addpath_id, pfx_buf,
+                                               sizeof(pfx_buf));
                                        zlog_debug(
                                                "%s rcvd %s...duplicate ignored",
                                                peer->host, pfx_buf);
@@ -2870,7 +2897,7 @@ int bgp_update(struct peer *peer, struct prefix *p, u_int32_t addpath_id,
                if (CHECK_FLAG(ri->flags, BGP_INFO_REMOVED)) {
                        if (bgp_debug_update(peer, p, NULL, 1)) {
                                bgp_debug_rdpfxpath2str(
-                                       afi, safi, prd, p, label,
+                                       afi, safi, prd, p, label, num_labels,
                                        addpath_id ? 1 : 0, addpath_id, pfx_buf,
                                        sizeof(pfx_buf));
                                zlog_debug(
@@ -2884,8 +2911,9 @@ int bgp_update(struct peer *peer, struct prefix *p, u_int32_t addpath_id,
                /* Received Logging. */
                if (bgp_debug_update(peer, p, NULL, 1)) {
                        bgp_debug_rdpfxpath2str(afi, safi, prd, p, label,
-                                               addpath_id ? 1 : 0, addpath_id,
-                                               pfx_buf, sizeof(pfx_buf));
+                                               num_labels, addpath_id ? 1 : 0,
+                                               addpath_id, pfx_buf,
+                                               sizeof(pfx_buf));
                        zlog_debug("%s rcvd %s", peer->host, pfx_buf);
                }
 
@@ -2974,9 +3002,12 @@ int bgp_update(struct peer *peer, struct prefix *p, u_int32_t addpath_id,
 
                /* Update MPLS label */
                if (has_valid_label) {
-                       memcpy(&(bgp_info_extra_get(ri))->label, label,
-                              BGP_LABEL_BYTES);
-                       bgp_set_valid_label(&(bgp_info_extra_get(ri))->label);
+                       extra = bgp_info_extra_get(ri);
+                       memcpy(&extra->label, label,
+                              num_labels * sizeof(mpls_label_t));
+                       extra->num_labels = num_labels;
+                       if (!(afi == AFI_L2VPN && safi == SAFI_EVPN))
+                               bgp_set_valid_label(&extra->label[0]);
                }
 
 #if ENABLE_BGP_VNC
@@ -3033,8 +3064,8 @@ int bgp_update(struct peer *peer, struct prefix *p, u_int32_t addpath_id,
                                connected = 0;
 
                        if (bgp_find_or_add_nexthop(bgp, afi, ri, NULL,
-                                                   connected) ||
-                           CHECK_FLAG(peer->flags, PEER_FLAG_IS_RFAPI_HD))
+                                                   connected)
+                           || CHECK_FLAG(peer->flags, PEER_FLAG_IS_RFAPI_HD))
                                bgp_info_set_flag(rn, ri, BGP_INFO_VALID);
                        else {
                                if (BGP_DEBUG(nht, NHT)) {
@@ -3113,7 +3144,7 @@ int bgp_update(struct peer *peer, struct prefix *p, u_int32_t addpath_id,
                        peer->rcvd_attr_printed = 1;
                }
 
-               bgp_debug_rdpfxpath2str(afi, safi, prd, p, label,
+               bgp_debug_rdpfxpath2str(afi, safi, prd, p, label, num_labels,
                                        addpath_id ? 1 : 0, addpath_id, pfx_buf,
                                        sizeof(pfx_buf));
                zlog_debug("%s rcvd %s", peer->host, pfx_buf);
@@ -3124,9 +3155,11 @@ int bgp_update(struct peer *peer, struct prefix *p, u_int32_t addpath_id,
 
        /* Update MPLS label */
        if (has_valid_label) {
-               memcpy(&(bgp_info_extra_get(new))->label, label,
-                      BGP_LABEL_BYTES);
-               bgp_set_valid_label(&(bgp_info_extra_get(new))->label);
+               extra = bgp_info_extra_get(new);
+               memcpy(&extra->label, label, num_labels * sizeof(mpls_label_t));
+               extra->num_labels = num_labels;
+               if (!(afi == AFI_L2VPN && safi == SAFI_EVPN))
+                       bgp_set_valid_label(&extra->label[0]);
        }
 
        /* Update Overlay Index */
@@ -3146,8 +3179,8 @@ int bgp_update(struct peer *peer, struct prefix *p, u_int32_t addpath_id,
                else
                        connected = 0;
 
-               if (bgp_find_or_add_nexthop(bgp, afi, new, NULL, connected) ||
-                   CHECK_FLAG(peer->flags, PEER_FLAG_IS_RFAPI_HD))
+               if (bgp_find_or_add_nexthop(bgp, afi, new, NULL, connected)
+                   || CHECK_FLAG(peer->flags, PEER_FLAG_IS_RFAPI_HD))
                        bgp_info_set_flag(rn, new, BGP_INFO_VALID);
                else {
                        if (BGP_DEBUG(nht, NHT)) {
@@ -3228,7 +3261,7 @@ filtered:
                        peer->rcvd_attr_printed = 1;
                }
 
-               bgp_debug_rdpfxpath2str(afi, safi, prd, p, label,
+               bgp_debug_rdpfxpath2str(afi, safi, prd, p, label, num_labels,
                                        addpath_id ? 1 : 0, addpath_id, pfx_buf,
                                        sizeof(pfx_buf));
                zlog_debug("%s rcvd UPDATE about %s -- DENIED due to: %s",
@@ -3264,7 +3297,7 @@ filtered:
 int bgp_withdraw(struct peer *peer, struct prefix *p, u_int32_t addpath_id,
                 struct attr *attr, afi_t afi, safi_t safi, int type,
                 int sub_type, struct prefix_rd *prd, mpls_label_t *label,
-                struct bgp_route_evpn *evpn)
+                u_int32_t num_labels, struct bgp_route_evpn *evpn)
 {
        struct bgp *bgp;
        char pfx_buf[BGP_PRD_PATH_STRLEN];
@@ -3299,7 +3332,7 @@ int bgp_withdraw(struct peer *peer, struct prefix *p, u_int32_t addpath_id,
                if (!bgp_adj_in_unset(rn, peer, addpath_id)) {
                        if (bgp_debug_update(peer, p, NULL, 1)) {
                                bgp_debug_rdpfxpath2str(
-                                       afi, safi, prd, p, label,
+                                       afi, safi, prd, p, label, num_labels,
                                        addpath_id ? 1 : 0, addpath_id, pfx_buf,
                                        sizeof(pfx_buf));
                                zlog_debug(
@@ -3319,7 +3352,7 @@ int bgp_withdraw(struct peer *peer, struct prefix *p, u_int32_t addpath_id,
 
        /* Logging. */
        if (bgp_debug_update(peer, p, NULL, 1)) {
-               bgp_debug_rdpfxpath2str(afi, safi, prd, p, label,
+               bgp_debug_rdpfxpath2str(afi, safi, prd, p, label, num_labels,
                                        addpath_id ? 1 : 0, addpath_id, pfx_buf,
                                        sizeof(pfx_buf));
                zlog_debug("%s rcvd UPDATE about %s -- withdrawn", peer->host,
@@ -3330,7 +3363,7 @@ int bgp_withdraw(struct peer *peer, struct prefix *p, u_int32_t addpath_id,
        if (ri && !CHECK_FLAG(ri->flags, BGP_INFO_HISTORY))
                bgp_rib_withdraw(rn, ri, peer, afi, safi, prd);
        else if (bgp_debug_update(peer, p, NULL, 1)) {
-               bgp_debug_rdpfxpath2str(afi, safi, prd, p, label,
+               bgp_debug_rdpfxpath2str(afi, safi, prd, p, label, num_labels,
                                        addpath_id ? 1 : 0, addpath_id, pfx_buf,
                                        sizeof(pfx_buf));
                zlog_debug("%s Can't find the route %s", peer->host, pfx_buf);
@@ -3456,14 +3489,18 @@ static void bgp_soft_reconfig_table(struct peer *peer, afi_t afi, safi_t safi,
                                continue;
 
                        struct bgp_info *ri = rn->info;
-                       mpls_label_t label = (ri && ri->extra)
-                                                    ? ri->extra->label
-                                                    : MPLS_INVALID_LABEL;
+                       u_int32_t num_labels = 0;
+                       mpls_label_t *label_pnt = NULL;
+
+                       if (ri && ri->extra)
+                               num_labels = ri->extra->num_labels;
+                       if (num_labels)
+                               label_pnt = &ri->extra->label[0];
 
                        ret = bgp_update(peer, &rn->p, ain->addpath_rx_id,
                                         ain->attr, afi, safi, ZEBRA_ROUTE_BGP,
-                                        BGP_ROUTE_NORMAL, prd, &label, 1,
-                                        NULL);
+                                        BGP_ROUTE_NORMAL, prd, label_pnt,
+                                        num_labels, 1, NULL);
 
                        if (ret < 0) {
                                bgp_unlock_node(rn);
@@ -3978,7 +4015,7 @@ int bgp_nlri_parse_ip(struct peer *peer, struct attr *attr,
                                 * an error SHOULD
                                 * be logged locally, and the prefix SHOULD be
                                 * ignored.
-                                 */
+                                */
                                zlog_err(
                                        "%s: IPv4 unicast NLRI is multicast address %s, ignoring",
                                        peer->host, inet_ntoa(p.u.prefix4));
@@ -4016,11 +4053,12 @@ int bgp_nlri_parse_ip(struct peer *peer, struct attr *attr,
                if (attr)
                        ret = bgp_update(peer, &p, addpath_id, attr, afi, safi,
                                         ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL,
-                                        NULL, NULL, 0, NULL);
+                                        NULL, NULL, 0, 0, NULL);
                else
                        ret = bgp_withdraw(peer, &p, addpath_id, attr, afi,
                                           safi, ZEBRA_ROUTE_BGP,
-                                          BGP_ROUTE_NORMAL, NULL, NULL, NULL);
+                                          BGP_ROUTE_NORMAL, NULL, NULL, 0,
+                                          NULL);
 
                /* Address family configuration mismatch or maximum-prefix count
                   overflow. */
@@ -4332,10 +4370,13 @@ static void bgp_static_update_safi(struct bgp *bgp, struct prefix *p,
 #if ENABLE_BGP_VNC
        mpls_label_t label = 0;
 #endif
+       u_int32_t num_labels = 0;
        union gw_addr add;
 
        assert(bgp_static);
 
+       if (bgp_static->label != MPLS_INVALID_LABEL)
+               num_labels = 1;
        rn = bgp_afi_node_get(bgp->rib[afi][safi], afi, safi, p,
                              &bgp_static->prd);
 
@@ -4430,7 +4471,7 @@ static void bgp_static_update_safi(struct bgp *bgp, struct prefix *p,
                        ri->uptime = bgp_clock();
 #if ENABLE_BGP_VNC
                        if (ri->extra)
-                               label = decode_label(&ri->extra->label);
+                               label = decode_label(&ri->extra->label[0]);
 #endif
 
                        /* Process change. */
@@ -4453,7 +4494,10 @@ static void bgp_static_update_safi(struct bgp *bgp, struct prefix *p,
                        attr_new, rn);
        SET_FLAG(new->flags, BGP_INFO_VALID);
        new->extra = bgp_info_extra_new();
-       new->extra->label = bgp_static->label;
+       if (num_labels) {
+               new->extra->label[0] = bgp_static->label;
+               new->extra->num_labels = num_labels;
+       }
 #if ENABLE_BGP_VNC
        label = decode_label(&bgp_static->label);
 #endif
@@ -4480,9 +4524,9 @@ static void bgp_static_update_safi(struct bgp *bgp, struct prefix *p,
 
 /* Configure static BGP network.  When user don't run zebra, static
    route should be installed as valid.  */
-static int bgp_static_set(struct vty *vty, const char *ip_str, afi_t afi,
-                         safi_t safi, const char *rmap, int backdoor,
-                         u_int32_t label_index)
+static int bgp_static_set(struct vty *vty, const char *negate,
+                         const char *ip_str, afi_t afi, safi_t safi,
+                         const char *rmap, int backdoor, u_int32_t label_index)
 {
        VTY_DECLVAR_CONTEXT(bgp, bgp);
        int ret;
@@ -4504,112 +4548,108 @@ static int bgp_static_set(struct vty *vty, const char *ip_str, afi_t afi,
 
        apply_mask(&p);
 
-       /* Set BGP static route configuration. */
-       rn = bgp_node_get(bgp->route[afi][safi], &p);
+       if (negate) {
 
-       if (rn->info) {
-               /* Configuration change. */
-               bgp_static = rn->info;
+               /* Set BGP static route configuration. */
+               rn = bgp_node_lookup(bgp->route[afi][safi], &p);
 
-               /* Label index cannot be changed. */
-               if (bgp_static->label_index != label_index) {
-                       vty_out(vty, "%% Label index cannot be changed\n");
+               if (!rn) {
+                       vty_out(vty, "%% Can't find static route specified\n");
                        return CMD_WARNING_CONFIG_FAILED;
                }
 
-               /* Check previous routes are installed into BGP.  */
-               if (bgp_static->valid && bgp_static->backdoor != backdoor)
-                       need_update = 1;
-
-               bgp_static->backdoor = backdoor;
+               bgp_static = rn->info;
 
-               if (rmap) {
-                       if (bgp_static->rmap.name)
-                               XFREE(MTYPE_ROUTE_MAP_NAME,
-                                     bgp_static->rmap.name);
-                       bgp_static->rmap.name =
-                               XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap);
-                       bgp_static->rmap.map = route_map_lookup_by_name(rmap);
-               } else {
-                       if (bgp_static->rmap.name)
-                               XFREE(MTYPE_ROUTE_MAP_NAME,
-                                     bgp_static->rmap.name);
-                       bgp_static->rmap.name = NULL;
-                       bgp_static->rmap.map = NULL;
-                       bgp_static->valid = 0;
+               if ((label_index != BGP_INVALID_LABEL_INDEX)
+                   && (label_index != bgp_static->label_index)) {
+                       vty_out(vty,
+                               "%% label-index doesn't match static route\n");
+                       return CMD_WARNING_CONFIG_FAILED;
                }
-               bgp_unlock_node(rn);
-       } else {
-               /* New configuration. */
-               bgp_static = bgp_static_new();
-               bgp_static->backdoor = backdoor;
-               bgp_static->valid = 0;
-               bgp_static->igpmetric = 0;
-               bgp_static->igpnexthop.s_addr = 0;
-               bgp_static->label_index = label_index;
 
-               if (rmap) {
-                       if (bgp_static->rmap.name)
-                               XFREE(MTYPE_ROUTE_MAP_NAME,
-                                     bgp_static->rmap.name);
-                       bgp_static->rmap.name =
-                               XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap);
-                       bgp_static->rmap.map = route_map_lookup_by_name(rmap);
+               if ((rmap && bgp_static->rmap.name)
+                   && strcmp(rmap, bgp_static->rmap.name)) {
+                       vty_out(vty,
+                               "%% route-map name doesn't match static route\n");
+                       return CMD_WARNING_CONFIG_FAILED;
                }
-               rn->info = bgp_static;
-       }
-
-       bgp_static->valid = 1;
-       if (need_update)
-               bgp_static_withdraw(bgp, &p, afi, safi);
-
-       if (!bgp_static->backdoor)
-               bgp_static_update(bgp, &p, bgp_static, afi, safi);
 
-       return CMD_SUCCESS;
-}
+               /* Update BGP RIB. */
+               if (!bgp_static->backdoor)
+                       bgp_static_withdraw(bgp, &p, afi, safi);
 
-/* Configure static BGP network. */
-static int bgp_static_unset(struct vty *vty, const char *ip_str, afi_t afi,
-                           safi_t safi)
-{
-       VTY_DECLVAR_CONTEXT(bgp, bgp);
-       int ret;
-       struct prefix p;
-       struct bgp_static *bgp_static;
-       struct bgp_node *rn;
+               /* Clear configuration. */
+               bgp_static_free(bgp_static);
+               rn->info = NULL;
+               bgp_unlock_node(rn);
+               bgp_unlock_node(rn);
+       } else {
 
-       /* Convert IP prefix string to struct prefix. */
-       ret = str2prefix(ip_str, &p);
-       if (!ret) {
-               vty_out(vty, "%% Malformed prefix\n");
-               return CMD_WARNING_CONFIG_FAILED;
-       }
-       if (afi == AFI_IP6 && IN6_IS_ADDR_LINKLOCAL(&p.u.prefix6)) {
-               vty_out(vty, "%% Malformed prefix (link-local address)\n");
-               return CMD_WARNING_CONFIG_FAILED;
-       }
+               /* Set BGP static route configuration. */
+               rn = bgp_node_get(bgp->route[afi][safi], &p);
 
-       apply_mask(&p);
+               if (rn->info) {
+                       /* Configuration change. */
+                       bgp_static = rn->info;
 
-       rn = bgp_node_lookup(bgp->route[afi][safi], &p);
-       if (!rn) {
-               vty_out(vty,
-                       "%% Can't find specified static route configuration.\n");
-               return CMD_WARNING_CONFIG_FAILED;
-       }
+                       /* Label index cannot be changed. */
+                       if (bgp_static->label_index != label_index) {
+                               vty_out(vty, "%% cannot change label-index\n");
+                               return CMD_WARNING_CONFIG_FAILED;
+                       }
 
-       bgp_static = rn->info;
+                       /* Check previous routes are installed into BGP.  */
+                       if (bgp_static->valid
+                           && bgp_static->backdoor != backdoor)
+                               need_update = 1;
+
+                       bgp_static->backdoor = backdoor;
+
+                       if (rmap) {
+                               if (bgp_static->rmap.name)
+                                       XFREE(MTYPE_ROUTE_MAP_NAME,
+                                             bgp_static->rmap.name);
+                               bgp_static->rmap.name =
+                                       XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap);
+                               bgp_static->rmap.map =
+                                       route_map_lookup_by_name(rmap);
+                       } else {
+                               if (bgp_static->rmap.name)
+                                       XFREE(MTYPE_ROUTE_MAP_NAME,
+                                             bgp_static->rmap.name);
+                               bgp_static->rmap.name = NULL;
+                               bgp_static->rmap.map = NULL;
+                               bgp_static->valid = 0;
+                       }
+                       bgp_unlock_node(rn);
+               } else {
+                       /* New configuration. */
+                       bgp_static = bgp_static_new();
+                       bgp_static->backdoor = backdoor;
+                       bgp_static->valid = 0;
+                       bgp_static->igpmetric = 0;
+                       bgp_static->igpnexthop.s_addr = 0;
+                       bgp_static->label_index = label_index;
+
+                       if (rmap) {
+                               if (bgp_static->rmap.name)
+                                       XFREE(MTYPE_ROUTE_MAP_NAME,
+                                             bgp_static->rmap.name);
+                               bgp_static->rmap.name =
+                                       XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap);
+                               bgp_static->rmap.map =
+                                       route_map_lookup_by_name(rmap);
+                       }
+                       rn->info = bgp_static;
+               }
 
-       /* Update BGP RIB. */
-       if (!bgp_static->backdoor)
-               bgp_static_withdraw(bgp, &p, afi, safi);
+               bgp_static->valid = 1;
+               if (need_update)
+                       bgp_static_withdraw(bgp, &p, afi, safi);
 
-       /* Clear configuration. */
-       bgp_static_free(bgp_static);
-       rn->info = NULL;
-       bgp_unlock_node(rn);
-       bgp_unlock_node(rn);
+               if (!bgp_static->backdoor)
+                       bgp_static_update(bgp, &p, bgp_static, afi, safi);
+       }
 
        return CMD_SUCCESS;
 }
@@ -5036,387 +5076,60 @@ DEFUN (no_bgp_table_map,
                                   argv[idx_word]->arg);
 }
 
-DEFUN (bgp_network,
-       bgp_network_cmd,
-       "network A.B.C.D/M",
-       "Specify a network to announce via BGP\n"
-       "IPv4 prefix\n")
-{
-       int idx_ipv4_prefixlen = 1;
-       return bgp_static_set(vty, argv[idx_ipv4_prefixlen]->arg, AFI_IP,
-                             bgp_node_safi(vty), NULL, 0,
-                             BGP_INVALID_LABEL_INDEX);
-}
-
-DEFUN (bgp_network_route_map,
-       bgp_network_route_map_cmd,
-       "network A.B.C.D/M route-map WORD",
-       "Specify a network to announce via BGP\n"
-       "IPv4 prefix\n"
-       "Route-map to modify the attributes\n"
-       "Name of the route map\n")
-{
-       int idx_ipv4_prefixlen = 1;
-       int idx_word = 3;
-       return bgp_static_set(vty, argv[idx_ipv4_prefixlen]->arg, AFI_IP,
-                             bgp_node_safi(vty), argv[idx_word]->arg, 0,
-                             BGP_INVALID_LABEL_INDEX);
-}
-
-DEFUN (bgp_network_backdoor,
-       bgp_network_backdoor_cmd,
-       "network A.B.C.D/M backdoor",
-       "Specify a network to announce via BGP\n"
-       "IPv4 prefix\n"
-       "Specify a BGP backdoor route\n")
-{
-       int idx_ipv4_prefixlen = 1;
-       return bgp_static_set(vty, argv[idx_ipv4_prefixlen]->arg, AFI_IP,
-                             SAFI_UNICAST, NULL, 1, BGP_INVALID_LABEL_INDEX);
-}
-
-DEFUN (bgp_network_mask,
-       bgp_network_mask_cmd,
-       "network A.B.C.D mask A.B.C.D",
-       "Specify a network to announce via BGP\n"
-       "Network number\n"
-       "Network mask\n"
-       "Network mask\n")
-{
-       int idx_ipv4 = 1;
-       int idx_ipv4_2 = 3;
-       int ret;
-       char prefix_str[BUFSIZ];
-
-       ret = netmask_str2prefix_str(argv[idx_ipv4]->arg, argv[idx_ipv4_2]->arg,
-                                    prefix_str);
-       if (!ret) {
-               vty_out(vty, "%% Inconsistent address and mask\n");
-               return CMD_WARNING_CONFIG_FAILED;
-       }
-
-       return bgp_static_set(vty, prefix_str, AFI_IP, bgp_node_safi(vty), NULL,
-                             0, BGP_INVALID_LABEL_INDEX);
-}
-
-DEFUN (bgp_network_mask_route_map,
-       bgp_network_mask_route_map_cmd,
-       "network A.B.C.D mask A.B.C.D route-map WORD",
-       "Specify a network to announce via BGP\n"
-       "Network number\n"
-       "Network mask\n"
-       "Network mask\n"
-       "Route-map to modify the attributes\n"
-       "Name of the route map\n")
-{
-       int idx_ipv4 = 1;
-       int idx_ipv4_2 = 3;
-       int idx_word = 5;
-       int ret;
-       char prefix_str[BUFSIZ];
-
-       ret = netmask_str2prefix_str(argv[idx_ipv4]->arg, argv[idx_ipv4_2]->arg,
-                                    prefix_str);
-       if (!ret) {
-               vty_out(vty, "%% Inconsistent address and mask\n");
-               return CMD_WARNING_CONFIG_FAILED;
-       }
-
-       return bgp_static_set(vty, prefix_str, AFI_IP, bgp_node_safi(vty),
-                             argv[idx_word]->arg, 0, BGP_INVALID_LABEL_INDEX);
-}
-
-DEFUN (bgp_network_mask_backdoor,
-       bgp_network_mask_backdoor_cmd,
-       "network A.B.C.D mask A.B.C.D backdoor",
-       "Specify a network to announce via BGP\n"
-       "Network number\n"
-       "Network mask\n"
-       "Network mask\n"
-       "Specify a BGP backdoor route\n")
-{
-       int idx_ipv4 = 1;
-       int idx_ipv4_2 = 3;
-       int ret;
-       char prefix_str[BUFSIZ];
-
-       ret = netmask_str2prefix_str(argv[idx_ipv4]->arg, argv[idx_ipv4_2]->arg,
-                                    prefix_str);
-       if (!ret) {
-               vty_out(vty, "%% Inconsistent address and mask\n");
-               return CMD_WARNING_CONFIG_FAILED;
-       }
-
-       return bgp_static_set(vty, prefix_str, AFI_IP, SAFI_UNICAST, NULL, 1,
-                             BGP_INVALID_LABEL_INDEX);
-}
-
-DEFUN (bgp_network_mask_natural,
-       bgp_network_mask_natural_cmd,
-       "network A.B.C.D",
-       "Specify a network to announce via BGP\n"
-       "Network number\n")
-{
-       int idx_ipv4 = 1;
-       int ret;
-       char prefix_str[BUFSIZ];
-
-       ret = netmask_str2prefix_str(argv[idx_ipv4]->arg, NULL, prefix_str);
-       if (!ret) {
-               vty_out(vty, "%% Inconsistent address and mask\n");
-               return CMD_WARNING_CONFIG_FAILED;
-       }
-
-       return bgp_static_set(vty, prefix_str, AFI_IP, bgp_node_safi(vty), NULL,
-                             0, BGP_INVALID_LABEL_INDEX);
-}
-
-DEFUN (bgp_network_mask_natural_route_map,
-       bgp_network_mask_natural_route_map_cmd,
-       "network A.B.C.D route-map WORD",
-       "Specify a network to announce via BGP\n"
-       "Network number\n"
-       "Route-map to modify the attributes\n"
-       "Name of the route map\n")
-{
-       int idx_ipv4 = 1;
-       int idx_word = 3;
-       int ret;
-       char prefix_str[BUFSIZ];
-
-       ret = netmask_str2prefix_str(argv[idx_ipv4]->arg, NULL, prefix_str);
-       if (!ret) {
-               vty_out(vty, "%% Inconsistent address and mask\n");
-               return CMD_WARNING_CONFIG_FAILED;
-       }
-
-       return bgp_static_set(vty, prefix_str, AFI_IP, bgp_node_safi(vty),
-                             argv[idx_word]->arg, 0, BGP_INVALID_LABEL_INDEX);
-}
-
-DEFUN (bgp_network_mask_natural_backdoor,
-       bgp_network_mask_natural_backdoor_cmd,
-       "network A.B.C.D backdoor",
-       "Specify a network to announce via BGP\n"
-       "Network number\n"
-       "Specify a BGP backdoor route\n")
-{
-       int idx_ipv4 = 1;
-       int ret;
-       char prefix_str[BUFSIZ];
-
-       ret = netmask_str2prefix_str(argv[idx_ipv4]->arg, NULL, prefix_str);
-       if (!ret) {
-               vty_out(vty, "%% Inconsistent address and mask\n");
-               return CMD_WARNING_CONFIG_FAILED;
-       }
-
-       return bgp_static_set(vty, prefix_str, AFI_IP, SAFI_UNICAST, NULL, 1,
-                             BGP_INVALID_LABEL_INDEX);
-}
-
-DEFUN (bgp_network_label_index,
-       bgp_network_label_index_cmd,
-       "network A.B.C.D/M label-index (0-1048560)",
-       "Specify a network to announce via BGP\n"
-       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
-       "Label index to associate with the prefix\n"
-       "Label index value\n")
-{
-       u_int32_t label_index;
-
-       label_index = strtoul(argv[3]->arg, NULL, 10);
-       return bgp_static_set(vty, argv[1]->arg, AFI_IP, bgp_node_safi(vty),
-                             NULL, 0, label_index);
-}
-
-DEFUN (bgp_network_label_index_route_map,
-       bgp_network_label_index_route_map_cmd,
-       "network A.B.C.D/M label-index (0-1048560) route-map WORD",
-       "Specify a network to announce via BGP\n"
-       "IP prefix\n"
-       "Label index to associate with the prefix\n"
-       "Label index value\n"
-       "Route-map to modify the attributes\n"
-       "Name of the route map\n")
-{
-       u_int32_t label_index;
-
-       label_index = strtoul(argv[3]->arg, NULL, 10);
-       return bgp_static_set(vty, argv[1]->arg, AFI_IP, bgp_node_safi(vty),
-                             argv[5]->arg, 0, label_index);
-}
-
-DEFUN (no_bgp_network,
-       no_bgp_network_cmd,
-       "no network A.B.C.D/M [<backdoor|route-map WORD>]",
-       NO_STR
-       "Specify a network to announce via BGP\n"
-       "IPv4 prefix\n"
-       "Specify a BGP backdoor route\n"
-       "Route-map to modify the attributes\n"
-       "Name of the route map\n")
-{
-       int idx_ipv4_prefixlen = 2;
-       return bgp_static_unset(vty, argv[idx_ipv4_prefixlen]->arg, AFI_IP,
-                               bgp_node_safi(vty));
-}
-
-DEFUN (no_bgp_network_mask,
-       no_bgp_network_mask_cmd,
-       "no network A.B.C.D mask A.B.C.D [<backdoor|route-map WORD>]",
-       NO_STR
-       "Specify a network to announce via BGP\n"
-       "Network number\n"
-       "Network mask\n"
-       "Network mask\n"
-       "Specify a BGP backdoor route\n"
-       "Route-map to modify the attributes\n"
-       "Name of the route map\n")
-{
-       int idx_ipv4 = 2;
-       int idx_ipv4_2 = 4;
-       int ret;
-       char prefix_str[BUFSIZ];
-
-       ret = netmask_str2prefix_str(argv[idx_ipv4]->arg, argv[idx_ipv4_2]->arg,
-                                    prefix_str);
-       if (!ret) {
-               vty_out(vty, "%% Inconsistent address and mask\n");
-               return CMD_WARNING_CONFIG_FAILED;
-       }
-
-       return bgp_static_unset(vty, prefix_str, AFI_IP, bgp_node_safi(vty));
-}
-
-DEFUN (no_bgp_network_mask_natural,
-       no_bgp_network_mask_natural_cmd,
-       "no network A.B.C.D [<backdoor|route-map WORD>]",
-       NO_STR
-       "Specify a network to announce via BGP\n"
-       "Network number\n"
-       "Specify a BGP backdoor route\n"
-       "Route-map to modify the attributes\n"
-       "Name of the route map\n")
-{
-       int idx_ipv4 = 2;
-       int ret;
-       char prefix_str[BUFSIZ];
+DEFPY(bgp_network,
+       bgp_network_cmd,
+       "[no] network \
+       <A.B.C.D/M$prefix|A.B.C.D$address [mask A.B.C.D$netmask]> \
+       [{route-map WORD$map_name|label-index (0-1048560)$label_index| \
+       backdoor$backdoor}]",
+       NO_STR
+       "Specify a network to announce via BGP\n"
+       "IPv4 prefix\n"
+       "Network number\n"
+       "Network mask\n"
+       "Network mask\n"
+       "Route-map to modify the attributes\n"
+       "Name of the route map\n"
+       "Label index to associate with the prefix\n"
+       "Label index value\n"
+       "Specify a BGP backdoor route\n")
+{
+       char addr_prefix_str[BUFSIZ];
+
+       if (address_str) {
+               int ret;
 
-       ret = netmask_str2prefix_str(argv[idx_ipv4]->arg, NULL, prefix_str);
-       if (!ret) {
-               vty_out(vty, "%% Inconsistent address and mask\n");
-               return CMD_WARNING_CONFIG_FAILED;
+               ret = netmask_str2prefix_str(address_str, netmask_str,
+                                            addr_prefix_str);
+               if (!ret) {
+                       vty_out(vty, "%% Inconsistent address and mask\n");
+                       return CMD_WARNING_CONFIG_FAILED;
+               }
        }
 
-       return bgp_static_unset(vty, prefix_str, AFI_IP, bgp_node_safi(vty));
-}
-
-ALIAS(no_bgp_network, no_bgp_network_label_index_cmd,
-      "no network A.B.C.D/M label-index (0-1048560)", NO_STR
-      "Specify a network to announce via BGP\n"
-      "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
-      "Label index to associate with the prefix\n"
-      "Label index value\n")
-
-ALIAS(no_bgp_network, no_bgp_network_label_index_route_map_cmd,
-      "no network A.B.C.D/M label-index (0-1048560) route-map WORD", NO_STR
-      "Specify a network to announce via BGP\n"
-      "IP prefix\n"
-      "Label index to associate with the prefix\n"
-      "Label index value\n"
-      "Route-map to modify the attributes\n"
-      "Name of the route map\n")
-
-DEFUN (ipv6_bgp_network,
-       ipv6_bgp_network_cmd,
-       "network X:X::X:X/M",
-       "Specify a network to announce via BGP\n"
-       "IPv6 prefix\n")
-{
-       int idx_ipv6_prefixlen = 1;
-       return bgp_static_set(vty, argv[idx_ipv6_prefixlen]->arg, AFI_IP6,
-                             bgp_node_safi(vty), NULL, 0,
-                             BGP_INVALID_LABEL_INDEX);
-}
-
-DEFUN (ipv6_bgp_network_route_map,
-       ipv6_bgp_network_route_map_cmd,
-       "network X:X::X:X/M route-map WORD",
-       "Specify a network to announce via BGP\n"
-       "IPv6 prefix\n"
-       "Route-map to modify the attributes\n"
-       "Name of the route map\n")
-{
-       int idx_ipv6_prefixlen = 1;
-       int idx_word = 3;
-       return bgp_static_set(vty, argv[idx_ipv6_prefixlen]->arg, AFI_IP6,
-                             bgp_node_safi(vty), argv[idx_word]->arg, 0,
-                             BGP_INVALID_LABEL_INDEX);
-}
-
-DEFUN (ipv6_bgp_network_label_index,
-       ipv6_bgp_network_label_index_cmd,
-       "network X:X::X:X/M label-index (0-1048560)",
-       "Specify a network to announce via BGP\n"
-       "IPv6 prefix <network>/<length>\n"
-       "Label index to associate with the prefix\n"
-       "Label index value\n")
-{
-       u_int32_t label_index;
-
-       label_index = strtoul(argv[3]->arg, NULL, 10);
-       return bgp_static_set(vty, argv[1]->arg, AFI_IP6, bgp_node_safi(vty),
-                             NULL, 0, label_index);
-}
-
-DEFUN (ipv6_bgp_network_label_index_route_map,
-       ipv6_bgp_network_label_index_route_map_cmd,
-       "network X:X::X:X/M label-index (0-1048560) route-map WORD",
-       "Specify a network to announce via BGP\n"
-       "IPv6 prefix\n"
-       "Label index to associate with the prefix\n"
-       "Label index value\n"
-       "Route-map to modify the attributes\n"
-       "Name of the route map\n")
-{
-       u_int32_t label_index;
-
-       label_index = strtoul(argv[3]->arg, NULL, 10);
-       return bgp_static_set(vty, argv[1]->arg, AFI_IP6, bgp_node_safi(vty),
-                             argv[5]->arg, 0, label_index);
+       return bgp_static_set(
+               vty, no, address_str ? addr_prefix_str : prefix_str, AFI_IP,
+               bgp_node_safi(vty), map_name, backdoor ? 1 : 0,
+               label_index ? (uint32_t)label_index : BGP_INVALID_LABEL_INDEX);
 }
 
-DEFUN (no_ipv6_bgp_network,
-       no_ipv6_bgp_network_cmd,
-       "no network X:X::X:X/M [route-map WORD]",
-       NO_STR
-       "Specify a network to announce via BGP\n"
-       "IPv6 prefix\n"
-       "Route-map to modify the attributes\n"
-       "Name of the route map\n")
+DEFPY(ipv6_bgp_network,
+       ipv6_bgp_network_cmd,
+       "[no] network X:X::X:X/M$prefix \
+       [{route-map WORD$map_name|label-index (0-1048560)$label_index}]",
+       NO_STR
+       "Specify a network to announce via BGP\n"
+       "IPv6 prefix\n"
+       "Route-map to modify the attributes\n"
+       "Name of the route map\n"
+       "Label index to associate with the prefix\n"
+       "Label index value\n")
 {
-       int idx_ipv6_prefixlen = 2;
-       return bgp_static_unset(vty, argv[idx_ipv6_prefixlen]->arg, AFI_IP6,
-                               bgp_node_safi(vty));
+       return bgp_static_set(
+               vty, no, prefix_str, AFI_IP6, bgp_node_safi(vty), map_name, 0,
+               label_index ? (uint32_t)label_index : BGP_INVALID_LABEL_INDEX);
 }
 
-ALIAS(no_ipv6_bgp_network, no_ipv6_bgp_network_label_index_cmd,
-      "no network X:X::X:X/M label-index (0-1048560)", NO_STR
-      "Specify a network to announce via BGP\n"
-      "IPv6 prefix <network>/<length>\n"
-      "Label index to associate with the prefix\n"
-      "Label index value\n")
-
-ALIAS(no_ipv6_bgp_network, no_ipv6_bgp_network_label_index_route_map_cmd,
-      "no network X:X::X:X/M label-index (0-1048560) route-map WORD", NO_STR
-      "Specify a network to announce via BGP\n"
-      "IPv6 prefix\n"
-      "Label index to associate with the prefix\n"
-      "Label index value\n"
-      "Route-map to modify the attributes\n"
-      "Name of the route map\n")
-
 /* Aggreagete address:
 
   advertise-map  Set condition to advertise attribute
@@ -6139,8 +5852,7 @@ DEFUN (no_ipv6_aggregate_address,
 void bgp_redistribute_add(struct bgp *bgp, struct prefix *p,
                          const union g_addr *nexthop, ifindex_t ifindex,
                          enum nexthop_types_t nhtype, uint32_t metric,
-                         u_char type, u_short instance,
-                         route_tag_t tag)
+                         u_char type, u_short instance, route_tag_t tag)
 {
        struct bgp_info *new;
        struct bgp_info *bi;
@@ -6155,7 +5867,7 @@ void bgp_redistribute_add(struct bgp *bgp, struct prefix *p,
        /* Make default attribute. */
        bgp_attr_default_set(&attr, BGP_ORIGIN_INCOMPLETE);
 
-       switch(nhtype) {
+       switch (nhtype) {
        case NEXTHOP_TYPE_IFINDEX:
                break;
        case NEXTHOP_TYPE_IPV4:
@@ -6536,13 +6248,13 @@ void route_vty_out(struct vty *vty, struct prefix *p, struct bgp_info *binfo,
                switch (af) {
                case AF_INET:
                        sprintf(nexthop, "%s",
-                               inet_ntop(af, &attr->mp_nexthop_global_in,
-                                         buf, BUFSIZ));
+                               inet_ntop(af, &attr->mp_nexthop_global_in, buf,
+                                         BUFSIZ));
                        break;
                case AF_INET6:
                        sprintf(nexthop, "%s",
-                               inet_ntop(af, &attr->mp_nexthop_global,
-                                         buf, BUFSIZ));
+                               inet_ntop(af, &attr->mp_nexthop_global, buf,
+                                         BUFSIZ));
                        break;
                default:
                        sprintf(nexthop, "?");
@@ -6552,13 +6264,10 @@ void route_vty_out(struct vty *vty, struct prefix *p, struct bgp_info *binfo,
                if (json_paths) {
                        json_nexthop_global = json_object_new_object();
 
+                       json_object_string_add(json_nexthop_global, "afi",
+                                              (af == AF_INET) ? "ip" : "ipv6");
                        json_object_string_add(json_nexthop_global,
-                                              "afi",
-                                              (af == AF_INET) ?
-                                              "ip" : "ipv6");
-                       json_object_string_add(json_nexthop_global,
-                                              (af == AF_INET) ?
-                                              "ip" : "ipv6",
+                                              (af == AF_INET) ? "ip" : "ipv6",
                                               nexthop);
                        json_object_boolean_true_add(json_nexthop_global,
                                                     "used");
@@ -6570,92 +6279,80 @@ void route_vty_out(struct vty *vty, struct prefix *p, struct bgp_info *binfo,
 
                        json_object_string_add(json_nexthop_global, "ip",
                                               inet_ntoa(attr->nexthop));
-                       json_object_string_add(json_nexthop_global,
-                                              "afi", "ipv4");
+                       json_object_string_add(json_nexthop_global, "afi",
+                                              "ipv4");
                        json_object_boolean_true_add(json_nexthop_global,
                                                     "used");
                } else
                        vty_out(vty, "%-16s", inet_ntoa(attr->nexthop));
        }
        /* IPv4 Next Hop */
-       else if (p->family == AF_INET
-                && !BGP_ATTR_NEXTHOP_AFI_IP6(attr)) {
+       else if (p->family == AF_INET && !BGP_ATTR_NEXTHOP_AFI_IP6(attr)) {
                if (json_paths) {
                        json_nexthop_global = json_object_new_object();
 
-                       if ((safi == SAFI_MPLS_VPN)
-                           || (safi == SAFI_EVPN))
-                               json_object_string_add(json_nexthop_global,
-                                                      "ip",
-                                                      inet_ntoa(attr->mp_nexthop_global_in));
+                       if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_EVPN))
+                               json_object_string_add(
+                                       json_nexthop_global, "ip",
+                                       inet_ntoa(attr->mp_nexthop_global_in));
                        else
-                               json_object_string_add(json_nexthop_global,
-                                                      "ip",
-                                                      inet_ntoa(attr->nexthop));
+                               json_object_string_add(
+                                       json_nexthop_global, "ip",
+                                       inet_ntoa(attr->nexthop));
 
-                       json_object_string_add(json_nexthop_global,
-                                              "afi", "ipv4");
+                       json_object_string_add(json_nexthop_global, "afi",
+                                              "ipv4");
                        json_object_boolean_true_add(json_nexthop_global,
                                                     "used");
                } else {
-                       if ((safi == SAFI_MPLS_VPN)
-                           || (safi == SAFI_EVPN))
+                       if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_EVPN))
                                vty_out(vty, "%-16s",
-                                       inet_ntoa(
-                                               attr->mp_nexthop_global_in));
+                                       inet_ntoa(attr->mp_nexthop_global_in));
                        else
-                               vty_out(vty, "%-16s",
-                                       inet_ntoa(attr->nexthop));
+                               vty_out(vty, "%-16s", inet_ntoa(attr->nexthop));
                }
        }
 
        /* IPv6 Next Hop */
-       else if (p->family == AF_INET6
-                || BGP_ATTR_NEXTHOP_AFI_IP6(attr)) {
+       else if (p->family == AF_INET6 || BGP_ATTR_NEXTHOP_AFI_IP6(attr)) {
                int len;
                char buf[BUFSIZ];
 
                if (json_paths) {
                        json_nexthop_global = json_object_new_object();
-                       json_object_string_add(json_nexthop_global, "ip",
-                                              inet_ntop(AF_INET6,
-                                                        &attr->mp_nexthop_global, buf,
-                                                        BUFSIZ));
-                       json_object_string_add(json_nexthop_global,
-                                              "afi", "ipv6");
-                       json_object_string_add(json_nexthop_global,
-                                              "scope", "global");
+                       json_object_string_add(
+                               json_nexthop_global, "ip",
+                               inet_ntop(AF_INET6, &attr->mp_nexthop_global,
+                                         buf, BUFSIZ));
+                       json_object_string_add(json_nexthop_global, "afi",
+                                              "ipv6");
+                       json_object_string_add(json_nexthop_global, "scope",
+                                              "global");
 
                        /* We display both LL & GL if both have been
                         * received */
                        if ((attr->mp_nexthop_len == 32)
                            || (binfo->peer->conf_if)) {
-                               json_nexthop_ll =
-                                       json_object_new_object();
+                               json_nexthop_ll = json_object_new_object();
                                json_object_string_add(
                                        json_nexthop_ll, "ip",
-                                       inet_ntop(
-                                               AF_INET6,
-                                               &attr->mp_nexthop_local,
-                                               buf, BUFSIZ));
-                               json_object_string_add(json_nexthop_ll,
-                                                      "afi", "ipv6");
-                               json_object_string_add(json_nexthop_ll,
-                                                      "scope",
+                                       inet_ntop(AF_INET6,
+                                                 &attr->mp_nexthop_local, buf,
+                                                 BUFSIZ));
+                               json_object_string_add(json_nexthop_ll, "afi",
+                                                      "ipv6");
+                               json_object_string_add(json_nexthop_ll, "scope",
                                                       "link-local");
 
-                               if ((IPV6_ADDR_CMP(
-                                            &attr->mp_nexthop_global,
-                                            &attr->mp_nexthop_local)
+                               if ((IPV6_ADDR_CMP(&attr->mp_nexthop_global,
+                                                  &attr->mp_nexthop_local)
                                     != 0)
                                    && !attr->mp_nexthop_prefer_global)
                                        json_object_boolean_true_add(
-                                               json_nexthop_ll,
-                                               "used");
+                                               json_nexthop_ll, "used");
                                else
                                        json_object_boolean_true_add(
-                                               json_nexthop_global,
-                                               "used");
+                                               json_nexthop_global, "used");
                        } else
                                json_object_boolean_true_add(
                                        json_nexthop_global, "used");
@@ -6666,20 +6363,17 @@ void route_vty_out(struct vty *vty, struct prefix *p, struct bgp_info *binfo,
                             && !attr->mp_nexthop_prefer_global)
                            || (binfo->peer->conf_if)) {
                                if (binfo->peer->conf_if) {
-                                       len = vty_out(
-                                               vty, "%s",
-                                               binfo->peer->conf_if);
+                                       len = vty_out(vty, "%s",
+                                                     binfo->peer->conf_if);
                                        len = 16 - len; /* len of IPv6
                                                           addr + max
                                                           len of def
                                                           ifname */
 
                                        if (len < 1)
-                                               vty_out(vty, "\n%*s",
-                                                       36, " ");
+                                               vty_out(vty, "\n%*s", 36, " ");
                                        else
-                                               vty_out(vty, "%*s", len,
-                                                       " ");
+                                               vty_out(vty, "%*s", len, " ");
                                } else {
                                        len = vty_out(
                                                vty, "%s",
@@ -6690,17 +6384,16 @@ void route_vty_out(struct vty *vty, struct prefix *p, struct bgp_info *binfo,
                                        len = 16 - len;
 
                                        if (len < 1)
-                                               vty_out(vty, "\n%*s",
-                                                       36, " ");
+                                               vty_out(vty, "\n%*s", 36, " ");
                                        else
-                                               vty_out(vty, "%*s", len,
-                                                       " ");
+                                               vty_out(vty, "%*s", len, " ");
                                }
                        } else {
-                               len = vty_out(vty, "%s",
-                                             inet_ntop(AF_INET6,
-                                                       &attr->mp_nexthop_global,
-                                                       buf, BUFSIZ));
+                               len = vty_out(
+                                       vty, "%s",
+                                       inet_ntop(AF_INET6,
+                                                 &attr->mp_nexthop_global, buf,
+                                                 BUFSIZ));
                                len = 16 - len;
 
                                if (len < 1)
@@ -6714,8 +6407,7 @@ void route_vty_out(struct vty *vty, struct prefix *p, struct bgp_info *binfo,
        /* MED/Metric */
        if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC))
                if (json_paths)
-                       json_object_int_add(json_path, "med",
-                                           attr->med);
+                       json_object_int_add(json_path, "med", attr->med);
                else
                        vty_out(vty, "%10u", attr->med);
        else if (!json_paths)
@@ -6738,10 +6430,9 @@ void route_vty_out(struct vty *vty, struct prefix *p, struct bgp_info *binfo,
 
        if (json_paths) {
                char buf[BUFSIZ];
-               json_object_string_add(json_path, "peerId",
-                                      sockunion2str(&binfo->peer->su,
-                                                    buf,
-                                                    SU_ADDRSTRLEN));
+               json_object_string_add(
+                       json_path, "peerId",
+                       sockunion2str(&binfo->peer->su, buf, SU_ADDRSTRLEN));
        }
 
        /* Print aspath */
@@ -6755,9 +6446,8 @@ void route_vty_out(struct vty *vty, struct prefix *p, struct bgp_info *binfo,
 
        /* Print origin */
        if (json_paths)
-               json_object_string_add(
-                       json_path, "origin",
-                       bgp_origin_long_str[attr->origin]);
+               json_object_string_add(json_path, "origin",
+                                      bgp_origin_long_str[attr->origin]);
        else
                vty_out(vty, "%s", bgp_origin_str[attr->origin]);
 
@@ -6955,8 +6645,7 @@ void route_vty_out_tag(struct vty *vty, struct prefix *p,
        if (attr) {
                if (((p->family == AF_INET)
                     && ((safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP)))
-                   || (safi == SAFI_EVPN
-                       && !BGP_ATTR_NEXTHOP_AFI_IP6(attr))
+                   || (safi == SAFI_EVPN && !BGP_ATTR_NEXTHOP_AFI_IP6(attr))
                    || (!BGP_ATTR_NEXTHOP_AFI_IP6(attr))) {
                        if (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP
                            || safi == SAFI_EVPN) {
@@ -7028,7 +6717,7 @@ void route_vty_out_tag(struct vty *vty, struct prefix *p,
                }
        }
 
-       label = decode_label(&binfo->extra->label);
+       label = decode_label(&binfo->extra->label[0]);
 
        if (bgp_is_valid_label(&label)) {
                if (json) {
@@ -7150,9 +6839,10 @@ static void damp_route_vty_out(struct vty *vty, struct prefix *p,
                bgp_damp_reuse_time_vty(vty, binfo, timebuf, BGP_UPTIME_LEN,
                                        use_json, json);
        else
-               vty_out(vty, "%s ", bgp_damp_reuse_time_vty(vty, binfo, timebuf,
-                                                           BGP_UPTIME_LEN,
-                                                           use_json, json));
+               vty_out(vty, "%s ",
+                       bgp_damp_reuse_time_vty(vty, binfo, timebuf,
+                                               BGP_UPTIME_LEN, use_json,
+                                               json));
 
        /* Print attribute */
        attr = binfo->attr;
@@ -7231,8 +6921,9 @@ static void flap_route_vty_out(struct vty *vty, struct prefix *p,
                peer_uptime(bdi->start_time, timebuf, BGP_UPTIME_LEN, use_json,
                            json);
        else
-               vty_out(vty, "%s ", peer_uptime(bdi->start_time, timebuf,
-                                               BGP_UPTIME_LEN, 0, NULL));
+               vty_out(vty, "%s ",
+                       peer_uptime(bdi->start_time, timebuf, BGP_UPTIME_LEN, 0,
+                                   NULL));
 
        if (CHECK_FLAG(binfo->flags, BGP_INFO_DAMPED)
            && !CHECK_FLAG(binfo->flags, BGP_INFO_HISTORY)) {
@@ -7366,13 +7057,14 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct prefix *p,
 
 #if defined(HAVE_CUMULUS)
        if (!json_paths && safi == SAFI_EVPN) {
-               char tag_buf[20];
+               char tag_buf[30];
 
                bgp_evpn_route2str((struct prefix_evpn *)p, buf2, sizeof(buf2));
                vty_out(vty, "  Route %s", buf2);
                tag_buf[0] = '\0';
-               if (binfo->extra) {
-                       bgp_evpn_label2str(&binfo->extra->label, tag_buf,
+               if (binfo->extra && binfo->extra->num_labels) {
+                       bgp_evpn_label2str(binfo->extra->label,
+                                          binfo->extra->num_labels, tag_buf,
                                           sizeof(tag_buf));
                        vty_out(vty, " VNI %s", tag_buf);
                }
@@ -7483,8 +7175,8 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct prefix *p,
 
                /* Line2 display Next-hop, Neighbor, Router-id */
                /* Display the nexthop */
-               if ((p->family == AF_INET || p->family == AF_ETHERNET ||
-                    p->family == AF_EVPN)
+               if ((p->family == AF_INET || p->family == AF_ETHERNET
+                    || p->family == AF_EVPN)
                    && (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP
                        || safi == SAFI_EVPN
                        || !BGP_ATTR_NEXTHOP_AFI_IP6(attr))) {
@@ -7892,8 +7584,7 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct prefix *p,
                if (attr->community) {
                        if (json_paths) {
                                if (!attr->community->json)
-                                       community_str(attr->community,
-                                                     true);
+                                       community_str(attr->community, true);
                                json_object_lock(attr->community->json);
                                json_object_object_add(json_path, "community",
                                                       attr->community->json);
@@ -8007,13 +7698,14 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct prefix *p,
 
 /* Remote Label */
 #if defined(HAVE_CUMULUS)
-               if (binfo->extra && bgp_is_valid_label(&binfo->extra->label)
+               if (binfo->extra && bgp_is_valid_label(&binfo->extra->label[0])
                    && safi != SAFI_EVPN)
 #else
-               if (binfo->extra && bgp_is_valid_label(&binfo->extra->label))
+               if (binfo->extra && bgp_is_valid_label(&binfo->extra->label[0]))
 #endif
                {
-                       mpls_label_t label = label_pton(&binfo->extra->label);
+                       mpls_label_t label =
+                               label_pton(&binfo->extra->label[0]);
                        if (json_paths)
                                json_object_int_add(json_path, "remoteLabel",
                                                    label);
@@ -8141,9 +7833,8 @@ static int bgp_show_community_list(struct vty *vty, struct bgp *bgp,
 static int bgp_show_prefix_longer(struct vty *vty, struct bgp *bgp,
                                  const char *prefix, afi_t afi, safi_t safi,
                                  enum bgp_show_type type);
-static int bgp_show_regexp(struct vty *vty, struct bgp *bgp,
-                          const char *regstr, afi_t afi,
-                          safi_t safi, enum bgp_show_type type);
+static int bgp_show_regexp(struct vty *vty, struct bgp *bgp, const char *regstr,
+                          afi_t afi, safi_t safi, enum bgp_show_type type);
 static int bgp_show_community(struct vty *vty, struct bgp *bgp,
                              const char *comstr, int exact, afi_t afi,
                              safi_t safi);
@@ -8151,9 +7842,10 @@ static int bgp_show_community(struct vty *vty, struct bgp *bgp,
 
 static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi,
                          struct bgp_table *table, enum bgp_show_type type,
-                         void *output_arg, u_char use_json,
-                         char *rd, int is_last,
-                         unsigned long *output_cum, unsigned long *total_cum)
+                         void *output_arg, u_char use_json, char *rd,
+                         int is_last, unsigned long *output_cum,
+                         unsigned long *total_cum,
+                         unsigned long *json_header_depth)
 {
        struct bgp_info *ri;
        struct bgp_node *rn;
@@ -8170,16 +7862,19 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi,
        if (output_cum && *output_cum != 0)
                header = 0;
 
-       if (use_json && header) {
+       if (use_json && !*json_header_depth) {
                vty_out(vty,
                        "{\n \"vrfId\": %d,\n \"vrfName\": \"%s\",\n \"tableVersion\": %" PRId64
                        ",\n \"routerId\": \"%s\",\n \"routes\": { ",
-                       bgp->vrf_id == VRF_UNKNOWN ? -1 : bgp->vrf_id,
+                       bgp->vrf_id == VRF_UNKNOWN ? -1 : (int)bgp->vrf_id,
                        bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT ? "Default"
                                                                    : bgp->name,
                        table->version, inet_ntoa(bgp->router_id));
-               if (rd)
+               *json_header_depth = 2;
+               if (rd) {
                        vty_out(vty, " \"routeDistinguishers\" : {");
+                       ++*json_header_depth;
+               }
                json_paths = json_object_new_object();
        }
 
@@ -8204,8 +7899,7 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi,
                            || type == bgp_show_type_flap_neighbor
                            || type == bgp_show_type_dampend_paths
                            || type == bgp_show_type_damp_neighbor) {
-                               if (!(ri->extra
-                                     && ri->extra->damp_info))
+                               if (!(ri->extra && ri->extra->damp_info))
                                        continue;
                        }
                        if (type == bgp_show_type_regexp) {
@@ -8240,8 +7934,8 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi,
                                binfo.peer = ri->peer;
                                binfo.attr = &dummy_attr;
 
-                               ret = route_map_apply(rmap, &rn->p,
-                                                     RMAP_BGP, &binfo);
+                               ret = route_map_apply(rmap, &rn->p, RMAP_BGP,
+                                                     &binfo);
                                if (ret == RMAP_DENYMATCH)
                                        continue;
                        }
@@ -8252,8 +7946,7 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi,
 
                                if (ri->peer == NULL
                                    || ri->peer->su_remote == NULL
-                                   || !sockunion_same(ri->peer->su_remote,
-                                                      su))
+                                   || !sockunion_same(ri->peer->su_remote, su))
                                        continue;
                        }
                        if (type == bgp_show_type_cidr_only) {
@@ -8292,19 +7985,17 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi,
                                struct community *com = output_arg;
 
                                if (!ri->attr->community
-                                   || !community_cmp(ri->attr->community,
-                                                     com))
+                                   || !community_cmp(ri->attr->community, com))
                                        continue;
                        }
                        if (type == bgp_show_type_community_list) {
                                struct community_list *list = output_arg;
 
-                               if (!community_list_match(
-                                           ri->attr->community, list))
+                               if (!community_list_match(ri->attr->community,
+                                                         list))
                                        continue;
                        }
-                       if (type
-                           == bgp_show_type_community_list_exact) {
+                       if (type == bgp_show_type_community_list_exact) {
                                struct community_list *list = output_arg;
 
                                if (!community_list_exact_match(
@@ -8322,8 +8013,8 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi,
                        if (type == bgp_show_type_lcommunity_list) {
                                struct community_list *list = output_arg;
 
-                               if (!lcommunity_list_match(
-                                           ri->attr->lcommunity, list))
+                               if (!lcommunity_list_match(ri->attr->lcommunity,
+                                                          list))
                                        continue;
                        }
                        if (type == bgp_show_type_lcommunity_all) {
@@ -8348,9 +8039,8 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi,
                                if (type == bgp_show_type_dampend_paths
                                    || type == bgp_show_type_damp_neighbor)
                                        vty_out(vty, BGP_SHOW_DAMP_HEADER);
-                               else if (
-                                       type == bgp_show_type_flap_statistics
-                                       || type == bgp_show_type_flap_neighbor)
+                               else if (type == bgp_show_type_flap_statistics
+                                        || type == bgp_show_type_flap_neighbor)
                                        vty_out(vty, BGP_SHOW_FLAP_HEADER);
                                else
                                        vty_out(vty, BGP_SHOW_HEADER);
@@ -8365,16 +8055,14 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi,
                        if (type == bgp_show_type_dampend_paths
                            || type == bgp_show_type_damp_neighbor)
                                damp_route_vty_out(vty, &rn->p, ri, display,
-                                                  safi, use_json,
-                                                  json_paths);
+                                                  safi, use_json, json_paths);
                        else if (type == bgp_show_type_flap_statistics
                                 || type == bgp_show_type_flap_neighbor)
                                flap_route_vty_out(vty, &rn->p, ri, display,
-                                                  safi, use_json,
-                                                  json_paths);
+                                                  safi, use_json, json_paths);
                        else
-                               route_vty_out(vty, &rn->p, ri, display,
-                                             safi, json_paths);
+                               route_vty_out(vty, &rn->p, ri, display, safi,
+                                             json_paths);
                        display++;
                }
 
@@ -8385,8 +8073,7 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi,
 
                        p = &rn->p;
                        sprintf(buf2, "%s/%d",
-                               inet_ntop(p->family, &p->u.prefix,
-                                         buf, BUFSIZ),
+                               inet_ntop(p->family, &p->u.prefix, buf, BUFSIZ),
                                p->prefixlen);
                        if (first)
                                vty_out(vty, "\"%s\": ", buf2);
@@ -8394,8 +8081,9 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi,
                                vty_out(vty, ",\"%s\": ", buf2);
 
                        vty_out(vty, "%s",
-                               json_object_to_json_string_ext(json_paths, JSON_C_TO_STRING_PRETTY));
+                               json_object_to_json_string(json_paths));
                        json_object_free(json_paths);
+                       json_paths = NULL;
                        first = 0;
                }
        }
@@ -8409,11 +8097,16 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi,
                *total_cum = total_count;
        }
        if (use_json) {
-               json_object_free(json_paths);
-               if (is_last)
-                       vty_out(vty, " } }\n");
-               else
-                       vty_out(vty, " }, ");
+               if (json_paths)
+                       json_object_free(json_paths);
+               if (rd) {
+                       vty_out(vty, " }%s ", (is_last ? "" : ","));
+               }
+               if (is_last) {
+                       unsigned long i;
+                       for (i = 0; i < *json_header_depth; ++i)
+                               vty_out(vty, " } ");
+               }
        } else {
                if (is_last) {
                        /* No route is displayed */
@@ -8440,6 +8133,10 @@ int bgp_show_table_rd(struct vty *vty, struct bgp *bgp, safi_t safi,
        struct bgp_node *rn, *next;
        unsigned long output_cum = 0;
        unsigned long total_cum = 0;
+       unsigned long json_header_depth = 0;
+       bool show_msg;
+
+       show_msg = (!use_json && type == bgp_show_type_normal);
 
        for (rn = bgp_table_top(table); rn; rn = next) {
                next = bgp_route_next(rn);
@@ -8452,19 +8149,29 @@ int bgp_show_table_rd(struct vty *vty, struct bgp *bgp, safi_t safi,
                        memcpy(&prd, &(rn->p), sizeof(struct prefix_rd));
                        prefix_rd2str(&prd, rd, sizeof(rd));
                        bgp_show_table(vty, bgp, safi, rn->info, type,
-                                      output_arg, use_json,
-                                      rd, next == NULL,
-                                      &output_cum, &total_cum);
+                                      output_arg, use_json, rd, next == NULL,
+                                      &output_cum, &total_cum,
+                                      &json_header_depth);
+                       if (next == NULL)
+                               show_msg = false;
                }
        }
-       if (use_json)
-               vty_out(vty, " } }");
+       if (show_msg) {
+               if (output_cum == 0)
+                       vty_out(vty, "No BGP prefixes displayed, %ld exist\n",
+                               total_cum);
+               else
+                       vty_out(vty,
+                               "\nDisplayed  %ld routes and %ld total paths\n",
+                               output_cum, total_cum);
+       }
        return CMD_SUCCESS;
 }
 static int bgp_show(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi,
                    enum bgp_show_type type, void *output_arg, u_char use_json)
 {
        struct bgp_table *table;
+       unsigned long json_header_depth = 0;
 
        if (bgp == NULL) {
                bgp = bgp_get_default();
@@ -8489,7 +8196,7 @@ static int bgp_show(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi,
                safi = SAFI_UNICAST;
 
        return bgp_show_table(vty, bgp, safi, table, type, output_arg, use_json,
-                             NULL, 1, NULL, NULL);
+                             NULL, 1, NULL, NULL, &json_header_depth);
 }
 
 static void bgp_show_all_instances_routes_vty(struct vty *vty, afi_t afi,
@@ -8594,8 +8301,8 @@ void route_vty_out_detail_header(struct vty *vty, struct bgp *bgp,
                vty_out(vty, "BGP routing table entry for %s%s%s/%d\n",
                        ((safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP
                          || safi == SAFI_EVPN)
-                        ? prefix_rd2str(prd, buf1, sizeof(buf1))
-                        : ""),
+                                ? prefix_rd2str(prd, buf1, sizeof(buf1))
+                                : ""),
                        ((safi == SAFI_MPLS_VPN) || (safi == SAFI_EVPN)) ? ":"
                                                                         : "",
                        buf2, p->prefixlen);
@@ -8806,8 +8513,9 @@ static int bgp_show_route_in_table(struct vty *vty, struct bgp *bgp,
                if (display)
                        json_object_object_add(json, "paths", json_paths);
 
-               vty_out(vty, "%s\n", json_object_to_json_string_ext(
-                                            json, JSON_C_TO_STRING_PRETTY));
+               vty_out(vty, "%s\n",
+                       json_object_to_json_string_ext(
+                               json, JSON_C_TO_STRING_PRETTY));
                json_object_free(json);
        } else {
                if (!display) {
@@ -9074,14 +8782,17 @@ DEFUN (show_ip_bgp,
        if (argv_find(argv, argc, "community", &idx)) {
                /* show a specific community */
                if (argv_find(argv, argc, "local-AS", &idx_community_type)
-                   || argv_find(argv, argc, "no-advertise", &idx_community_type)
+                   || argv_find(argv, argc, "no-advertise",
+                                &idx_community_type)
                    || argv_find(argv, argc, "no-export", &idx_community_type)
-                   || argv_find(argv, argc, "graceful-shutdown", &idx_community_type)
+                   || argv_find(argv, argc, "graceful-shutdown",
+                                &idx_community_type)
                    || argv_find(argv, argc, "AA:NN", &idx_community_type)) {
 
                        if (argv_find(argv, argc, "exact-match", &idx))
                                exact_match = 1;
-                       return bgp_show_community(vty, bgp, argv[idx_community_type]->arg,
+                       return bgp_show_community(vty, bgp,
+                                                 argv[idx_community_type]->arg,
                                                  exact_match, afi, safi);
                }
        }
@@ -9299,9 +9010,8 @@ DEFUN (show_ip_bgp_instance_all,
        return CMD_SUCCESS;
 }
 
-static int bgp_show_regexp(struct vty *vty, struct bgp *bgp,
-                          const char *regstr, afi_t afi,
-                          safi_t safi, enum bgp_show_type type)
+static int bgp_show_regexp(struct vty *vty, struct bgp *bgp, const char *regstr,
+                          afi_t afi, safi_t safi, enum bgp_show_type type)
 {
        regex_t *regex;
        int rc;
@@ -9448,7 +9158,8 @@ static struct peer *peer_lookup_in_view(struct vty *vty, struct bgp *bgp,
                                                ip_str);
                                        vty_out(vty, "%s\n",
                                                json_object_to_json_string_ext(
-                                                       json_no, JSON_C_TO_STRING_PRETTY));
+                                                       json_no,
+                                                       JSON_C_TO_STRING_PRETTY));
                                        json_object_free(json_no);
                                } else
                                        vty_out(vty,
@@ -9469,8 +9180,8 @@ static struct peer *peer_lookup_in_view(struct vty *vty, struct bgp *bgp,
                        json_object_string_add(json_no, "warning",
                                               "No such neighbor");
                        vty_out(vty, "%s\n",
-                               json_object_to_json_string_ext(json_no,
-                                                              JSON_C_TO_STRING_PRETTY));
+                               json_object_to_json_string_ext(
+                                       json_no, JSON_C_TO_STRING_PRETTY));
                        json_object_free(json_no);
                } else
                        vty_out(vty, "No such neighbor\n");
@@ -9588,8 +9299,8 @@ static int bgp_table_stats_walker(struct thread *t)
                        ts->counts[BGP_STATS_UNAGGREGATEABLE]++;
                        /* announced address space */
                        if (space)
-                               ts->total_space += pow(2.0,
-                                                      space - rn->p.prefixlen);
+                               ts->total_space +=
+                                       pow(2.0, space - rn->p.prefixlen);
                } else if (prn->info)
                        ts->counts[BGP_STATS_MAX_AGGREGATEABLE]++;
 
@@ -9704,20 +9415,20 @@ static int bgp_table_stats(struct vty *vty, struct bgp *bgp, afi_t afi,
                        if (afi == AFI_IP6) {
                                vty_out(vty, "%30s: ", "/32 equivalent ");
                                vty_out(vty, "%12g\n",
-                                       ts.total_space * pow(2.0, -128+32));
+                                       ts.total_space * pow(2.0, -128 + 32));
                                vty_out(vty, "%30s: ", "/48 equivalent ");
                                vty_out(vty, "%12g\n",
-                                       ts.total_space * pow(2.0, -128+48));
+                                       ts.total_space * pow(2.0, -128 + 48));
                        } else {
                                vty_out(vty, "%30s: ", "% announced ");
                                vty_out(vty, "%12.2f\n",
                                        ts.total_space * 100. * pow(2.0, -32));
                                vty_out(vty, "%30s: ", "/8 equivalent ");
                                vty_out(vty, "%12.2f\n",
-                                       ts.total_space * pow(2.0, -32+8));
+                                       ts.total_space * pow(2.0, -32 + 8));
                                vty_out(vty, "%30s: ", "/24 equivalent ");
                                vty_out(vty, "%12.2f\n",
-                                       ts.total_space * pow(2.0, -32+24));
+                                       ts.total_space * pow(2.0, -32 + 24));
                        }
                        break;
                default:
@@ -9854,9 +9565,9 @@ static int bgp_peer_counts(struct vty *vty, struct peer *peer, afi_t afi,
        pcounts.table = peer->bgp->rib[afi][safi];
 
        /* in-place call via thread subsystem so as to record execution time
-       *    * stats for the thread-walk (i.e. ensure this can't be blamed on
-       *       * on just vty_read()).
-       *          */
+        * stats for the thread-walk (i.e. ensure this can't be blamed on
+        * on just vty_read()).
+        */
        thread_execute(bm->master, bgp_peer_count_walker, &pcounts, 0);
 
        if (use_json) {
@@ -9879,8 +9590,9 @@ static int bgp_peer_counts(struct vty *vty, struct peer *peer, afi_t afi,
                                json, "recommended",
                                "Please report this bug, with the above command output");
                }
-               vty_out(vty, "%s\n", json_object_to_json_string_ext(json,
-                                                                   JSON_C_TO_STRING_PRETTY));
+               vty_out(vty, "%s\n",
+                       json_object_to_json_string_ext(
+                               json, JSON_C_TO_STRING_PRETTY));
                json_object_free(json);
        } else {
 
@@ -10114,8 +9826,9 @@ static void show_adj_route(struct vty *vty, struct peer *peer, afi_t afi,
                                               "bgpOriginatingDefaultNetwork",
                                               "0.0.0.0");
                } else {
-                       vty_out(vty, "BGP table version is %" PRIu64
-                                    ", local router ID is %s\n",
+                       vty_out(vty,
+                               "BGP table version is %" PRIu64
+                               ", local router ID is %s\n",
                                table->version, inet_ntoa(bgp->router_id));
                        vty_out(vty, BGP_SHOW_SCODE_HEADER);
                        vty_out(vty, BGP_SHOW_OCODE_HEADER);
@@ -10226,19 +9939,14 @@ static void show_adj_route(struct vty *vty, struct peer *peer, afi_t afi,
                                        }
 
                                        if (adj->attr) {
-                                               bgp_attr_dup(&attr,
-                                                            adj->attr);
+                                               bgp_attr_dup(&attr, adj->attr);
                                                ret = bgp_output_modifier(
-                                                       peer, &rn->p,
-                                                       &attr, afi,
-                                                       safi,
-                                                       rmap_name);
+                                                       peer, &rn->p, &attr,
+                                                       afi, safi, rmap_name);
                                                if (ret != RMAP_DENY) {
                                                        route_vty_out_tmp(
-                                                               vty,
-                                                               &rn->p,
-                                                               &attr,
-                                                               safi,
+                                                               vty, &rn->p,
+                                                               &attr, safi,
                                                                use_json,
                                                                json_ar);
                                                        output_count++;
@@ -10263,8 +9971,9 @@ static void show_adj_route(struct vty *vty, struct peer *peer, afi_t afi,
                                output_count);
        }
        if (use_json) {
-               vty_out(vty, "%s\n", json_object_to_json_string_ext(json,
-                                                                   JSON_C_TO_STRING_PRETTY));
+               vty_out(vty, "%s\n",
+                       json_object_to_json_string_ext(
+                               json, JSON_C_TO_STRING_PRETTY));
                json_object_free(json);
        }
 }
@@ -11154,10 +10863,10 @@ static void bgp_config_write_network_vpn(struct vty *vty, struct bgp *bgp,
                        if (bgp_static->rmap.name)
                                vty_out(vty, " route-map %s",
                                        bgp_static->rmap.name);
-                       else {
-                               if (bgp_static->backdoor)
-                                       vty_out(vty, " backdoor");
-                       }
+
+                       if (bgp_static->backdoor)
+                               vty_out(vty, " backdoor");
+
                        vty_out(vty, "\n");
                }
        }
@@ -11201,23 +10910,25 @@ static void bgp_config_write_network_evpn(struct vty *vty, struct bgp *bgp,
                        prefix_rd2str(prd, rdbuf, sizeof(rdbuf));
                        if (p->u.prefix_evpn.route_type == 5) {
                                char local_buf[PREFIX_STRLEN];
-                               uint8_t family = IS_EVPN_PREFIX_IPADDR_V4((struct prefix_evpn *)p)
-                                       ? AF_INET
-                                       : AF_INET6;
-                               inet_ntop(family, &p->u.prefix_evpn.ip.ip.addr, local_buf,
-                                         PREFIX_STRLEN);
-                               sprintf(buf, "%s/%u", local_buf,p->u.prefix_evpn.ip_prefix_length);
+                               uint8_t family = IS_EVPN_PREFIX_IPADDR_V4((
+                                                        struct prefix_evpn *)p)
+                                                        ? AF_INET
+                                                        : AF_INET6;
+                               inet_ntop(family, &p->u.prefix_evpn.ip.ip.addr,
+                                         local_buf, PREFIX_STRLEN);
+                               sprintf(buf, "%s/%u", local_buf,
+                                       p->u.prefix_evpn.ip_prefix_length);
                        } else {
                                prefix2str(p, buf, sizeof(buf));
                        }
 
-                       if (bgp_static->gatewayIp.family == AF_INET ||
-                           bgp_static->gatewayIp.family == AF_INET6)
+                       if (bgp_static->gatewayIp.family == AF_INET
+                           || bgp_static->gatewayIp.family == AF_INET6)
                                inet_ntop(bgp_static->gatewayIp.family,
                                          &bgp_static->gatewayIp.u.prefix, buf2,
                                          sizeof(buf2));
                        vty_out(vty,
-                               " network %s rd %s ethtag %u tag %u esi %s gwip %s routermac %s\n",
+                               "  network %s rd %s ethtag %u label %u esi %s gwip %s routermac %s\n",
                                buf, rdbuf, p->u.prefix_evpn.eth_tag,
                                decode_label(&bgp_static->label), esi, buf2,
                                macrouter);
@@ -11290,10 +11001,9 @@ void bgp_config_write_network(struct vty *vty, struct bgp *bgp, afi_t afi,
 
                if (bgp_static->rmap.name)
                        vty_out(vty, " route-map %s", bgp_static->rmap.name);
-               else {
-                       if (bgp_static->backdoor)
-                               vty_out(vty, " backdoor");
-               }
+
+               if (bgp_static->backdoor)
+                       vty_out(vty, " backdoor");
 
                vty_out(vty, "\n");
        }
@@ -11376,18 +11086,7 @@ void bgp_route_init(void)
        /* IPv4 BGP commands. */
        install_element(BGP_NODE, &bgp_table_map_cmd);
        install_element(BGP_NODE, &bgp_network_cmd);
-       install_element(BGP_NODE, &bgp_network_mask_cmd);
-       install_element(BGP_NODE, &bgp_network_mask_natural_cmd);
-       install_element(BGP_NODE, &bgp_network_route_map_cmd);
-       install_element(BGP_NODE, &bgp_network_mask_route_map_cmd);
-       install_element(BGP_NODE, &bgp_network_mask_natural_route_map_cmd);
-       install_element(BGP_NODE, &bgp_network_backdoor_cmd);
-       install_element(BGP_NODE, &bgp_network_mask_backdoor_cmd);
-       install_element(BGP_NODE, &bgp_network_mask_natural_backdoor_cmd);
        install_element(BGP_NODE, &no_bgp_table_map_cmd);
-       install_element(BGP_NODE, &no_bgp_network_cmd);
-       install_element(BGP_NODE, &no_bgp_network_mask_cmd);
-       install_element(BGP_NODE, &no_bgp_network_mask_natural_cmd);
 
        install_element(BGP_NODE, &aggregate_address_cmd);
        install_element(BGP_NODE, &aggregate_address_mask_cmd);
@@ -11397,20 +11096,7 @@ void bgp_route_init(void)
        /* IPv4 unicast configuration.  */
        install_element(BGP_IPV4_NODE, &bgp_table_map_cmd);
        install_element(BGP_IPV4_NODE, &bgp_network_cmd);
-       install_element(BGP_IPV4_NODE, &bgp_network_mask_cmd);
-       install_element(BGP_IPV4_NODE, &bgp_network_mask_natural_cmd);
-       install_element(BGP_IPV4_NODE, &bgp_network_route_map_cmd);
-       install_element(BGP_IPV4_NODE, &bgp_network_mask_route_map_cmd);
-       install_element(BGP_IPV4_NODE, &bgp_network_mask_natural_route_map_cmd);
-       install_element(BGP_IPV4_NODE, &bgp_network_label_index_cmd);
-       install_element(BGP_IPV4_NODE, &bgp_network_label_index_route_map_cmd);
-       install_element(BGP_IPV4_NODE, &no_bgp_network_label_index_cmd);
-       install_element(BGP_IPV4_NODE,
-                       &no_bgp_network_label_index_route_map_cmd);
        install_element(BGP_IPV4_NODE, &no_bgp_table_map_cmd);
-       install_element(BGP_IPV4_NODE, &no_bgp_network_cmd);
-       install_element(BGP_IPV4_NODE, &no_bgp_network_mask_cmd);
-       install_element(BGP_IPV4_NODE, &no_bgp_network_mask_natural_cmd);
 
        install_element(BGP_IPV4_NODE, &aggregate_address_cmd);
        install_element(BGP_IPV4_NODE, &aggregate_address_mask_cmd);
@@ -11420,16 +11106,7 @@ void bgp_route_init(void)
        /* IPv4 multicast configuration.  */
        install_element(BGP_IPV4M_NODE, &bgp_table_map_cmd);
        install_element(BGP_IPV4M_NODE, &bgp_network_cmd);
-       install_element(BGP_IPV4M_NODE, &bgp_network_mask_cmd);
-       install_element(BGP_IPV4M_NODE, &bgp_network_mask_natural_cmd);
-       install_element(BGP_IPV4M_NODE, &bgp_network_route_map_cmd);
-       install_element(BGP_IPV4M_NODE, &bgp_network_mask_route_map_cmd);
-       install_element(BGP_IPV4M_NODE,
-                       &bgp_network_mask_natural_route_map_cmd);
        install_element(BGP_IPV4M_NODE, &no_bgp_table_map_cmd);
-       install_element(BGP_IPV4M_NODE, &no_bgp_network_cmd);
-       install_element(BGP_IPV4M_NODE, &no_bgp_network_mask_cmd);
-       install_element(BGP_IPV4M_NODE, &no_bgp_network_mask_natural_cmd);
        install_element(BGP_IPV4M_NODE, &aggregate_address_cmd);
        install_element(BGP_IPV4M_NODE, &aggregate_address_mask_cmd);
        install_element(BGP_IPV4M_NODE, &no_aggregate_address_cmd);
@@ -11472,21 +11149,12 @@ void bgp_route_init(void)
        /* New config IPv6 BGP commands.  */
        install_element(BGP_IPV6_NODE, &bgp_table_map_cmd);
        install_element(BGP_IPV6_NODE, &ipv6_bgp_network_cmd);
-       install_element(BGP_IPV6_NODE, &ipv6_bgp_network_route_map_cmd);
        install_element(BGP_IPV6_NODE, &no_bgp_table_map_cmd);
-       install_element(BGP_IPV6_NODE, &no_ipv6_bgp_network_cmd);
-       install_element(BGP_IPV6_NODE, &ipv6_bgp_network_label_index_cmd);
-       install_element(BGP_IPV6_NODE, &no_ipv6_bgp_network_label_index_cmd);
-       install_element(BGP_IPV6_NODE,
-                       &ipv6_bgp_network_label_index_route_map_cmd);
-       install_element(BGP_IPV6_NODE,
-                       &no_ipv6_bgp_network_label_index_route_map_cmd);
 
        install_element(BGP_IPV6_NODE, &ipv6_aggregate_address_cmd);
        install_element(BGP_IPV6_NODE, &no_ipv6_aggregate_address_cmd);
 
        install_element(BGP_IPV6M_NODE, &ipv6_bgp_network_cmd);
-       install_element(BGP_IPV6M_NODE, &no_ipv6_bgp_network_cmd);
 
        install_element(BGP_NODE, &bgp_distance_cmd);
        install_element(BGP_NODE, &no_bgp_distance_cmd);
index 085de3fabb0eb64f6e275ff325e2206cc3b84ba7..2d4034d77dcbfa178439f36ef7549077934279f7 100644 (file)
@@ -59,6 +59,11 @@ enum bgp_show_type {
 #define BGP_SHOW_OCODE_HEADER "Origin codes: i - IGP, e - EGP, ? - incomplete\n\n"
 #define BGP_SHOW_HEADER "   Network          Next Hop            Metric LocPrf Weight Path\n"
 
+/* Maximum number of labels we can process or send with a prefix. We
+ * really do only 1 for MPLS (BGP-LU) but we can do 2 for EVPN-VxLAN.
+ */
+#define BGP_MAX_LABELS 2
+
 /* Ancillary information to struct bgp_info,
  * used for uncommonly used data (aggregation, MPLS, etc.)
  * and lazily allocated to save memory.
@@ -73,8 +78,9 @@ struct bgp_info_extra {
        /* Nexthop reachability check.  */
        u_int32_t igpmetric;
 
-       /* MPLS label.  */
-       mpls_label_t label;
+       /* MPLS label(s) - VNI(s) for EVPN-VxLAN  */
+       mpls_label_t label[BGP_MAX_LABELS];
+       u_int32_t num_labels;
 
 #if ENABLE_BGP_VNC
        union {
@@ -357,10 +363,10 @@ extern int bgp_static_unset_safi(afi_t afi, safi_t safi, struct vty *,
 /* this is primarily for MPLS-VPN */
 extern int bgp_update(struct peer *, struct prefix *, u_int32_t, struct attr *,
                      afi_t, safi_t, int, int, struct prefix_rd *,
-                     mpls_label_t *, int, struct bgp_route_evpn *);
+                     mpls_label_t *, u_int32_t, int, struct bgp_route_evpn *);
 extern int bgp_withdraw(struct peer *, struct prefix *, u_int32_t,
                        struct attr *, afi_t, safi_t, int, int,
-                       struct prefix_rd *, mpls_label_t *,
+                       struct prefix_rd *, mpls_label_t *, u_int32_t,
                        struct bgp_route_evpn *);
 
 /* for bgp_nexthop and bgp_damp */
@@ -415,8 +421,6 @@ extern void bgp_peer_clear_node_queue_drain_immediate(struct peer *peer);
 extern void bgp_process_queues_drain_immediate(void);
 
 /* for encap/vpn */
-extern struct bgp_node *bgp_afi_node_get(struct bgp_table *, afi_t, safi_t,
-                                        struct prefix *, struct prefix_rd *);
 extern struct bgp_node *bgp_afi_node_lookup(struct bgp_table *table, afi_t afi,
                                            safi_t safi, struct prefix *p,
                                            struct prefix_rd *prd);
index 8c9f9f65ca4e4b3894e6d27ae7d2435b41ecaca1..4d5624d3b0027a6d501aa4ab55dc025dc37336ea 100644 (file)
@@ -618,8 +618,7 @@ static route_map_result_t route_match_mac_address(void *rule,
                p.prefixlen = ETH_ALEN * 8;
                p.u.prefix_eth = prefix->u.prefix_evpn.mac;
 
-               return (access_list_apply(alist, &p)
-                                       == FILTER_DENY
+               return (access_list_apply(alist, &p) == FILTER_DENY
                                ? RMAP_NOMATCH
                                : RMAP_MATCH);
        }
@@ -659,7 +658,7 @@ static route_map_result_t route_match_vni(void *rule, struct prefix *prefix,
                vni = *((vni_t *)rule);
                bgp_info = (struct bgp_info *)object;
 
-               if (vni == label2vni(&bgp_info->extra->label))
+               if (vni == label2vni(&bgp_info->extra->label[0]))
                        return RMAP_MATCH;
        }
 
@@ -696,6 +695,56 @@ struct route_map_rule_cmd route_match_evpn_vni_cmd = {
        "evpn vni", route_match_vni, route_match_vni_compile,
        route_match_vni_free};
 
+/* `match evpn route-type' */
+
+/* Match function should return 1 if match is success else return
+   zero. */
+static route_map_result_t route_match_evpn_route_type(void *rule,
+                                                     struct prefix *prefix,
+                                                     route_map_object_t type,
+                                                     void *object)
+{
+       u_char route_type = 0;
+
+       if (type == RMAP_BGP) {
+               route_type = *((u_char *)rule);
+
+               if (route_type == prefix->u.prefix_evpn.route_type)
+                       return RMAP_MATCH;
+       }
+
+       return RMAP_NOMATCH;
+}
+
+/* Route map `route-type' match statement. */
+static void *route_match_evpn_route_type_compile(const char *arg)
+{
+       u_char *route_type = NULL;
+
+       route_type = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(u_char));
+
+       if (strncmp(arg, "ma", 2) == 0)
+               *route_type = BGP_EVPN_MAC_IP_ROUTE;
+       else if (strncmp(arg, "mu", 2) == 0)
+               *route_type = BGP_EVPN_IMET_ROUTE;
+       else
+               *route_type = BGP_EVPN_IP_PREFIX_ROUTE;
+
+       return route_type;
+}
+
+/* Free route map's compiled `route-type' value. */
+static void route_match_evpn_route_type_free(void *rule)
+{
+       XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+/* Route map commands for evpn route-type  matching. */
+struct route_map_rule_cmd route_match_evpn_route_type_cmd = {
+       "evpn route-type", route_match_evpn_route_type,
+       route_match_evpn_route_type_compile,
+       route_match_evpn_route_type_free};
+
 /* `match local-preference LOCAL-PREF' */
 
 /* Match function return 1 if match is success else return zero. */
@@ -3027,6 +3076,19 @@ static void bgp_route_map_process_update(struct bgp *bgp, const char *rmap_name,
                                }
                        }
                }
+
+       /* for type5 command route-maps */
+       FOREACH_AFI_SAFI (afi, safi) {
+               if (bgp->adv_cmd_rmap[afi][safi].name &&
+                   strcmp(rmap_name, bgp->adv_cmd_rmap[afi][safi].name) == 0) {
+                       if (BGP_DEBUG(zebra, ZEBRA))
+                               zlog_debug(
+                                          "Processing route_map %s update on advertise type5 route command",
+                                          rmap_name);
+                       bgp_evpn_withdraw_type5_routes(bgp, afi, safi);
+                       bgp_evpn_advertise_type5_routes(bgp, afi, safi);
+               }
+       }
 }
 
 static int bgp_route_map_process_update_cb(char *rmap_name)
@@ -3132,6 +3194,36 @@ DEFUN (no_match_mac_address,
                                      RMAP_EVENT_FILTER_DELETED);
 }
 
+DEFUN (match_evpn_route_type,
+       match_evpn_route_type_cmd,
+       "match evpn route-type <macip | multicast | prefix>",
+       MATCH_STR
+       EVPN_HELP_STR
+       "Match route-type\n"
+       "mac-ip route\n"
+       "IMET route\n"
+       "prefix route\n")
+{
+       return bgp_route_match_add(vty, "evpn route-type", argv[3]->arg,
+                                  RMAP_EVENT_MATCH_ADDED);
+}
+
+DEFUN (no_match_evpn_route_type,
+       no_match_evpn_route_type_cmd,
+       "no match evpn route-type <macip | multicast | prefix>",
+       NO_STR
+       MATCH_STR
+       EVPN_HELP_STR
+       "Match route-type\n"
+       "mac-ip route\n"
+       "IMET route\n"
+       "prefix route\n")
+{
+       return bgp_route_match_delete(vty, "evpn route-type", argv[4]->arg,
+                                     RMAP_EVENT_MATCH_DELETED);
+}
+
+
 DEFUN (match_evpn_vni,
        match_evpn_vni_cmd,
        "match evpn vni (1-16777215)",
@@ -3519,9 +3611,9 @@ DEFUN (set_ip_nexthop_peer,
        "Use peer address (for BGP only)\n")
 {
        int (*func)(struct vty *, struct route_map_index *, const char *,
-                    const char *) = strmatch(argv[0]->text, "no")
-                                            ? generic_set_delete
-                                            : generic_set_add;
+                   const char *) = strmatch(argv[0]->text, "no")
+                                           ? generic_set_delete
+                                           : generic_set_add;
 
        return func(vty, VTY_GET_CONTEXT(route_map_index), "ip next-hop",
                    "peer-address");
@@ -3537,9 +3629,9 @@ DEFUN (set_ip_nexthop_unchanged,
        "Don't modify existing Next hop address\n")
 {
        int (*func)(struct vty *, struct route_map_index *, const char *,
-                    const char *) = strmatch(argv[0]->text, "no")
-                                            ? generic_set_delete
-                                            : generic_set_add;
+                   const char *) = strmatch(argv[0]->text, "no")
+                                           ? generic_set_delete
+                                           : generic_set_add;
 
        return func(vty, VTY_GET_CONTEXT(route_map_index), "ip next-hop",
                    "unchanged");
@@ -3780,7 +3872,8 @@ DEFUN (set_community,
                        buffer_putstr(b, "no-export");
                        continue;
                }
-               if (strncmp(argv[i]->arg, "graceful-shutdown", strlen(argv[i]->arg))
+               if (strncmp(argv[i]->arg, "graceful-shutdown",
+                           strlen(argv[i]->arg))
                    == 0) {
                        buffer_putstr(b, "graceful-shutdown");
                        continue;
@@ -4534,6 +4627,7 @@ void bgp_route_map_init(void)
        route_map_install_match(&route_match_tag_cmd);
        route_map_install_match(&route_match_mac_address_cmd);
        route_map_install_match(&route_match_evpn_vni_cmd);
+       route_map_install_match(&route_match_evpn_route_type_cmd);
 
        route_map_install_set(&route_set_ip_nexthop_cmd);
        route_map_install_set(&route_set_local_pref_cmd);
@@ -4568,6 +4662,8 @@ void bgp_route_map_init(void)
        install_element(RMAP_NODE, &no_match_mac_address_cmd);
        install_element(RMAP_NODE, &match_evpn_vni_cmd);
        install_element(RMAP_NODE, &no_match_evpn_vni_cmd);
+       install_element(RMAP_NODE, &match_evpn_route_type_cmd);
+       install_element(RMAP_NODE, &no_match_evpn_route_type_cmd);
 
        install_element(RMAP_NODE, &match_aspath_cmd);
        install_element(RMAP_NODE, &no_match_aspath_cmd);
index 484ea7c433b6dc93b633e240eac582d8d7d31f53..8317a252e1670061247d2a3d09ddfa0b555baf70 100644 (file)
@@ -512,6 +512,7 @@ static u_char *bgpPeerTable(struct variable *v, oid name[], size_t *length,
 {
        static struct in_addr addr;
        struct peer *peer;
+       uint32_t ui, uo;
 
        if (smux_header_table(v, name, length, exact, var_len, write_method)
            == MATCH_FAILED)
@@ -571,21 +572,20 @@ static u_char *bgpPeerTable(struct variable *v, oid name[], size_t *length,
                return SNMP_INTEGER(peer->as);
                break;
        case BGPPEERINUPDATES:
-               return SNMP_INTEGER(peer->update_in);
+               ui = atomic_load_explicit(&peer->update_in,
+                                         memory_order_relaxed);
+               return SNMP_INTEGER(ui);
                break;
        case BGPPEEROUTUPDATES:
-               return SNMP_INTEGER(peer->update_out);
+               uo = atomic_load_explicit(&peer->update_out,
+                                         memory_order_relaxed);
+               return SNMP_INTEGER(uo);
                break;
        case BGPPEERINTOTALMESSAGES:
-               return SNMP_INTEGER(peer->open_in + peer->update_in
-                                   + peer->keepalive_in + peer->notify_in
-                                   + peer->refresh_in + peer->dynamic_cap_in);
+               return SNMP_INTEGER(PEER_TOTAL_RX(peer));
                break;
        case BGPPEEROUTTOTALMESSAGES:
-               return SNMP_INTEGER(peer->open_out + peer->update_out
-                                   + peer->keepalive_out + peer->notify_out
-                                   + peer->refresh_out
-                                   + peer->dynamic_cap_out);
+               return SNMP_INTEGER(PEER_TOTAL_TX(peer));
                break;
        case BGPPEERLASTERROR: {
                static u_char lasterror[2];
index b63dfbed0ac240cacdcb6277ff13be46527f3fd5..9fa733a720e993108972fe2d9a2ad8596492d1d3 100644 (file)
@@ -701,7 +701,8 @@ struct bpacket *subgroup_update_packet(struct update_subgroup *subgrp)
        int addpath_overhead = 0;
        u_int32_t addpath_tx_id = 0;
        struct prefix_rd *prd = NULL;
-       mpls_label_t label = MPLS_INVALID_LABEL;
+       mpls_label_t label = MPLS_INVALID_LABEL, *label_pnt = NULL;
+       u_int32_t num_labels = 0;
 
        if (!subgrp)
                return NULL;
@@ -772,7 +773,7 @@ struct bpacket *subgroup_update_packet(struct update_subgroup *subgrp)
                         * attr. */
                        total_attr_len = bgp_packet_attribute(
                                NULL, peer, s, adv->baa->attr, &vecarr, NULL,
-                               afi, safi, from, NULL, NULL, 0, 0);
+                               afi, safi, from, NULL, NULL, 0, 0, 0);
 
                        space_remaining =
                                STREAM_CONCAT_REMAIN(s, snlri, STREAM_SIZE(s))
@@ -815,11 +816,15 @@ struct bpacket *subgroup_update_packet(struct update_subgroup *subgrp)
                        if (rn->prn)
                                prd = (struct prefix_rd *)&rn->prn->p;
 
-                       if (safi == SAFI_LABELED_UNICAST)
+                       if (safi == SAFI_LABELED_UNICAST) {
                                label = bgp_adv_label(rn, binfo, peer, afi,
                                                      safi);
-                       else if (binfo && binfo->extra)
-                               label = binfo->extra->label;
+                               label_pnt = &label;
+                               num_labels = 1;
+                       } else if (binfo && binfo->extra) {
+                               label_pnt = &binfo->extra->label[0];
+                               num_labels = binfo->extra->num_labels;
+                       }
 
                        if (stream_empty(snlri))
                                mpattrlen_pos = bgp_packet_mpattr_start(
@@ -827,8 +832,9 @@ struct bpacket *subgroup_update_packet(struct update_subgroup *subgrp)
                                        adv->baa->attr);
 
                        bgp_packet_mpattr_prefix(snlri, afi, safi, &rn->p, prd,
-                                                &label, addpath_encode,
-                                                addpath_tx_id, adv->baa->attr);
+                                                label_pnt, num_labels,
+                                                addpath_encode, addpath_tx_id,
+                                                adv->baa->attr);
                }
 
                num_pfx++;
@@ -857,7 +863,8 @@ struct bpacket *subgroup_update_packet(struct update_subgroup *subgrp)
                                send_attr_printed = 1;
                        }
 
-                       bgp_debug_rdpfxpath2str(afi, safi, prd, &rn->p, &label,
+                       bgp_debug_rdpfxpath2str(afi, safi, prd, &rn->p,
+                                               label_pnt, num_labels,
                                                addpath_encode, addpath_tx_id,
                                                pfx_buf, sizeof(pfx_buf));
                        zlog_debug("u%" PRIu64 ":s%" PRIu64 " send UPDATE %s",
@@ -1009,7 +1016,7 @@ struct bpacket *subgroup_withdraw_packet(struct update_subgroup *subgrp)
                        }
 
                        bgp_packet_mpunreach_prefix(s, &rn->p, afi, safi, prd,
-                                                   NULL, addpath_encode,
+                                                   NULL, 0, addpath_encode,
                                                    addpath_tx_id, NULL);
                }
 
@@ -1018,7 +1025,7 @@ struct bpacket *subgroup_withdraw_packet(struct update_subgroup *subgrp)
                if (bgp_debug_update(NULL, &rn->p, subgrp->update_group, 0)) {
                        char pfx_buf[BGP_PRD_PATH_STRLEN];
 
-                       bgp_debug_rdpfxpath2str(afi, safi, prd, &rn->p, NULL,
+                       bgp_debug_rdpfxpath2str(afi, safi, prd, &rn->p, NULL, 0,
                                                addpath_encode, addpath_tx_id,
                                                pfx_buf, sizeof(pfx_buf));
                        zlog_debug("u%" PRIu64 ":s%" PRIu64
@@ -1132,7 +1139,7 @@ void subgroup_default_update_packet(struct update_subgroup *subgrp,
        stream_putw(s, 0);
        total_attr_len = bgp_packet_attribute(
                NULL, peer, s, attr, &vecarr, &p, afi, safi, from, NULL, NULL,
-               addpath_encode, BGP_ADDPATH_TX_ID_FOR_DEFAULT_ORIGINATE);
+               0, addpath_encode, BGP_ADDPATH_TX_ID_FOR_DEFAULT_ORIGINATE);
 
        /* Set Total Path Attribute Length. */
        stream_putw_at(s, pos, total_attr_len);
@@ -1227,7 +1234,7 @@ void subgroup_default_withdraw_packet(struct update_subgroup *subgrp)
                mp_start = stream_get_endp(s);
                mplen_pos = bgp_packet_mpunreach_start(s, afi, safi);
                bgp_packet_mpunreach_prefix(
-                       s, &p, afi, safi, NULL, NULL, addpath_encode,
+                       s, &p, afi, safi, NULL, NULL, 0, addpath_encode,
                        BGP_ADDPATH_TX_ID_FOR_DEFAULT_ORIGINATE, NULL);
 
                /* Set the mp_unreach attr's length */
index d1d684ccb306eb716c8abd698fa9a291ae19edcf..c7140b2f1f8b1d4d8b28f761c8a346250786b7c8 100644 (file)
@@ -58,6 +58,7 @@
 #include "bgpd/bgp_updgrp.h"
 #include "bgpd/bgp_bfd.h"
 #include "bgpd/bgp_io.h"
+#include "bgpd/bgp_evpn.h"
 
 static struct peer_group *listen_range_exists(struct bgp *bgp,
                                              struct prefix *range, int exact);
@@ -873,6 +874,8 @@ DEFUN_NOSH (router_bgp,
                 */
        }
 
+       /* unset the auto created flag as the user config is now present */
+       UNSET_FLAG(bgp->vrf_flags, BGP_VRF_AUTO);
        VTY_PUSH_CONTEXT(BGP_NODE, bgp);
 
        return CMD_SUCCESS;
@@ -909,6 +912,12 @@ DEFUN (no_router_bgp,
                                "%% Multiple BGP processes are configured\n");
                        return CMD_WARNING_CONFIG_FAILED;
                }
+
+               if (bgp->l3vni) {
+                       vty_out(vty, "%% Please unconfigure l3vni %u",
+                               bgp->l3vni);
+                       return CMD_WARNING_CONFIG_FAILED;
+               }
        } else {
                as = strtoul(argv[idx_asn]->arg, NULL, 10);
 
@@ -921,6 +930,12 @@ DEFUN (no_router_bgp,
                        vty_out(vty, "%% Can't find BGP instance\n");
                        return CMD_WARNING_CONFIG_FAILED;
                }
+
+               if (bgp->l3vni) {
+                       vty_out(vty, "%% Please unconfigure l3vni %u",
+                               bgp->l3vni);
+                       return CMD_WARNING_CONFIG_FAILED;
+               }
        }
 
        bgp_delete(bgp);
@@ -1525,7 +1540,8 @@ DEFUN (no_bgp_maxpaths,
 }
 
 ALIAS_HIDDEN(no_bgp_maxpaths, no_bgp_maxpaths_hidden_cmd,
-            "no maximum-paths [" CMD_RANGE_STR(1, MULTIPATH_NUM) "]", NO_STR
+            "no maximum-paths [" CMD_RANGE_STR(1, MULTIPATH_NUM) "]",
+            NO_STR
             "Forward packets over multiple paths\n"
             "Number of paths\n")
 
@@ -1853,14 +1869,14 @@ static void bgp_redistribute_redo(struct bgp *bgp)
        struct listnode *node;
        struct bgp_redist *red;
 
-        for (afi = AFI_IP; afi < AFI_MAX; afi++) {
-                for (i = 0; i < ZEBRA_ROUTE_MAX; i++) {
+       for (afi = AFI_IP; afi < AFI_MAX; afi++) {
+               for (i = 0; i < ZEBRA_ROUTE_MAX; i++) {
 
-                        red_list = bgp->redist[afi][i];
-                        if (!red_list)
-                                continue;
+                       red_list = bgp->redist[afi][i];
+                       if (!red_list)
+                               continue;
 
-                        for (ALL_LIST_ELEMENTS_RO(red_list, node, red)) {
+                       for (ALL_LIST_ELEMENTS_RO(red_list, node, red)) {
                                bgp_redistribute_resend(bgp, afi, i,
                                                        red->instance);
                        }
@@ -2677,6 +2693,19 @@ static int peer_remote_as_vty(struct vty *vty, const char *peer_str,
        return bgp_vty_return(vty, ret);
 }
 
+DEFUN (bgp_default_shutdown,
+       bgp_default_shutdown_cmd,
+       "[no] bgp default shutdown",
+       NO_STR
+       BGP_STR
+       "Configure BGP defaults\n"
+       "Apply administrative shutdown to newly configured peers\n")
+{
+       VTY_DECLVAR_CONTEXT(bgp, bgp);
+       bgp->autoshutdown = !strmatch(argv[0]->text, "no");
+       return CMD_SUCCESS;
+}
+
 DEFUN (neighbor_remote_as,
        neighbor_remote_as_cmd,
        "neighbor <A.B.C.D|X:X::X:X|WORD> remote-as <(1-4294967295)|internal|external>",
@@ -3223,7 +3252,6 @@ DEFUN (no_neighbor_password,
        return bgp_vty_return(vty, ret);
 }
 
-
 DEFUN (neighbor_activate,
        neighbor_activate_cmd,
        "neighbor <A.B.C.D|X:X::X:X|WORD> activate",
@@ -3367,7 +3395,7 @@ DEFUN (no_neighbor_set_peer_group,
                return CMD_WARNING_CONFIG_FAILED;
        }
 
-       ret = peer_group_unbind(bgp, peer, group);
+       ret = peer_delete(peer);
 
        return bgp_vty_return(vty, ret);
 }
@@ -4336,23 +4364,23 @@ DEFUN (neighbor_attr_unchanged,
                SET_FLAG(flags, PEER_FLAG_NEXTHOP_UNCHANGED);
                SET_FLAG(flags, PEER_FLAG_MED_UNCHANGED);
        } else {
-               if (!CHECK_FLAG(flags, PEER_FLAG_AS_PATH_UNCHANGED) &&
-                   peer_af_flag_check(peer, afi, safi,
-                                      PEER_FLAG_AS_PATH_UNCHANGED)) {
+               if (!CHECK_FLAG(flags, PEER_FLAG_AS_PATH_UNCHANGED)
+                   && peer_af_flag_check(peer, afi, safi,
+                                         PEER_FLAG_AS_PATH_UNCHANGED)) {
                        peer_af_flag_unset_vty(vty, peer_str, afi, safi,
                                               PEER_FLAG_AS_PATH_UNCHANGED);
                }
 
-               if (!CHECK_FLAG(flags, PEER_FLAG_NEXTHOP_UNCHANGED) &&
-                   peer_af_flag_check(peer, afi, safi,
-                                      PEER_FLAG_NEXTHOP_UNCHANGED)) {
+               if (!CHECK_FLAG(flags, PEER_FLAG_NEXTHOP_UNCHANGED)
+                   && peer_af_flag_check(peer, afi, safi,
+                                         PEER_FLAG_NEXTHOP_UNCHANGED)) {
                        peer_af_flag_unset_vty(vty, peer_str, afi, safi,
                                               PEER_FLAG_NEXTHOP_UNCHANGED);
                }
 
-               if (!CHECK_FLAG(flags, PEER_FLAG_MED_UNCHANGED) &&
-                   peer_af_flag_check(peer, afi, safi,
-                                      PEER_FLAG_MED_UNCHANGED)) {
+               if (!CHECK_FLAG(flags, PEER_FLAG_MED_UNCHANGED)
+                   && peer_af_flag_check(peer, afi, safi,
+                                         PEER_FLAG_MED_UNCHANGED)) {
                        peer_af_flag_unset_vty(vty, peer_str, afi, safi,
                                               PEER_FLAG_MED_UNCHANGED);
                }
@@ -6098,9 +6126,11 @@ DEFUN_NOSH (address_family_ipv4_safi,
        if (argc == 3) {
                VTY_DECLVAR_CONTEXT(bgp, bgp);
                safi_t safi = bgp_vty_safi_from_str(argv[2]->text);
-               if (bgp->inst_type != BGP_INSTANCE_TYPE_DEFAULT &&
-                   safi != SAFI_UNICAST && safi != SAFI_MULTICAST) {
-                       vty_out(vty, "Only Unicast and Multicast SAFIs supported in non-core instances.\n");
+               if (bgp->inst_type != BGP_INSTANCE_TYPE_DEFAULT
+                   && safi != SAFI_UNICAST && safi != SAFI_MULTICAST
+                   && safi != SAFI_EVPN) {
+                       vty_out(vty,
+                               "Only Unicast/Multicast/EVPN SAFIs supported in non-core instances.\n");
                        return CMD_WARNING_CONFIG_FAILED;
                }
                vty->node = bgp_node_type(AFI_IP, safi);
@@ -6120,9 +6150,11 @@ DEFUN_NOSH (address_family_ipv6_safi,
        if (argc == 3) {
                VTY_DECLVAR_CONTEXT(bgp, bgp);
                safi_t safi = bgp_vty_safi_from_str(argv[2]->text);
-               if (bgp->inst_type != BGP_INSTANCE_TYPE_DEFAULT &&
-                   safi != SAFI_UNICAST && safi != SAFI_MULTICAST) {
-                       vty_out(vty, "Only Unicast and Multicast SAFIs supported in non-core instances.\n");
+               if (bgp->inst_type != BGP_INSTANCE_TYPE_DEFAULT
+                   && safi != SAFI_UNICAST && safi != SAFI_MULTICAST
+                   && safi != SAFI_EVPN) {
+                       vty_out(vty,
+                               "Only Unicast/Multicast/EVPN SAFIs supported in non-core instances.\n");
                        return CMD_WARNING_CONFIG_FAILED;
                }
                vty->node = bgp_node_type(AFI_IP6, safi);
@@ -6164,10 +6196,6 @@ DEFUN_NOSH (address_family_evpn,
        "Address Family modifier\n")
 {
        VTY_DECLVAR_CONTEXT(bgp, bgp);
-       if (bgp->inst_type != BGP_INSTANCE_TYPE_DEFAULT) {
-               vty_out(vty, "Only Unicast and Multicast SAFIs supported in non-core instances.\n");
-               return CMD_WARNING_CONFIG_FAILED;
-       }
        vty->node = BGP_EVPN_NODE;
        return CMD_SUCCESS;
 }
@@ -6450,6 +6478,7 @@ DEFUN (show_bgp_vrfs,
        "Show BGP VRFs\n"
        JSON_STR)
 {
+       char buf[ETHER_ADDR_STRLEN];
        struct list *inst = bm->bgp;
        struct listnode *node;
        struct bgp *bgp;
@@ -6457,8 +6486,6 @@ DEFUN (show_bgp_vrfs,
        json_object *json = NULL;
        json_object *json_vrfs = NULL;
        int count = 0;
-       static char header[] =
-               "Type  Id     RouterId          #PeersCfg  #PeersEstb  Name";
 
        if (!bgp_option_check(BGP_OPT_MULTIPLE_INSTANCE)) {
                vty_out(vty, "BGP Multiple Instance is not enabled\n");
@@ -6476,7 +6503,6 @@ DEFUN (show_bgp_vrfs,
                struct listnode *node, *nnode;
                int peers_cfg, peers_estb;
                json_object *json_vrf = NULL;
-               int vrf_id_ui;
 
                /* Skip Views. */
                if (bgp->inst_type == BGP_INSTANCE_TYPE_VIEW)
@@ -6484,7 +6510,10 @@ DEFUN (show_bgp_vrfs,
 
                count++;
                if (!uj && count == 1)
-                       vty_out(vty, "%s\n", header);
+                       vty_out(vty,
+                               "%4s  %-5s  %-16s  %9s  %10s  %-37s %-10s %-15s\n",
+                               "Type", "Id", "routerId", "#PeersVfg",
+                               "#PeersEstb", "Name", "L3-VNI", "Rmac");
 
                peers_cfg = peers_estb = 0;
                if (uj)
@@ -6507,8 +6536,11 @@ DEFUN (show_bgp_vrfs,
                        type = "VRF";
                }
 
-               vrf_id_ui = (bgp->vrf_id == VRF_UNKNOWN) ? -1 : bgp->vrf_id;
+
                if (uj) {
+                       int64_t vrf_id_ui = (bgp->vrf_id == VRF_UNKNOWN)
+                                                   ? -1
+                                                   : (int64_t)bgp->vrf_id;
                        json_object_string_add(json_vrf, "type", type);
                        json_object_int_add(json_vrf, "vrfId", vrf_id_ui);
                        json_object_string_add(json_vrf, "routerId",
@@ -6518,11 +6550,20 @@ DEFUN (show_bgp_vrfs,
                        json_object_int_add(json_vrf, "numEstablishedPeers",
                                            peers_estb);
 
+                       json_object_int_add(json_vrf, "l3vni", bgp->l3vni);
+                       json_object_string_add(
+                               json_vrf, "rmac",
+                               prefix_mac2str(&bgp->rmac, buf, sizeof(buf)));
                        json_object_object_add(json_vrfs, name, json_vrf);
                } else
-                       vty_out(vty, "%4s  %-5d  %-16s  %9u  %10u  %s\n", type,
-                               vrf_id_ui, inet_ntoa(bgp->router_id), peers_cfg,
-                               peers_estb, name);
+                       vty_out(vty,
+                               "%4s  %-5d  %-16s  %9u  %10u  %-37s %-10u %-15s\n",
+                               type,
+                               bgp->vrf_id == VRF_UNKNOWN ? -1
+                                                          : (int)bgp->vrf_id,
+                               inet_ntoa(bgp->router_id), peers_cfg,
+                               peers_estb, name, bgp->l3vni,
+                               prefix_mac2str(&bgp->rmac, buf, sizeof(buf)));
        }
 
        if (uj) {
@@ -6530,8 +6571,9 @@ DEFUN (show_bgp_vrfs,
 
                json_object_int_add(json, "totalVrfs", count);
 
-               vty_out(vty, "%s\n", json_object_to_json_string_ext(
-                                            json, JSON_C_TO_STRING_PRETTY));
+               vty_out(vty, "%s\n",
+                       json_object_to_json_string_ext(
+                               json, JSON_C_TO_STRING_PRETTY));
                json_object_free(json);
        } else {
                if (count)
@@ -6574,17 +6616,21 @@ static void bgp_show_martian_nexthops(struct vty *vty, struct bgp *bgp)
                     vty);
 }
 
-DEFUN(show_bgp_martian_nexthop_db,
-      show_bgp_martian_nexthop_db_cmd,
-      "show bgp martian next-hop",
-      SHOW_STR
-      BGP_STR
+DEFUN(show_bgp_martian_nexthop_db, show_bgp_martian_nexthop_db_cmd,
+      "show bgp [<view|vrf> VIEWVRFNAME] martian next-hop",
+      SHOW_STR BGP_STR BGP_INSTANCE_HELP_STR
       "martian next-hops\n"
       "martian next-hop database\n")
 {
        struct bgp *bgp = NULL;
+       int idx = 0;
+
+       if (argv_find(argv, argc, "view", &idx)
+           || argv_find(argv, argc, "vrf", &idx))
+               bgp = bgp_lookup_by_name(argv[idx + 1]->arg);
+       else
+               bgp = bgp_get_default();
 
-       bgp = bgp_get_default();
        if (!bgp) {
                vty_out(vty, "%% No BGP process is configured\n");
                return CMD_WARNING;
@@ -6676,17 +6722,20 @@ DEFUN (show_bgp_memory,
        /* Other attributes */
        if ((count = community_count()))
                vty_out(vty, "%ld BGP community entries, using %s of memory\n",
-                       count, mtype_memstr(memstrbuf, sizeof(memstrbuf),
-                                           count * sizeof(struct community)));
+                       count,
+                       mtype_memstr(memstrbuf, sizeof(memstrbuf),
+                                    count * sizeof(struct community)));
        if ((count = mtype_stats_alloc(MTYPE_ECOMMUNITY)))
                vty_out(vty, "%ld BGP community entries, using %s of memory\n",
-                       count, mtype_memstr(memstrbuf, sizeof(memstrbuf),
-                                           count * sizeof(struct ecommunity)));
+                       count,
+                       mtype_memstr(memstrbuf, sizeof(memstrbuf),
+                                    count * sizeof(struct ecommunity)));
        if ((count = mtype_stats_alloc(MTYPE_LCOMMUNITY)))
                vty_out(vty,
                        "%ld BGP large-community entries, using %s of memory\n",
-                       count, mtype_memstr(memstrbuf, sizeof(memstrbuf),
-                                           count * sizeof(struct lcommunity)));
+                       count,
+                       mtype_memstr(memstrbuf, sizeof(memstrbuf),
+                                    count * sizeof(struct lcommunity)));
 
        if ((count = mtype_stats_alloc(MTYPE_CLUSTER)))
                vty_out(vty, "%ld Cluster lists, using %s of memory\n", count,
@@ -6715,8 +6764,9 @@ DEFUN (show_bgp_memory,
                                     count * sizeof(struct hash_backet)));
        if ((count = mtype_stats_alloc(MTYPE_BGP_REGEXP)))
                vty_out(vty, "%ld compiled regexes, using %s of memory\n",
-                       count, mtype_memstr(memstrbuf, sizeof(memstrbuf),
-                                           count * sizeof(regex_t)));
+                       count,
+                       mtype_memstr(memstrbuf, sizeof(memstrbuf),
+                                    count * sizeof(regex_t)));
        return CMD_SUCCESS;
 }
 
@@ -6731,27 +6781,21 @@ static void bgp_show_bestpath_json(struct bgp *bgp, json_object *json)
                json_object_string_add(bestpath, "asPath", "confed");
 
        if (bgp_flag_check(bgp, BGP_FLAG_ASPATH_MULTIPATH_RELAX)) {
-               if (bgp_flag_check(bgp,
-                                  BGP_FLAG_MULTIPATH_RELAX_AS_SET))
-                       json_object_string_add(bestpath,
-                                              "multiPathRelax",
+               if (bgp_flag_check(bgp, BGP_FLAG_MULTIPATH_RELAX_AS_SET))
+                       json_object_string_add(bestpath, "multiPathRelax",
                                               "as-set");
                else
-                       json_object_string_add(bestpath,
-                                              "multiPathRelax",
+                       json_object_string_add(bestpath, "multiPathRelax",
                                               "true");
        } else
-               json_object_string_add(bestpath,
-                                      "multiPathRelax",
-                                      "false");
+               json_object_string_add(bestpath, "multiPathRelax", "false");
 
        if (bgp_flag_check(bgp, BGP_FLAG_COMPARE_ROUTER_ID))
                json_object_string_add(bestpath, "compareRouterId", "true");
        if (bgp_flag_check(bgp, BGP_FLAG_MED_CONFED)
            || bgp_flag_check(bgp, BGP_FLAG_MED_MISSING_AS_WORST)) {
                if (bgp_flag_check(bgp, BGP_FLAG_MED_CONFED))
-                       json_object_string_add(bestpath, "med",
-                                              "confed");
+                       json_object_string_add(bestpath, "med", "confed");
                if (bgp_flag_check(bgp, BGP_FLAG_MED_MISSING_AS_WORST))
                        json_object_string_add(bestpath, "med",
                                               "missing-as-worst");
@@ -6840,10 +6884,11 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
                if (!count) {
                        unsigned long ents;
                        char memstrbuf[MTYPE_MEMSTR_LEN];
-                       int vrf_id_ui;
+                       int64_t vrf_id_ui;
 
-                       vrf_id_ui =
-                               (bgp->vrf_id == VRF_UNKNOWN) ? -1 : bgp->vrf_id;
+                       vrf_id_ui = (bgp->vrf_id == VRF_UNKNOWN)
+                                           ? -1
+                                           : (int64_t)bgp->vrf_id;
 
                        /* Usage summary and header */
                        if (use_json) {
@@ -6862,7 +6907,9 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
                                vty_out(vty,
                                        "BGP router identifier %s, local AS number %u vrf-id %d",
                                        inet_ntoa(bgp->router_id), bgp->as,
-                                       vrf_id_ui);
+                                       bgp->vrf_id == VRF_UNKNOWN
+                                               ? -1
+                                               : (int)bgp->vrf_id);
                                vty_out(vty, "\n");
                        }
 
@@ -6971,8 +7018,9 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
                                                json, "peerGroupCount", ents);
                                        json_object_int_add(
                                                json, "peerGroupMemory",
-                                               ents * sizeof(struct
-                                                             peer_group));
+                                               ents
+                                                       * sizeof(struct
+                                                                peer_group));
                                }
 
                                if (CHECK_FLAG(bgp->af_flags[afi][safi],
@@ -6995,10 +7043,11 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
                                vty_out(vty,
                                        "RIB entries %ld, using %s of memory\n",
                                        ents,
-                                       mtype_memstr(memstrbuf,
-                                                    sizeof(memstrbuf),
-                                                    ents * sizeof(struct
-                                                                  bgp_node)));
+                                       mtype_memstr(
+                                               memstrbuf, sizeof(memstrbuf),
+                                               ents
+                                                       * sizeof(struct
+                                                                bgp_node)));
 
                                /* Peer related usage */
                                ents = listcount(bgp->peer);
@@ -7015,8 +7064,9 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
                                                mtype_memstr(
                                                        memstrbuf,
                                                        sizeof(memstrbuf),
-                                                       ents * sizeof(struct
-                                                                     peer_group)));
+                                                       ents
+                                                               * sizeof(struct
+                                                                        peer_group)));
 
                                if (CHECK_FLAG(bgp->af_flags[afi][safi],
                                               BGP_CONFIG_DAMPENING))
@@ -7053,17 +7103,9 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
                        json_object_int_add(json_peer, "remoteAs", peer->as);
                        json_object_int_add(json_peer, "version", 4);
                        json_object_int_add(json_peer, "msgRcvd",
-                                           peer->open_in + peer->update_in
-                                                   + peer->keepalive_in
-                                                   + peer->notify_in
-                                                   + peer->refresh_in
-                                                   + peer->dynamic_cap_in);
+                                           PEER_TOTAL_RX(peer));
                        json_object_int_add(json_peer, "msgSent",
-                                           peer->open_out + peer->update_out
-                                                   + peer->keepalive_out
-                                                   + peer->notify_out
-                                                   + peer->refresh_out
-                                                   + peer->dynamic_cap_out);
+                                           PEER_TOTAL_TX(peer));
 
                        json_object_int_add(json_peer, "tableVersion",
                                            peer->version[afi][safi]);
@@ -7120,48 +7162,19 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
                                        " ");
 
                        vty_out(vty, "4 %10u %7u %7u %8" PRIu64 " %4d %4zd %8s",
-                               peer->as,
-                               atomic_load_explicit(&peer->open_in,
-                                                    memory_order_relaxed)
-                                       + atomic_load_explicit(
-                                                 &peer->update_in,
-                                                 memory_order_relaxed)
-                                       + atomic_load_explicit(
-                                                 &peer->keepalive_in,
-                                                 memory_order_relaxed)
-                                       + atomic_load_explicit(
-                                                 &peer->notify_in,
-                                                 memory_order_relaxed)
-                                       + atomic_load_explicit(
-                                                 &peer->refresh_in,
-                                                 memory_order_relaxed)
-                                       + atomic_load_explicit(
-                                                 &peer->dynamic_cap_in,
-                                                 memory_order_relaxed),
-                               atomic_load_explicit(&peer->open_out,
-                                                    memory_order_relaxed)
-                                       + atomic_load_explicit(
-                                                 &peer->update_out,
-                                                 memory_order_relaxed)
-                                       + atomic_load_explicit(
-                                                 &peer->keepalive_out,
-                                                 memory_order_relaxed)
-                                       + atomic_load_explicit(
-                                                 &peer->notify_out,
-                                                 memory_order_relaxed)
-                                       + atomic_load_explicit(
-                                                 &peer->refresh_out,
-                                                 memory_order_relaxed)
-                                       + atomic_load_explicit(
-                                                 &peer->dynamic_cap_out,
-                                                 memory_order_relaxed),
-                               peer->version[afi][safi], 0, peer->obuf->count,
+                               peer->as, PEER_TOTAL_RX(peer),
+                               PEER_TOTAL_TX(peer), peer->version[afi][safi],
+                               0, peer->obuf->count,
                                peer_uptime(peer->uptime, timebuf,
                                            BGP_UPTIME_LEN, 0, NULL));
 
                        if (peer->status == Established)
-                               vty_out(vty, " %12ld",
-                                       peer->pcount[afi][pfx_rcd_safi]);
+                               if (peer->afc_recv[afi][pfx_rcd_safi])
+                                       vty_out(vty, " %12ld",
+                                               peer->pcount[afi]
+                                                           [pfx_rcd_safi]);
+                               else
+                                       vty_out(vty, " NoNeg");
                        else {
                                if (CHECK_FLAG(peer->flags, PEER_FLAG_SHUTDOWN))
                                        vty_out(vty, " Idle (Admin)");
@@ -7186,8 +7199,9 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
 
                bgp_show_bestpath_json(bgp, json);
 
-               vty_out(vty, "%s\n", json_object_to_json_string_ext(
-                                            json, JSON_C_TO_STRING_PRETTY));
+               vty_out(vty, "%s\n",
+                       json_object_to_json_string_ext(
+                               json, JSON_C_TO_STRING_PRETTY));
                json_object_free(json);
        } else {
                if (count)
@@ -7723,7 +7737,7 @@ static void bgp_show_peer_afi(struct vty *vty, struct peer *p, afi_t afi,
                }
 
                if (afi == AFI_L2VPN && safi == SAFI_EVPN) {
-                       if (p->bgp->advertise_all_vni)
+                       if (is_evpn_enabled())
                                json_object_boolean_true_add(
                                        json_addr, "advertiseAllVnis");
                }
@@ -7823,8 +7837,9 @@ static void bgp_show_peer_afi(struct vty *vty, struct peer *p, afi_t afi,
 
                paf = peer_af_find(p, afi, safi);
                if (paf && PAF_SUBGRP(paf)) {
-                       vty_out(vty, "  Update group %" PRIu64
-                                    ", subgroup %" PRIu64 "\n",
+                       vty_out(vty,
+                               "  Update group %" PRIu64 ", subgroup %" PRIu64
+                               "\n",
                                PAF_UPDGRP(paf)->id, PAF_SUBGRP(paf)->id);
                        vty_out(vty, "  Packet Queue length %d\n",
                                bpacket_queue_virtual_length(paf));
@@ -7995,7 +8010,7 @@ static void bgp_show_peer_afi(struct vty *vty, struct peer *p, afi_t afi,
 
                /* advertise-vni-all */
                if (afi == AFI_L2VPN && safi == SAFI_EVPN) {
-                       if (p->bgp->advertise_all_vni)
+                       if (is_evpn_enabled())
                                vty_out(vty, "  advertise-all-vni\n");
                }
 
@@ -8288,17 +8303,30 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, u_char use_json,
 
                if (p->status == Established) {
                        time_t uptime;
-                       struct tm *tm;
 
                        uptime = bgp_clock();
                        uptime -= p->uptime;
-                       tm = gmtime(&uptime);
                        epoch_tbuf = time(NULL) - uptime;
 
+#if CONFDATE > 20200101
+                       CPP_NOTICE(
+                               "bgpTimerUp should be deprecated and can be removed now");
+#endif
+                       /*
+                        * bgpTimerUp was miliseconds that was accurate
+                        * up to 1 day, then the value returned
+                        * became garbage.  So in order to provide
+                        * some level of backwards compatability,
+                        * we still provde the data, but now
+                        * we are returning the correct value
+                        * and also adding a new bgpTimerUpMsec
+                        * which will allow us to deprecate
+                        * this eventually
+                        */
                        json_object_int_add(json_neigh, "bgpTimerUp",
-                                           (tm->tm_sec * 1000)
-                                                   + (tm->tm_min * 60000)
-                                                   + (tm->tm_hour * 3600000));
+                                           uptime * 1000);
+                       json_object_int_add(json_neigh, "bgpTimerUpMsec",
+                                           uptime * 1000);
                        json_object_string_add(json_neigh, "bgpTimerUpString",
                                               peer_uptime(p->uptime, timebuf,
                                                           BGP_UPTIME_LEN, 0,
@@ -8358,8 +8386,8 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, u_char use_json,
                                "bgpTimerConfiguredKeepAliveIntervalMsecs",
                                p->keepalive * 1000);
                } else if ((bgp->default_holdtime != BGP_DEFAULT_HOLDTIME)
-                          || (bgp->default_keepalive !=
-                              BGP_DEFAULT_KEEPALIVE)) {
+                          || (bgp->default_keepalive
+                              != BGP_DEFAULT_KEEPALIVE)) {
                        json_object_int_add(json_neigh,
                                            "bgpTimerConfiguredHoldTimeMsecs",
                                            bgp->default_holdtime);
@@ -8419,8 +8447,8 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, u_char use_json,
                        vty_out(vty, ", keepalive interval is %d seconds\n",
                                p->keepalive);
                } else if ((bgp->default_holdtime != BGP_DEFAULT_HOLDTIME)
-                          || (bgp->default_keepalive !=
-                              BGP_DEFAULT_KEEPALIVE)) {
+                          || (bgp->default_keepalive
+                              != BGP_DEFAULT_KEEPALIVE)) {
                        vty_out(vty, "  Configured hold time is %d",
                                bgp->default_holdtime);
                        vty_out(vty, ", keepalive interval is %d seconds\n",
@@ -9329,34 +9357,44 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, u_char use_json,
                json_object_int_add(json_stat, "depthInq", 0);
                json_object_int_add(json_stat, "depthOutq",
                                    (unsigned long)p->obuf->count);
-               json_object_int_add(json_stat, "opensSent", p->open_out);
-               json_object_int_add(json_stat, "opensRecv", p->open_in);
+               json_object_int_add(json_stat, "opensSent",
+                                   atomic_load_explicit(&p->open_out,
+                                                        memory_order_relaxed));
+               json_object_int_add(json_stat, "opensRecv",
+                                   atomic_load_explicit(&p->open_in,
+                                                        memory_order_relaxed));
                json_object_int_add(json_stat, "notificationsSent",
-                                   p->notify_out);
+                                   atomic_load_explicit(&p->notify_out,
+                                                        memory_order_relaxed));
                json_object_int_add(json_stat, "notificationsRecv",
-                                   p->notify_in);
-               json_object_int_add(json_stat, "updatesSent", p->update_out);
-               json_object_int_add(json_stat, "updatesRecv", p->update_in);
+                                   atomic_load_explicit(&p->notify_in,
+                                                        memory_order_relaxed));
+               json_object_int_add(json_stat, "updatesSent",
+                                   atomic_load_explicit(&p->update_out,
+                                                        memory_order_relaxed));
+               json_object_int_add(json_stat, "updatesRecv",
+                                   atomic_load_explicit(&p->update_in,
+                                                        memory_order_relaxed));
                json_object_int_add(json_stat, "keepalivesSent",
-                                   p->keepalive_out);
+                                   atomic_load_explicit(&p->keepalive_out,
+                                                        memory_order_relaxed));
                json_object_int_add(json_stat, "keepalivesRecv",
-                                   p->keepalive_in);
+                                   atomic_load_explicit(&p->keepalive_in,
+                                                        memory_order_relaxed));
                json_object_int_add(json_stat, "routeRefreshSent",
-                                   p->refresh_out);
+                                   atomic_load_explicit(&p->refresh_out,
+                                                        memory_order_relaxed));
                json_object_int_add(json_stat, "routeRefreshRecv",
-                                   p->refresh_in);
+                                   atomic_load_explicit(&p->refresh_in,
+                                                        memory_order_relaxed));
                json_object_int_add(json_stat, "capabilitySent",
-                                   p->dynamic_cap_out);
+                                   atomic_load_explicit(&p->dynamic_cap_out,
+                                                        memory_order_relaxed));
                json_object_int_add(json_stat, "capabilityRecv",
-                                   p->dynamic_cap_in);
-               json_object_int_add(json_stat, "totalSent",
-                                   p->open_out + p->notify_out + p->update_out
-                                           + p->keepalive_out + p->refresh_out
-                                           + p->dynamic_cap_out);
-               json_object_int_add(json_stat, "totalRecv",
-                                   p->open_in + p->notify_in + p->update_in
-                                           + p->keepalive_in + p->refresh_in
-                                           + p->dynamic_cap_in);
+                                   atomic_load_explicit(&p->dynamic_cap_in,
+                                                        memory_order_relaxed));
+               json_object_int_add(json_stat, "totalSent", PEER_TOTAL_TX(p));
+               json_object_int_add(json_stat, "totalRecv", PEER_TOTAL_RX(p));
                json_object_object_add(json_neigh, "messageStats", json_stat);
        } else {
                /* Packet counts. */
@@ -9365,25 +9403,38 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, u_char use_json,
                vty_out(vty, "    Outq depth is %lu\n",
                        (unsigned long)p->obuf->count);
                vty_out(vty, "                         Sent       Rcvd\n");
-               vty_out(vty, "    Opens:         %10d %10d\n", p->open_out,
-                       p->open_in);
-               vty_out(vty, "    Notifications: %10d %10d\n", p->notify_out,
-                       p->notify_in);
-               vty_out(vty, "    Updates:       %10d %10d\n", p->update_out,
-                       p->update_in);
-               vty_out(vty, "    Keepalives:    %10d %10d\n", p->keepalive_out,
-                       p->keepalive_in);
-               vty_out(vty, "    Route Refresh: %10d %10d\n", p->refresh_out,
-                       p->refresh_in);
+               vty_out(vty, "    Opens:         %10d %10d\n",
+                       atomic_load_explicit(&p->open_out,
+                                            memory_order_relaxed),
+                       atomic_load_explicit(&p->open_in,
+                                            memory_order_relaxed));
+               vty_out(vty, "    Notifications: %10d %10d\n",
+                       atomic_load_explicit(&p->notify_out,
+                                            memory_order_relaxed),
+                       atomic_load_explicit(&p->notify_in,
+                                            memory_order_relaxed));
+               vty_out(vty, "    Updates:       %10d %10d\n",
+                       atomic_load_explicit(&p->update_out,
+                                            memory_order_relaxed),
+                       atomic_load_explicit(&p->update_in,
+                                            memory_order_relaxed));
+               vty_out(vty, "    Keepalives:    %10d %10d\n",
+                       atomic_load_explicit(&p->keepalive_out,
+                                            memory_order_relaxed),
+                       atomic_load_explicit(&p->keepalive_in,
+                                            memory_order_relaxed));
+               vty_out(vty, "    Route Refresh: %10d %10d\n",
+                       atomic_load_explicit(&p->refresh_out,
+                                            memory_order_relaxed),
+                       atomic_load_explicit(&p->refresh_in,
+                                            memory_order_relaxed));
                vty_out(vty, "    Capability:    %10d %10d\n",
-                       p->dynamic_cap_out, p->dynamic_cap_in);
-               vty_out(vty, "    Total:         %10d %10d\n",
-                       p->open_out + p->notify_out + p->update_out
-                               + p->keepalive_out + p->refresh_out
-                               + p->dynamic_cap_out,
-                       p->open_in + p->notify_in + p->update_in
-                               + p->keepalive_in + p->refresh_in
-                               + p->dynamic_cap_in);
+                       atomic_load_explicit(&p->dynamic_cap_out,
+                                            memory_order_relaxed),
+                       atomic_load_explicit(&p->dynamic_cap_in,
+                                            memory_order_relaxed));
+               vty_out(vty, "    Total:         %10d %10d\n", PEER_TOTAL_TX(p),
+                       PEER_TOTAL_RX(p));
        }
 
        if (use_json) {
@@ -9588,8 +9639,9 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, u_char use_json,
                        } else
                                vty_out(vty,
                                        "  Reduce the no. of prefix from %s, will restart in %ld seconds\n",
-                                       p->host, thread_timer_remain_second(
-                                                        p->t_pmax_restart));
+                                       p->host,
+                                       thread_timer_remain_second(
+                                               p->t_pmax_restart));
                } else {
                        if (use_json)
                                json_object_boolean_true_add(
@@ -9833,9 +9885,9 @@ static int bgp_show_neighbor(struct vty *vty, struct bgp *bgp,
        }
 
        if (use_json) {
-               bgp_show_bestpath_json(bgp, json);
-               vty_out(vty, "%s\n", json_object_to_json_string_ext(
-                                            json, JSON_C_TO_STRING_PRETTY));
+               vty_out(vty, "%s\n",
+                       json_object_to_json_string_ext(
+                               json, JSON_C_TO_STRING_PRETTY));
                json_object_free(json);
        } else {
                vty_out(vty, "\n");
@@ -9845,12 +9897,15 @@ static int bgp_show_neighbor(struct vty *vty, struct bgp *bgp,
 }
 
 static void bgp_show_all_instances_neighbors_vty(struct vty *vty,
+                                                enum show_type type,
+                                                const char *ip_str,
                                                 u_char use_json)
 {
        struct listnode *node, *nnode;
        struct bgp *bgp;
+       union sockunion su;
        json_object *json = NULL;
-       int is_first = 1;
+       int ret, is_first = 1;
 
        if (use_json)
                vty_out(vty, "{\n");
@@ -9868,7 +9923,7 @@ static void bgp_show_all_instances_neighbors_vty(struct vty *vty,
                        json_object_int_add(json, "vrfId",
                                            (bgp->vrf_id == VRF_UNKNOWN)
                                                    ? -1
-                                                   : bgp->vrf_id);
+                                                   : (int64_t)bgp->vrf_id);
                        json_object_string_add(
                                json, "vrfName",
                                (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)
@@ -9890,8 +9945,19 @@ static void bgp_show_all_instances_neighbors_vty(struct vty *vty,
                                        ? "Default"
                                        : bgp->name);
                }
-               bgp_show_neighbor(vty, bgp, show_all, NULL, NULL, use_json,
-                                 json);
+
+               if (type == show_peer) {
+                       ret = str2sockunion(ip_str, &su);
+                       if (ret < 0)
+                               bgp_show_neighbor(vty, bgp, type, NULL, ip_str,
+                                                 use_json, json);
+                       else
+                               bgp_show_neighbor(vty, bgp, type, &su, NULL,
+                                                 use_json, json);
+               } else {
+                       bgp_show_neighbor(vty, bgp, show_all, NULL, NULL,
+                                         use_json, json);
+               }
        }
 
        if (use_json)
@@ -9909,7 +9975,8 @@ static int bgp_show_neighbor_vty(struct vty *vty, const char *name,
 
        if (name) {
                if (strmatch(name, "all")) {
-                       bgp_show_all_instances_neighbors_vty(vty, use_json);
+                       bgp_show_all_instances_neighbors_vty(vty, type, ip_str,
+                                                            use_json);
                        return CMD_SUCCESS;
                } else {
                        bgp = bgp_lookup_by_name(name);
@@ -10591,7 +10658,8 @@ DEFUN (show_ip_bgp_peer_groups,
        vrf = pg = NULL;
        int idx = 0;
 
-       vrf = argv_find(argv, argc, "VIEWVRFNAME", &idx) ? argv[idx]->arg : NULL;
+       vrf = argv_find(argv, argc, "VIEWVRFNAME", &idx) ? argv[idx]->arg
+                                                        : NULL;
        pg = argv_find(argv, argc, "PGNAME", &idx) ? argv[idx]->arg : NULL;
 
        return bgp_show_peer_group_vty(vty, vrf, pg);
@@ -11558,6 +11626,9 @@ void bgp_vty_init(void)
        install_element(BGP_NODE, &bgp_listen_range_cmd);
        install_element(BGP_NODE, &no_bgp_listen_range_cmd);
 
+       /* "bgp default shutdown" command */
+       install_element(BGP_NODE, &bgp_default_shutdown_cmd);
+
        /* "neighbor remote-as" commands. */
        install_element(BGP_NODE, &neighbor_remote_as_cmd);
        install_element(BGP_NODE, &neighbor_interface_config_cmd);
index e456f7caed0611ae69420ab8bb135982da091db0..cbb41f0840a526e8e41559f9d08d0aa08510cb53 100644 (file)
@@ -44,9 +44,9 @@ struct bgp;
        "Address Family modifier\n"
 
 extern void bgp_vty_init(void);
-extern const char *afi_safi_print(afi_t, safi_t);
-extern const char *afi_safi_json(afi_t, safi_t);
-extern void bgp_config_write_update_delay(struct vty *, struct bgp *);
+extern const char *afi_safi_print(afi_t afi, safi_t safi);
+extern const char *afi_safi_json(afi_t afi, safi_t safi);
+extern void bgp_config_write_update_delay(struct vty *vty, struct bgp *bgp);
 extern void bgp_config_write_wpkt_quanta(struct vty *vty, struct bgp *bgp);
 extern void bgp_config_write_rpkt_quanta(struct vty *vty, struct bgp *bgp);
 extern void bgp_config_write_listen(struct vty *vty, struct bgp *bgp);
index 1cf04abfce69a32c7a9682133cdaaf5784aa9548..1dc08e2b008c0d57046a11a6470dba27996a6870 100644 (file)
@@ -570,8 +570,8 @@ static int zebra_read_route(int command, struct zclient *zclient,
 
                /* Now perform the add/update. */
                bgp_redistribute_add(bgp, &api.prefix, &nexthop, ifindex,
-                                    nhtype, api.metric, api.type,
-                                    api.instance, api.tag);
+                                    nhtype, api.metric, api.type, api.instance,
+                                    api.tag);
        } else {
                bgp_redistribute_delete(bgp, &api.prefix, api.type,
                                        api.instance);
@@ -999,6 +999,7 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p,
 
        /* Make Zebra API structure. */
        memset(&api, 0, sizeof(api));
+       memcpy(&api.rmac, &(info->attr->rmac), sizeof(struct ethaddr));
        api.vrf_id = bgp->vrf_id;
        api.type = ZEBRA_ROUTE_BGP;
        api.safi = safi;
@@ -1015,6 +1016,13 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p,
        if (info->sub_type == BGP_ROUTE_AGGREGATE)
                zapi_route_set_blackhole(&api, BLACKHOLE_NULL);
 
+       /* If it is an EVPN route mark as such.
+        * Currently presence of rmac in attr denotes
+        * this is an EVPN type-2 route
+        */
+       if (!is_zero_mac(&(info->attr->rmac)))
+               SET_FLAG(api.flags, ZEBRA_FLAG_EVPN_ROUTE);
+
        if (peer->sort == BGP_PEER_IBGP || peer->sort == BGP_PEER_CONFED
            || info->sub_type == BGP_ROUTE_AGGREGATE) {
                SET_FLAG(api.flags, ZEBRA_FLAG_IBGP);
@@ -1072,7 +1080,14 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p,
 
                        api_nh = &api.nexthops[valid_nh_count];
                        api_nh->gate.ipv4 = *nexthop;
-                       api_nh->type = NEXTHOP_TYPE_IPV4;
+                       api_nh->vrf_id = bgp->vrf_id;
+                       /* EVPN type-2 routes are
+                          programmed as onlink on l3-vni SVI
+                        */
+                       if (CHECK_FLAG(api.flags, ZEBRA_FLAG_EVPN_ROUTE))
+                               api_nh->type = NEXTHOP_TYPE_IPV4_IFINDEX;
+                       else
+                               api_nh->type = NEXTHOP_TYPE_IPV4;
                } else {
                        ifindex_t ifindex;
                        struct in6_addr *nexthop;
@@ -1127,9 +1142,10 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p,
                }
 
                if (mpinfo->extra
-                   && bgp_is_valid_label(&mpinfo->extra->label)) {
+                   && bgp_is_valid_label(&mpinfo->extra->label[0])
+                   && !CHECK_FLAG(api.flags, ZEBRA_FLAG_EVPN_ROUTE)) {
                        has_valid_label = 1;
-                       label = label_pton(&mpinfo->extra->label);
+                       label = label_pton(&mpinfo->extra->label[0]);
 
                        api_nh->label_num = 1;
                        api_nh->labels[0] = label;
@@ -1137,7 +1153,8 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p,
                valid_nh_count++;
        }
 
-       if (has_valid_label)
+       /* if this is a evpn route we don't have to include the label */
+       if (has_valid_label && !(CHECK_FLAG(api.flags, ZEBRA_FLAG_EVPN_ROUTE)))
                SET_FLAG(api.message, ZAPI_MESSAGE_LABEL);
 
        if (info->sub_type != BGP_ROUTE_AGGREGATE)
@@ -1179,7 +1196,8 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p,
                                  sizeof(nh_buf));
 
                        label_buf[0] = '\0';
-                       if (has_valid_label)
+                       if (has_valid_label
+                           && !CHECK_FLAG(api.flags, ZEBRA_FLAG_EVPN_ROUTE))
                                sprintf(label_buf, "label %u",
                                        api_nh->labels[0]);
                        zlog_debug("  nhop [%d]: %s %s", i + 1, nh_buf,
@@ -1233,11 +1251,19 @@ void bgp_zebra_withdraw(struct prefix *p, struct bgp_info *info, safi_t safi)
                return;
 
        memset(&api, 0, sizeof(api));
+       memcpy(&api.rmac, &(info->attr->rmac), sizeof(struct ethaddr));
        api.vrf_id = peer->bgp->vrf_id;
        api.type = ZEBRA_ROUTE_BGP;
        api.safi = safi;
        api.prefix = *p;
 
+       /* If it is an EVPN route mark as such.
+        * Currently presence of rmac in attr denotes
+        * this is an EVPN type-2 route
+        */
+       if (!is_zero_mac(&(info->attr->rmac)))
+               SET_FLAG(api.flags, ZEBRA_FLAG_EVPN_ROUTE);
+
        if (peer->sort == BGP_PEER_IBGP) {
                SET_FLAG(api.flags, ZEBRA_FLAG_INTERNAL);
                SET_FLAG(api.flags, ZEBRA_FLAG_IBGP);
@@ -1516,8 +1542,9 @@ void bgp_update_redist_vrf_bitmaps(struct bgp *bgp, vrf_id_t old_vrf_id)
 
        for (afi = AFI_IP; afi < AFI_MAX; afi++)
                for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
-                       if (vrf_bitmap_check(zclient->redist[afi][i],
-                                            old_vrf_id)) {
+                       if ((old_vrf_id == VRF_UNKNOWN)
+                           || vrf_bitmap_check(zclient->redist[afi][i],
+                                               old_vrf_id)) {
                                vrf_bitmap_unset(zclient->redist[afi][i],
                                                 old_vrf_id);
                                vrf_bitmap_set(zclient->redist[afi][i],
@@ -1549,8 +1576,7 @@ void bgp_zebra_instance_register(struct bgp *bgp)
 
        /* For default instance, register to learn about VNIs, if appropriate.
         */
-       if (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT
-           && bgp->advertise_all_vni)
+       if (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT && is_evpn_enabled())
                bgp_zebra_advertise_all_vni(bgp, 1);
 }
 
@@ -1568,8 +1594,7 @@ void bgp_zebra_instance_deregister(struct bgp *bgp)
 
        /* For default instance, unregister learning about VNIs, if appropriate.
         */
-       if (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT
-           && bgp->advertise_all_vni)
+       if (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT && is_evpn_enabled())
                bgp_zebra_advertise_all_vni(bgp, 0);
 
        /* Deregister for router-id, interfaces, redistributed routes. */
@@ -1605,6 +1630,29 @@ void bgp_zebra_terminate_radv(struct bgp *bgp, struct peer *peer)
        zclient_send_interface_radv_req(zclient, bgp->vrf_id, peer->ifp, 0, 0);
 }
 
+int bgp_zebra_advertise_subnet(struct bgp *bgp, int advertise, vni_t vni)
+{
+       struct stream *s = NULL;
+
+       /* Check socket. */
+       if (!zclient || zclient->sock < 0)
+               return 0;
+
+       /* Don't try to register if Zebra doesn't know of this instance. */
+       if (!IS_BGP_INST_KNOWN_TO_ZEBRA(bgp))
+               return 0;
+
+       s = zclient->obuf;
+       stream_reset(s);
+
+       zclient_create_header(s, ZEBRA_ADVERTISE_SUBNET, bgp->vrf_id);
+       stream_putc(s, advertise);
+       stream_put3(s, vni);
+       stream_putw_at(s, 0, stream_get_endp(s));
+
+       return zclient_send_message(zclient);
+}
+
 int bgp_zebra_advertise_gw_macip(struct bgp *bgp, int advertise, vni_t vni)
 {
        struct stream *s = NULL;
@@ -1675,30 +1723,68 @@ static void bgp_zebra_connected(struct zclient *zclient)
         */
 }
 
+static int bgp_zebra_process_local_l3vni(int cmd, struct zclient *zclient,
+                                        zebra_size_t length, vrf_id_t vrf_id)
+{
+       char buf[ETHER_ADDR_STRLEN];
+       vni_t l3vni = 0;
+       struct ethaddr rmac;
+       struct in_addr originator_ip;
+       struct stream *s;
+
+       memset(&rmac, 0, sizeof(struct ethaddr));
+       memset(&originator_ip, 0, sizeof(struct in_addr));
+       s = zclient->ibuf;
+       l3vni = stream_getl(s);
+       if (cmd == ZEBRA_L3VNI_ADD) {
+               stream_get(&rmac, s, sizeof(struct ethaddr));
+               originator_ip.s_addr = stream_get_ipv4(s);
+       }
+
+       if (BGP_DEBUG(zebra, ZEBRA))
+               zlog_debug("Rx L3-VNI %s VRF %s VNI %u RMAC %s",
+                          (cmd == ZEBRA_L3VNI_ADD) ? "add" : "del",
+                          vrf_id_to_name(vrf_id), l3vni,
+                          prefix_mac2str(&rmac, buf, sizeof(buf)));
+
+       if (cmd == ZEBRA_L3VNI_ADD)
+               bgp_evpn_local_l3vni_add(l3vni, vrf_id, &rmac, originator_ip);
+       else
+               bgp_evpn_local_l3vni_del(l3vni, vrf_id);
+
+       return 0;
+}
+
 static int bgp_zebra_process_local_vni(int command, struct zclient *zclient,
                                       zebra_size_t length, vrf_id_t vrf_id)
 {
        struct stream *s;
        vni_t vni;
        struct bgp *bgp;
-       struct in_addr vtep_ip;
+       struct in_addr vtep_ip = {INADDR_ANY};
+       vrf_id_t tenant_vrf_id = VRF_DEFAULT;
 
        s = zclient->ibuf;
        vni = stream_getl(s);
-       if (command == ZEBRA_VNI_ADD)
+       if (command == ZEBRA_VNI_ADD) {
                vtep_ip.s_addr = stream_get_ipv4(s);
+               stream_get(&tenant_vrf_id, s, sizeof(vrf_id_t));
+       }
+
        bgp = bgp_lookup_by_vrf_id(vrf_id);
        if (!bgp)
                return 0;
 
        if (BGP_DEBUG(zebra, ZEBRA))
-               zlog_debug("Rx VNI %s VRF %u VNI %u",
-                          (command == ZEBRA_VNI_ADD) ? "add" : "del", vrf_id,
-                          vni);
+               zlog_debug("Rx VNI %s VRF %s VNI %u tenant-vrf %s",
+                          (command == ZEBRA_VNI_ADD) ? "add" : "del",
+                          vrf_id_to_name(vrf_id), vni,
+                          vrf_id_to_name(tenant_vrf_id));
 
        if (command == ZEBRA_VNI_ADD)
                return bgp_evpn_local_vni_add(
-                       bgp, vni, vtep_ip.s_addr ? vtep_ip : bgp->router_id);
+                       bgp, vni, vtep_ip.s_addr ? vtep_ip : bgp->router_id,
+                       tenant_vrf_id);
        else
                return bgp_evpn_local_vni_del(bgp, vni);
 }
@@ -1752,6 +1838,48 @@ static int bgp_zebra_process_local_macip(int command, struct zclient *zclient,
                return bgp_evpn_local_macip_del(bgp, vni, &mac, &ip);
 }
 
+static void bgp_zebra_process_local_ip_prefix(int cmd, struct zclient *zclient,
+                                             zebra_size_t length,
+                                             vrf_id_t vrf_id)
+{
+       struct stream *s = NULL;
+       struct bgp *bgp_vrf = NULL;
+       struct prefix p;
+       char buf[PREFIX_STRLEN];
+
+       memset(&p, 0, sizeof(struct prefix));
+       s = zclient->ibuf;
+       stream_get(&p, s, sizeof(struct prefix));
+
+       bgp_vrf = bgp_lookup_by_vrf_id(vrf_id);
+       if (!bgp_vrf)
+               return;
+
+       if (BGP_DEBUG(zebra, ZEBRA))
+               zlog_debug("Recv prefix %s %s on vrf %s",
+                          prefix2str(&p, buf, sizeof(buf)),
+                          (cmd == ZEBRA_IP_PREFIX_ROUTE_ADD) ? "ADD" : "DEL",
+                          vrf_id_to_name(vrf_id));
+
+       if (cmd == ZEBRA_IP_PREFIX_ROUTE_ADD) {
+
+               if (p.family == AF_INET)
+                       return bgp_evpn_advertise_type5_route(
+                               bgp_vrf, &p, NULL, AFI_IP, SAFI_UNICAST);
+               else
+                       return bgp_evpn_advertise_type5_route(
+                               bgp_vrf, &p, NULL, AFI_IP6, SAFI_UNICAST);
+
+       } else {
+               if (p.family == AF_INET)
+                       return bgp_evpn_withdraw_type5_route(
+                               bgp_vrf, &p, AFI_IP, SAFI_UNICAST);
+               else
+                       return bgp_evpn_withdraw_type5_route(
+                               bgp_vrf, &p, AFI_IP6, SAFI_UNICAST);
+       }
+}
+
 extern struct zebra_privs_t bgpd_privs;
 
 void bgp_zebra_init(struct thread_master *master)
@@ -1782,6 +1910,10 @@ void bgp_zebra_init(struct thread_master *master)
        zclient->local_vni_del = bgp_zebra_process_local_vni;
        zclient->local_macip_add = bgp_zebra_process_local_macip;
        zclient->local_macip_del = bgp_zebra_process_local_macip;
+       zclient->local_l3vni_add = bgp_zebra_process_local_l3vni;
+       zclient->local_l3vni_del = bgp_zebra_process_local_l3vni;
+       zclient->local_ip_prefix_add = bgp_zebra_process_local_ip_prefix;
+       zclient->local_ip_prefix_del = bgp_zebra_process_local_ip_prefix;
 }
 
 void bgp_zebra_destroy(void)
index 7d37864f44a8cce16d32064a8dfbc77cadf002fc..da5160bc16d6c0ce96e8950eb58dff71ebe5a257 100644 (file)
@@ -58,7 +58,8 @@ extern struct interface *if_lookup_by_ipv6(struct in6_addr *, ifindex_t,
                                           vrf_id_t);
 extern struct interface *if_lookup_by_ipv6_exact(struct in6_addr *, ifindex_t,
                                                 vrf_id_t);
-
+extern int bgp_zebra_advertise_subnet(struct bgp *bgp, int advertise,
+                                     vni_t vni);
 extern int bgp_zebra_advertise_gw_macip(struct bgp *, int, vni_t);
 extern int bgp_zebra_advertise_all_vni(struct bgp *, int);
 
index 6dcb603cb68c4ff65ebdbcc7b4d79baec5f6b992..78e748fb6c5d2c5765af9ee67f6121f8b838c9ee 100644 (file)
@@ -24,6 +24,7 @@
 #include "thread.h"
 #include "buffer.h"
 #include "stream.h"
+#include "ringbuf.h"
 #include "command.h"
 #include "sockunion.h"
 #include "sockopt.h"
@@ -78,7 +79,7 @@
 #include "bgpd/bgp_evpn_vty.h"
 #include "bgpd/bgp_keepalives.h"
 #include "bgpd/bgp_io.h"
-
+#include "bgpd/bgp_ecommunity.h"
 
 DEFINE_MTYPE_STATIC(BGPD, PEER_TX_SHUTDOWN_MSG, "Peer shutdown message (TX)");
 DEFINE_QOBJ_TYPE(bgp_master)
@@ -217,7 +218,7 @@ static int bgp_router_id_set(struct bgp *bgp, const struct in_addr *id)
                return 0;
 
        /* EVPN uses router id in RD, withdraw them */
-       if (bgp->advertise_all_vni)
+       if (is_evpn_enabled())
                bgp_evpn_handle_router_id_update(bgp, TRUE);
 
        IPV4_ADDR_COPY(&bgp->router_id, id);
@@ -234,7 +235,7 @@ static int bgp_router_id_set(struct bgp *bgp, const struct in_addr *id)
        }
 
        /* EVPN uses router id in RD, update them */
-       if (bgp->advertise_all_vni)
+       if (is_evpn_enabled())
                bgp_evpn_handle_router_id_update(bgp, FALSE);
 
        return 0;
@@ -865,8 +866,7 @@ static void peer_af_flag_reset(struct peer *peer, afi_t afi, safi_t safi)
 /* peer global config reset */
 static void peer_global_config_reset(struct peer *peer)
 {
-
-       int v6only;
+       int saved_flags = 0;
 
        peer->change_local_as = 0;
        peer->ttl = (peer_sort(peer) == BGP_PEER_IBGP ? MAXTTL : 1);
@@ -884,13 +884,11 @@ static void peer_global_config_reset(struct peer *peer)
        else
                peer->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV;
 
-       /* This is a per-peer specific flag and so we must preserve it */
-       v6only = CHECK_FLAG(peer->flags, PEER_FLAG_IFPEER_V6ONLY);
-
+       /* These are per-peer specific flags and so we must preserve them */
+       saved_flags |= CHECK_FLAG(peer->flags, PEER_FLAG_IFPEER_V6ONLY);
+       saved_flags |= CHECK_FLAG(peer->flags, PEER_FLAG_SHUTDOWN);
        peer->flags = 0;
-
-       if (v6only)
-               SET_FLAG(peer->flags, PEER_FLAG_IFPEER_V6ONLY);
+       SET_FLAG(peer->flags, saved_flags);
 
        peer->config = 0;
        peer->holdtime = 0;
@@ -1150,19 +1148,19 @@ struct peer *peer_new(struct bgp *bgp)
         * - We RX a BGP_UPDATE where the attributes alone are just
         *   under BGP_MAX_PACKET_SIZE
         * - The user configures an outbound route-map that does many as-path
-        *   prepends or adds many communities.  At most they can have
-        * CMD_ARGC_MAX
-        *   args in a route-map so there is a finite limit on how large they
-        * can
-        *   make the attributes.
+        *   prepends or adds many communities. At most they can have
+        *   CMD_ARGC_MAX args in a route-map so there is a finite limit on how
+        *   large they can make the attributes.
         *
         * Having a buffer with BGP_MAX_PACKET_SIZE_OVERFLOW allows us to avoid
-        * bounds
-        * checking for every single attribute as we construct an UPDATE.
+        * bounds checking for every single attribute as we construct an
+        * UPDATE.
         */
        peer->obuf_work =
                stream_new(BGP_MAX_PACKET_SIZE + BGP_MAX_PACKET_SIZE_OVERFLOW);
-       peer->ibuf_work = stream_new(BGP_MAX_PACKET_SIZE * BGP_READ_PACKET_MAX);
+       peer->ibuf_work =
+               ringbuf_new(BGP_MAX_PACKET_SIZE * BGP_READ_PACKET_MAX);
+
        peer->scratch = stream_new(BGP_MAX_PACKET_SIZE);
 
        bgp_sync_init(peer);
@@ -1405,16 +1403,12 @@ static void bgp_recalculate_afi_safi_bestpaths(struct bgp *bgp, afi_t afi,
                if (rn->info != NULL) {
                        /* Special handling for 2-level routing
                         * tables. */
-                       if (safi == SAFI_MPLS_VPN
-                           || safi == SAFI_ENCAP
+                       if (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP
                            || safi == SAFI_EVPN) {
-                               for (nrn = bgp_table_top((
-                                            struct bgp_table
-                                                    *)(rn->info));
-                                    nrn;
-                                    nrn = bgp_route_next(nrn))
-                                       bgp_process(bgp, nrn,
-                                                   afi, safi);
+                               for (nrn = bgp_table_top(
+                                            (struct bgp_table *)(rn->info));
+                                    nrn; nrn = bgp_route_next(nrn))
+                                       bgp_process(bgp, nrn, afi, safi);
                        } else
                                bgp_process(bgp, rn, afi, safi);
                }
@@ -1497,8 +1491,11 @@ struct peer *peer_create(union sockunion *su, const char *conf_if,
                peer_af_create(peer, afi, safi);
        }
 
+       /* auto shutdown if configured */
+       if (bgp->autoshutdown)
+               peer_flag_set(peer, PEER_FLAG_SHUTDOWN);
        /* Set up peer's events and timers. */
-       if (!active && peer_active(peer))
+       else if (!active && peer_active(peer))
                bgp_timer_set(peer);
 
        return peer;
@@ -1863,8 +1860,7 @@ static int peer_activate_af(struct peer *peer, afi_t afi, safi_t safi)
        peer->afc[afi][safi] = 1;
 
        if (peer->group)
-               peer_group2peer_config_copy_af(peer->group, peer,
-                                              afi, safi);
+               peer_group2peer_config_copy_af(peer->group, peer, afi, safi);
 
        if (!active && peer_active(peer)) {
                bgp_timer_set(peer);
@@ -1932,12 +1928,14 @@ int peer_activate(struct peer *peer, afi_t afi, safi_t safi)
                ret |= peer_activate_af(peer, afi, safi);
        }
 
-       /* If this is the first peer to be activated for this afi/labeled-unicast
-        * recalc bestpaths to trigger label allocation */
-       if (safi == SAFI_LABELED_UNICAST && !bgp->allocate_mpls_labels[afi][SAFI_UNICAST]) {
+       /* If this is the first peer to be activated for this
+        * afi/labeled-unicast recalc bestpaths to trigger label allocation */
+       if (safi == SAFI_LABELED_UNICAST
+           && !bgp->allocate_mpls_labels[afi][SAFI_UNICAST]) {
 
                if (BGP_DEBUG(zebra, ZEBRA))
-                       zlog_info("peer(s) are now active for labeled-unicast, allocate MPLS labels");
+                       zlog_info(
+                               "peer(s) are now active for labeled-unicast, allocate MPLS labels");
 
                bgp->allocate_mpls_labels[afi][SAFI_UNICAST] = 1;
                bgp_recalculate_afi_safi_bestpaths(bgp, afi, SAFI_UNICAST);
@@ -2026,14 +2024,15 @@ int peer_deactivate(struct peer *peer, afi_t afi, safi_t safi)
 
        bgp = peer->bgp;
 
-       /* If this is the last peer to be deactivated for this afi/labeled-unicast
-        * recalc bestpaths to trigger label deallocation */
-       if (safi == SAFI_LABELED_UNICAST &&
-           bgp->allocate_mpls_labels[afi][SAFI_UNICAST] &&
-           !bgp_afi_safi_peer_exists(bgp, afi, safi)) {
+       /* If this is the last peer to be deactivated for this
+        * afi/labeled-unicast recalc bestpaths to trigger label deallocation */
+       if (safi == SAFI_LABELED_UNICAST
+           && bgp->allocate_mpls_labels[afi][SAFI_UNICAST]
+           && !bgp_afi_safi_peer_exists(bgp, afi, safi)) {
 
                if (BGP_DEBUG(zebra, ZEBRA))
-                       zlog_info("peer(s) are no longer active for labeled-unicast, deallocate MPLS labels");
+                       zlog_info(
+                               "peer(s) are no longer active for labeled-unicast, deallocate MPLS labels");
 
                bgp->allocate_mpls_labels[afi][SAFI_UNICAST] = 0;
                bgp_recalculate_afi_safi_bestpaths(bgp, afi, SAFI_UNICAST);
@@ -2179,7 +2178,7 @@ int peer_delete(struct peer *peer)
        }
 
        if (peer->ibuf_work) {
-               stream_free(peer->ibuf_work);
+               ringbuf_del(peer->ibuf_work);
                peer->ibuf_work = NULL;
        }
 
@@ -2339,7 +2338,7 @@ static void peer_group2peer_config_copy(struct peer_group *group,
                                        struct peer *peer)
 {
        struct peer *conf;
-       int v6only;
+       int saved_flags = 0;
 
        conf = group->conf;
 
@@ -2357,14 +2356,11 @@ static void peer_group2peer_config_copy(struct peer_group *group,
        /* GTSM hops */
        peer->gtsm_hops = conf->gtsm_hops;
 
-       /* this flag is per-neighbor and so has to be preserved */
-       v6only = CHECK_FLAG(peer->flags, PEER_FLAG_IFPEER_V6ONLY);
-
-       /* peer flags apply */
+       /* These are per-peer specific flags and so we must preserve them */
+       saved_flags |= CHECK_FLAG(peer->flags, PEER_FLAG_IFPEER_V6ONLY);
+       saved_flags |= CHECK_FLAG(peer->flags, PEER_FLAG_SHUTDOWN);
        peer->flags = conf->flags;
-
-       if (v6only)
-               SET_FLAG(peer->flags, PEER_FLAG_IFPEER_V6ONLY);
+       SET_FLAG(peer->flags, saved_flags);
 
        /* peer config apply */
        peer->config = conf->config;
@@ -2656,7 +2652,7 @@ int peer_group_bind(struct bgp *bgp, union sockunion *su, struct peer *peer,
                                }
                        } else if (peer->afc[afi][safi])
                                peer_deactivate(peer, afi, safi);
-                       }
+               }
 
                if (peer->group) {
                        assert(group && peer->group == group);
@@ -2858,8 +2854,7 @@ static struct bgp *bgp_create(as_t *as, const char *name,
                        XSTRDUP(MTYPE_BGP_PEER_HOST, cmd_domainname_get());
        bgp->peer = list_new();
        bgp->peer->cmp = (int (*)(void *, void *))peer_cmp;
-       bgp->peerhash = hash_create(peer_hash_key_make,
-                                   peer_hash_same,
+       bgp->peerhash = hash_create(peer_hash_key_make, peer_hash_same,
                                    "BGP Peer Hash");
        bgp->peerhash->max_size = BGP_PEER_MAX_HASH_SIZE;
 
@@ -3142,6 +3137,9 @@ int bgp_delete(struct bgp *bgp)
                                   bgp->name);
        }
 
+       /* unmap from RT list */
+       bgp_evpn_vrf_delete(bgp);
+
        /* Stop timers. */
        if (bgp->t_rmap_def_originate_eval) {
                BGP_TIMER_OFF(bgp->t_rmap_def_originate_eval);
@@ -3987,8 +3985,9 @@ static int peer_af_flag_modify(struct peer *peer, afi_t afi, safi_t safi,
        }
 
        /* Track if addpath TX is in use */
-       if (flag & (PEER_FLAG_ADDPATH_TX_ALL_PATHS
-                   | PEER_FLAG_ADDPATH_TX_BESTPATH_PER_AS)) {
+       if (flag
+           & (PEER_FLAG_ADDPATH_TX_ALL_PATHS
+              | PEER_FLAG_ADDPATH_TX_BESTPATH_PER_AS)) {
                bgp = peer->bgp;
                addpath_tx_used = 0;
 
@@ -6801,8 +6800,9 @@ static void bgp_config_write_peer_af(struct vty *vty, struct bgp *bgp,
        } else {
                if (!peer_af_flag_check(peer, afi, safi,
                                        PEER_FLAG_SEND_COMMUNITY)
-                   && (!g_peer || peer_af_flag_check(g_peer, afi, safi,
-                                                     PEER_FLAG_SEND_COMMUNITY))
+                   && (!g_peer
+                       || peer_af_flag_check(g_peer, afi, safi,
+                                             PEER_FLAG_SEND_COMMUNITY))
                    && !peer_af_flag_check(peer, afi, safi,
                                           PEER_FLAG_SEND_EXT_COMMUNITY)
                    && (!g_peer
@@ -6810,9 +6810,10 @@ static void bgp_config_write_peer_af(struct vty *vty, struct bgp *bgp,
                                              PEER_FLAG_SEND_EXT_COMMUNITY))
                    && !peer_af_flag_check(peer, afi, safi,
                                           PEER_FLAG_SEND_LARGE_COMMUNITY)
-                   && (!g_peer || peer_af_flag_check(
-                                          g_peer, afi, safi,
-                                          PEER_FLAG_SEND_LARGE_COMMUNITY))) {
+                   && (!g_peer
+                       || peer_af_flag_check(
+                                  g_peer, afi, safi,
+                                  PEER_FLAG_SEND_LARGE_COMMUNITY))) {
                        vty_out(vty, "  no neighbor %s send-community all\n",
                                addr);
                } else {
@@ -6840,9 +6841,10 @@ static void bgp_config_write_peer_af(struct vty *vty, struct bgp *bgp,
 
                        if (!peer_af_flag_check(peer, afi, safi,
                                                PEER_FLAG_SEND_COMMUNITY)
-                           && (!g_peer || peer_af_flag_check(
-                                                  g_peer, afi, safi,
-                                                  PEER_FLAG_SEND_COMMUNITY))) {
+                           && (!g_peer
+                               || peer_af_flag_check(
+                                          g_peer, afi, safi,
+                                          PEER_FLAG_SEND_COMMUNITY))) {
                                vty_out(vty,
                                        "  no neighbor %s send-community\n",
                                        addr);
@@ -6953,17 +6955,17 @@ static void bgp_config_write_peer_af(struct vty *vty, struct bgp *bgp,
        bgp_config_write_filter(vty, peer, afi, safi);
 
        /* atribute-unchanged. */
-       if (peer_af_flag_check(peer, afi, safi, PEER_FLAG_AS_PATH_UNCHANGED) ||
-           peer_af_flag_check(peer, afi, safi, PEER_FLAG_NEXTHOP_UNCHANGED) ||
-           peer_af_flag_check(peer, afi, safi, PEER_FLAG_MED_UNCHANGED)) {
-
-               if (!peer_group_active(peer) ||
-                    peergroup_af_flag_check(peer, afi, safi,
-                                            PEER_FLAG_AS_PATH_UNCHANGED) ||
-                    peergroup_af_flag_check(peer, afi, safi,
-                                            PEER_FLAG_NEXTHOP_UNCHANGED) ||
-                    peergroup_af_flag_check(peer, afi, safi,
-                                            PEER_FLAG_MED_UNCHANGED)) {
+       if (peer_af_flag_check(peer, afi, safi, PEER_FLAG_AS_PATH_UNCHANGED)
+           || peer_af_flag_check(peer, afi, safi, PEER_FLAG_NEXTHOP_UNCHANGED)
+           || peer_af_flag_check(peer, afi, safi, PEER_FLAG_MED_UNCHANGED)) {
+
+               if (!peer_group_active(peer)
+                   || peergroup_af_flag_check(peer, afi, safi,
+                                              PEER_FLAG_AS_PATH_UNCHANGED)
+                   || peergroup_af_flag_check(peer, afi, safi,
+                                              PEER_FLAG_NEXTHOP_UNCHANGED)
+                   || peergroup_af_flag_check(peer, afi, safi,
+                                              PEER_FLAG_MED_UNCHANGED)) {
 
                        vty_out(vty,
                                "  neighbor %s attribute-unchanged%s%s%s\n",
@@ -7080,6 +7082,11 @@ int bgp_config_write(struct vty *vty)
 
        /* BGP configuration. */
        for (ALL_LIST_ELEMENTS(bm->bgp, mnode, mnnode, bgp)) {
+
+               /* skip all auto created vrf as they dont have user config */
+               if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_AUTO))
+                       continue;
+
                /* Router bgp ASN */
                vty_out(vty, "router bgp %u", bgp->as);
 
@@ -7143,6 +7150,10 @@ int bgp_config_write(struct vty *vty)
                        vty_out(vty, " bgp default subgroup-pkt-queue-max %u\n",
                                bgp->default_subgroup_pkt_queue_max);
 
+               /* BGP default autoshutdown neighbors */
+               if (bgp->autoshutdown)
+                       vty_out(vty, " bgp default shutdown\n");
+
                /* BGP client-to-client reflection. */
                if (bgp_flag_check(bgp, BGP_FLAG_NO_CLIENT_TO_CLIENT))
                        vty_out(vty, " no bgp client-to-client reflection\n");
@@ -7304,6 +7315,38 @@ int bgp_config_write(struct vty *vty)
                if (bgp_option_check(BGP_OPT_CONFIG_CISCO))
                        vty_out(vty, " no auto-summary\n");
 
+               /* import route-target */
+               if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_IMPORT_RT_CFGD)) {
+                       char *ecom_str;
+                       struct listnode *node, *nnode;
+                       struct ecommunity *ecom;
+
+                       for (ALL_LIST_ELEMENTS(bgp->vrf_import_rtl, node, nnode,
+                                              ecom)) {
+                               ecom_str = ecommunity_ecom2str(
+                                       ecom, ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
+                               vty_out(vty, "   route-target import %s\n",
+                                       ecom_str);
+                               XFREE(MTYPE_ECOMMUNITY_STR, ecom_str);
+                       }
+               }
+
+               /* export route-target */
+               if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_EXPORT_RT_CFGD)) {
+                       char *ecom_str;
+                       struct listnode *node, *nnode;
+                       struct ecommunity *ecom;
+
+                       for (ALL_LIST_ELEMENTS(bgp->vrf_export_rtl, node, nnode,
+                                              ecom)) {
+                               ecom_str = ecommunity_ecom2str(
+                                       ecom, ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
+                               vty_out(vty, "   route-target export %s\n",
+                                       ecom_str);
+                               XFREE(MTYPE_ECOMMUNITY_STR, ecom_str);
+                       }
+               }
+
                /* IPv4 unicast configuration.  */
                bgp_config_write_family(vty, bgp, AFI_IP, SAFI_UNICAST);
 
@@ -7364,6 +7407,13 @@ void bgp_master_init(struct thread_master *master)
 
        bgp_process_queue_init();
 
+       /* init the rd id space.
+          assign 0th index in the bitfield,
+          so that we start with id 1
+        */
+       bf_init(bm->rd_idspace, UINT16_MAX);
+       bf_assign_zero_index(bm->rd_idspace);
+
        /* Enable multiple instances by default. */
        bgp_option_set(BGP_OPT_MULTIPLE_INSTANCE);
 
@@ -7421,24 +7471,33 @@ static void bgp_pthreads_init()
 {
        frr_pthread_init();
 
-       frr_pthread_new("BGP i/o thread", PTHREAD_IO, bgp_io_start,
-                       bgp_io_stop);
-       frr_pthread_new("BGP keepalives thread", PTHREAD_KEEPALIVES,
-                       bgp_keepalives_start, bgp_keepalives_stop);
-
-       /* pre-run initialization */
-       bgp_keepalives_init();
-       bgp_io_init();
+       struct frr_pthread_attr io = {
+               .id = PTHREAD_IO,
+               .start = frr_pthread_attr_default.start,
+               .stop = frr_pthread_attr_default.stop,
+               .name = "BGP I/O thread",
+       };
+       struct frr_pthread_attr ka = {
+               .id = PTHREAD_KEEPALIVES,
+               .start = bgp_keepalives_start,
+               .stop = bgp_keepalives_stop,
+               .name = "BGP Keepalives thread",
+       };
+       frr_pthread_new(&io);
+       frr_pthread_new(&ka);
 }
 
 void bgp_pthreads_run()
 {
-       pthread_attr_t attr;
-       pthread_attr_init(&attr);
-       pthread_attr_setschedpolicy(&attr, SCHED_FIFO);
+       struct frr_pthread *io = frr_pthread_get(PTHREAD_IO);
+       struct frr_pthread *ka = frr_pthread_get(PTHREAD_KEEPALIVES);
 
-       frr_pthread_run(PTHREAD_IO, &attr, NULL);
-       frr_pthread_run(PTHREAD_KEEPALIVES, &attr, NULL);
+       frr_pthread_run(io, NULL);
+       frr_pthread_run(ka, NULL);
+
+       /* Wait until threads are ready. */
+       frr_pthread_wait_running(io);
+       frr_pthread_wait_running(ka);
 }
 
 void bgp_pthreads_finish()
@@ -7520,6 +7579,7 @@ void bgp_terminate(void)
         */
        /* reverse bgp_master_init */
        bgp_close();
+
        if (bm->listen_sockets)
                list_delete_and_null(&bm->listen_sockets);
 
index 6bb49e0c53ea7939e268bcf635d251ce18afabf9..220b6d989e43b551f98b8275d4884b85f7c6c14d 100644 (file)
@@ -36,6 +36,7 @@
 #include "defaults.h"
 #include "bgp_memory.h"
 #include "bitfield.h"
+#include "vxlan.h"
 
 #define BGP_MAX_HOSTNAME 64    /* Linux max, is larger than most other sys */
 #define BGP_PEER_MAX_HASH_SIZE 16384
@@ -136,6 +137,9 @@ struct bgp_master {
                                      /* clang-format off */
 #define RMAP_DEFAULT_UPDATE_TIMER 5 /* disabled by default */
 
+       /* Id space for automatic RD derivation for an EVI/VRF */
+       bitfield_t rd_idspace;
+
        QOBJ_FIELDS
 };
 DECLARE_QOBJ_TYPE(bgp_master)
@@ -258,13 +262,14 @@ struct bgp {
                               /* $FRR indent$ */
                               /* clang-format off */
 #define BGP_MAXMED_ADMIN_UNCONFIGURED  0 /* Off by default */
-       u_int32_t
-               maxmed_admin_value; /* Max-med value when administrative in on
+       u_int32_t maxmed_admin_value; /* Max-med value when administrative in on
                                       */
+                                     /* $FRR indent$ */
+                                     /* clang-format off */
 #define BGP_MAXMED_VALUE_DEFAULT  4294967294 /* Maximum by default */
 
-       u_char maxmed_active;   /* 1/0 if max-med is active or not */
-       u_int32_t maxmed_value; /* Max-med value when its active */
+       u_char maxmed_active;    /* 1/0 if max-med is active or not */
+       u_int32_t maxmed_value;       /* Max-med value when its active */
 
        /* BGP update delay on startup */
        struct thread *t_update_delay;
@@ -386,6 +391,9 @@ struct bgp {
        /* Actual coalesce time */
        uint32_t coalesce_time;
 
+       /* Auto-shutdown new peers */
+       bool autoshutdown;
+
        u_int32_t addpath_tx_id;
        int addpath_tx_used[AFI_MAX][SAFI_MAX];
 
@@ -408,8 +416,44 @@ struct bgp {
        /* Hash table of Import RTs to EVIs */
        struct hash *import_rt_hash;
 
-       /* Id space for automatic RD derivation for an EVI */
-       bitfield_t rd_idspace;
+       /* Hash table of VRF import RTs to VRFs */
+       struct hash *vrf_import_rt_hash;
+
+       /* L3-VNI corresponding to this vrf */
+       vni_t l3vni;
+
+       /* router-mac to be used in mac-ip routes for this vrf */
+       struct ethaddr rmac;
+
+       /* originator ip - to be used as NH for type-5 routes */
+       struct in_addr originator_ip;
+
+       /* vrf flags */
+       uint32_t vrf_flags;
+#define BGP_VRF_AUTO                        (1 << 0)
+#define BGP_VRF_ADVERTISE_IPV4_IN_EVPN      (1 << 1)
+#define BGP_VRF_ADVERTISE_IPV6_IN_EVPN      (1 << 2)
+#define BGP_VRF_IMPORT_RT_CFGD              (1 << 3)
+#define BGP_VRF_EXPORT_RT_CFGD              (1 << 4)
+#define BGP_VRF_RD_CFGD                     (1 << 5)
+
+       /* unique ID for auto derivation of RD for this vrf */
+       uint16_t vrf_rd_id;
+
+       /* RD for this VRF */
+       struct prefix_rd vrf_prd;
+
+       /* import rt list for the vrf instance */
+       struct list *vrf_import_rtl;
+
+       /* export rt list for the vrf instance */
+       struct list *vrf_export_rtl;
+
+       /* list of corresponding l2vnis (struct bgpevpn) */
+       struct list *l2vnis;
+
+       /* route map for advertise ipv4/ipv6 unicast (type-5 routes) */
+       struct bgp_rmap adv_cmd_rmap[AFI_MAX][SAFI_MAX];
 
        QOBJ_FIELDS
 };
@@ -598,8 +642,8 @@ struct peer {
        struct stream_fifo *ibuf; // packets waiting to be processed
        struct stream_fifo *obuf; // packets waiting to be written
 
-       struct stream *ibuf_work; // WiP buffer used by bgp_read() only
-       struct stream *obuf_work; // WiP buffer used to construct packets
+       struct ringbuf *ibuf_work; // WiP buffer used by bgp_read() only
+       struct stream *obuf_work;  // WiP buffer used to construct packets
 
        struct stream *curr; // the current packet being parsed
 
@@ -788,8 +832,8 @@ struct peer {
 #define PEER_CONFIG_ROUTEADV          (1 << 2) /* route advertise */
 #define PEER_GROUP_CONFIG_TIMER       (1 << 3) /* timers from peer-group */
 
-#define PEER_OR_GROUP_TIMER_SET(peer)                                        \
-       (CHECK_FLAG(peer->config, PEER_CONFIG_TIMER)                         \
+#define PEER_OR_GROUP_TIMER_SET(peer)                                          \
+       (CHECK_FLAG(peer->config, PEER_CONFIG_TIMER)                           \
         || CHECK_FLAG(peer->config, PEER_GROUP_CONFIG_TIMER))
 
        _Atomic uint32_t holdtime;
@@ -829,6 +873,30 @@ struct peer {
        /* workqueues */
        struct work_queue *clear_node_queue;
 
+#define PEER_TOTAL_RX(peer)                                                    \
+       atomic_load_explicit(&peer->open_in, memory_order_relaxed)             \
+               + atomic_load_explicit(&peer->update_in, memory_order_relaxed) \
+               + atomic_load_explicit(&peer->notify_in, memory_order_relaxed) \
+               + atomic_load_explicit(&peer->refresh_in,                      \
+                                      memory_order_relaxed)                   \
+               + atomic_load_explicit(&peer->keepalive_in,                    \
+                                      memory_order_relaxed)                   \
+               + atomic_load_explicit(&peer->dynamic_cap_in,                  \
+                                      memory_order_relaxed)
+
+#define PEER_TOTAL_TX(peer)                                                    \
+       atomic_load_explicit(&peer->open_out, memory_order_relaxed)            \
+               + atomic_load_explicit(&peer->update_out,                      \
+                                      memory_order_relaxed)                   \
+               + atomic_load_explicit(&peer->notify_out,                      \
+                                      memory_order_relaxed)                   \
+               + atomic_load_explicit(&peer->refresh_out,                     \
+                                      memory_order_relaxed)                   \
+               + atomic_load_explicit(&peer->keepalive_out,                   \
+                                      memory_order_relaxed)                   \
+               + atomic_load_explicit(&peer->dynamic_cap_out,                 \
+                                      memory_order_relaxed)
+
        /* Statistics field */
        _Atomic uint32_t open_in;         /* Open message input count */
        _Atomic uint32_t open_out;        /* Open message output count */
@@ -842,7 +910,7 @@ struct peer {
        _Atomic uint32_t refresh_in;      /* Route Refresh input count */
        _Atomic uint32_t refresh_out;     /* Route Refresh output count */
        _Atomic uint32_t dynamic_cap_in;  /* Dynamic Capability input count.  */
-       _Atomic uint32_t dynamic_cap_out; /* Dynamic Capability output count.  */
+       _Atomic uint32_t dynamic_cap_out; /* Dynamic Capability output count. */
 
        /* BGP state count */
        u_int32_t established; /* Established */
@@ -863,9 +931,6 @@ struct peer {
        /* Send prefix count. */
        unsigned long scount[AFI_MAX][SAFI_MAX];
 
-       /* Announcement attribute hash.  */
-       struct hash *hash[AFI_MAX][SAFI_MAX];
-
        /* Notify data. */
        struct bgp_notify notify;
 
@@ -1020,6 +1085,7 @@ struct bgp_nlri {
 #define BGP_ATTR_AS4_PATH                       17
 #define BGP_ATTR_AS4_AGGREGATOR                 18
 #define BGP_ATTR_AS_PATHLIMIT                   21
+#define BGP_ATTR_PMSI_TUNNEL                    22
 #define BGP_ATTR_ENCAP                          23
 #define BGP_ATTR_LARGE_COMMUNITIES              32
 #define BGP_ATTR_PREFIX_SID                     40
@@ -1426,7 +1492,8 @@ extern int peer_cmp(struct peer *p1, struct peer *p2);
 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, iana_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 7f2dbe7f9d6cf4243ff3ce52dee3991ae3fcfbc7..f28b8a2ceda69cce1b8cfd5a765d0dfc0c4cd6fe 100644 (file)
@@ -260,20 +260,21 @@ int bgp_rfapi_is_vnc_configured(struct bgp *bgp)
 /***********************************************************************
  *                     VNC Configuration/CLI
  ***********************************************************************/
-#define VNC_VTY_CONFIG_CHECK(bgp)                                      \
-       {                                                               \
-               switch (bgp_rfapi_is_vnc_configured(bgp)) {             \
-               case EPERM:                                             \
-                       vty_out(vty, "VNC operations only permitted on default BGP instance.\n"); \
-                       return CMD_WARNING_CONFIG_FAILED;               \
-                       break;                                          \
-               case ENXIO:                                             \
-                       vty_out(vty, "VNC not configured.\n");          \
-                       return CMD_WARNING_CONFIG_FAILED;               \
-                       break;                                          \
-               default:                                                \
-                       break;                                          \
-               }                                                       \
+#define VNC_VTY_CONFIG_CHECK(bgp)                                                            \
+       {                                                                                    \
+               switch (bgp_rfapi_is_vnc_configured(bgp)) {                                  \
+               case EPERM:                                                                  \
+                       vty_out(vty,                                                         \
+                               "VNC operations only permitted on default BGP instance.\n"); \
+                       return CMD_WARNING_CONFIG_FAILED;                                    \
+                       break;                                                               \
+               case ENXIO:                                                                  \
+                       vty_out(vty, "VNC not configured.\n");                               \
+                       return CMD_WARNING_CONFIG_FAILED;                                    \
+                       break;                                                               \
+               default:                                                                     \
+                       break;                                                               \
+               }                                                                            \
        }
 
 DEFUN (vnc_advertise_un_method,
@@ -509,9 +510,8 @@ DEFUN (vnc_defaults_responselifetime,
        } else {
                rspint = strtoul(argv[1]->arg, NULL, 10);
                if (rspint > INT32_MAX)
-                       rspint =
-                               INT32_MAX; /* is really an int, not an unsigned
-                                             int */
+                       rspint = INT32_MAX; /* is really an int, not an unsigned
+                                              int */
        }
 
        bgp->rfapi_cfg->default_response_lifetime = rspint;
@@ -554,7 +554,7 @@ rfapi_group_new(struct bgp *bgp, rfapi_group_cfg_type_t type, const char *name)
                /* add to tail of list */
                listnode_add(bgp->rfapi_cfg->nve_groups_sequential, rfg);
        }
-       rfg->label = MPLS_LABEL_ILLEGAL;
+       rfg->label = MPLS_LABEL_NONE;
        QOBJ_REG(rfg, rfapi_nve_group_cfg);
 
        return rfg;
@@ -1631,14 +1631,14 @@ DEFUN (vnc_nve_group_export_no_prefixlist,
                return CMD_WARNING_CONFIG_FAILED;
        }
 
-       if (argv[idx-1]->text[0] == 'z')
+       if (argv[idx - 1]->text[0] == 'z')
                is_bgp = 0;
-       idx += 2;               /* skip afi and keyword */
+       idx += 2; /* skip afi and keyword */
 
        if (is_bgp) {
-               if (idx == argc ||
-                   strmatch(argv[idx]->arg,
-                            rfg->plist_export_bgp_name[afi])) {
+               if (idx == argc
+                   || strmatch(argv[idx]->arg,
+                               rfg->plist_export_bgp_name[afi])) {
                        if (rfg->plist_export_bgp_name[afi])
                                free(rfg->plist_export_bgp_name[afi]);
                        rfg->plist_export_bgp_name[afi] = NULL;
@@ -1647,9 +1647,9 @@ DEFUN (vnc_nve_group_export_no_prefixlist,
                        vnc_direct_bgp_reexport_group_afi(bgp, rfg, afi);
                }
        } else {
-               if (idx == argc ||
-                   strmatch(argv[idx]->arg,
-                            rfg->plist_export_zebra_name[afi])) {
+               if (idx == argc
+                   || strmatch(argv[idx]->arg,
+                               rfg->plist_export_zebra_name[afi])) {
                        if (rfg->plist_export_zebra_name[afi])
                                free(rfg->plist_export_zebra_name[afi]);
                        rfg->plist_export_zebra_name[afi] = NULL;
@@ -1700,7 +1700,7 @@ DEFUN (vnc_nve_group_export_prefixlist,
                return CMD_WARNING_CONFIG_FAILED;
        }
 
-       if (argv[idx-1]->text[0] == 'z')
+       if (argv[idx - 1]->text[0] == 'z')
                is_bgp = 0;
        idx = argc - 1;
 
@@ -1758,18 +1758,19 @@ DEFUN (vnc_nve_group_export_no_routemap,
        switch (argv[idx]->text[0]) {
        case 'z':
                is_bgp = 0;
-               /* fall thru */
+       /* fall thru */
        case 'b':
                idx += 2;
                break;
-       default:                /* route-map */
+       default: /* route-map */
                idx++;
                break;
        }
 
        if (is_bgp) {
-               if (idx == argc ||
-                   strmatch(argv[idx]->arg, rfg->routemap_export_bgp_name)) {
+               if (idx == argc
+                   || strmatch(argv[idx]->arg,
+                               rfg->routemap_export_bgp_name)) {
                        if (rfg->routemap_export_bgp_name)
                                free(rfg->routemap_export_bgp_name);
                        rfg->routemap_export_bgp_name = NULL;
@@ -1779,9 +1780,9 @@ DEFUN (vnc_nve_group_export_no_routemap,
                        vnc_direct_bgp_reexport_group_afi(bgp, rfg, AFI_IP6);
                }
        } else {
-               if (idx == argc ||
-                   strmatch(argv[idx]->arg,
-                            rfg->routemap_export_zebra_name)) {
+               if (idx == argc
+                   || strmatch(argv[idx]->arg,
+                               rfg->routemap_export_zebra_name)) {
                        if (rfg->routemap_export_zebra_name)
                                free(rfg->routemap_export_zebra_name);
                        rfg->routemap_export_zebra_name = NULL;
@@ -2466,8 +2467,7 @@ bgp_rfapi_delete_named_nve_group(struct vty *vty, /* NULL = no output */
                if (rfg->rfd)
                        clear_vnc_vrf_closer(rfg);
                bgp_rfapi_delete_nve_group(vty, bgp, rfg);
-       }
-       else /* must be delete all */
+       } else /* must be delete all */
                for (ALL_LIST_ELEMENTS(bgp->rfapi_cfg->nve_groups_sequential,
                                       node, nnode, rfg)) {
                        if (rfg->rfd)
@@ -2977,6 +2977,11 @@ DEFUN_NOSH (vnc_vrf_policy,
        struct rfapi_nve_group_cfg *rfg;
        VTY_DECLVAR_CONTEXT(bgp, bgp);
 
+       if (bgp->inst_type == BGP_INSTANCE_TYPE_VRF) {
+               vty_out(vty, "Can't configure vrf-policy within a BGP VRF instance\n");
+               return CMD_WARNING_CONFIG_FAILED;
+       }
+
        /* Search for name */
        rfg = bgp_rfapi_cfg_match_byname(bgp, argv[1]->arg,
                                         RFAPI_GROUP_CFG_VRF);
@@ -3007,6 +3012,10 @@ DEFUN (vnc_no_vrf_policy,
 {
        VTY_DECLVAR_CONTEXT(bgp, bgp);
 
+       /* silently return */
+       if (bgp->inst_type == BGP_INSTANCE_TYPE_VRF)
+               return CMD_SUCCESS;
+
        return bgp_rfapi_delete_named_nve_group(vty, bgp, argv[2]->arg,
                                                RFAPI_GROUP_CFG_VRF);
 }
@@ -3063,7 +3072,7 @@ DEFUN (vnc_vrf_policy_no_label,
                vnc_redistribute_prechange(bgp);
        }
 
-       rfg->label = MPLS_LABEL_ILLEGAL;
+       rfg->label = MPLS_LABEL_NONE;
 
        if (bgp->rfapi_cfg->rfg_redist == rfg) {
                vnc_redistribute_postchange(bgp);
@@ -3950,7 +3959,9 @@ int bgp_rfapi_cfg_write(struct vty *vty, struct bgp *bgp)
                                if (rfg->plist_export_bgp_name[afi]) {
                                        vty_out(vty,
                                                "  export %s%s prefix-list %s\n",
-                                               (rfg->type == RFAPI_GROUP_CFG_VRF ? "" : "bgp "),
+                                               (rfg->type == RFAPI_GROUP_CFG_VRF
+                                                        ? ""
+                                                        : "bgp "),
                                                afistr,
                                                rfg->plist_export_bgp_name
                                                        [afi]);
@@ -3958,7 +3969,9 @@ int bgp_rfapi_cfg_write(struct vty *vty, struct bgp *bgp)
                                if (rfg->plist_export_zebra_name[afi]) {
                                        vty_out(vty,
                                                "  export %s%s prefix-list %s\n",
-                                               (rfg->type == RFAPI_GROUP_CFG_VRF ? "" : "zebra "),
+                                               (rfg->type == RFAPI_GROUP_CFG_VRF
+                                                        ? ""
+                                                        : "zebra "),
                                                afistr,
                                                rfg->plist_export_zebra_name
                                                        [afi]);
@@ -3993,12 +4006,16 @@ int bgp_rfapi_cfg_write(struct vty *vty, struct bgp *bgp)
 
                        if (rfg->routemap_export_bgp_name) {
                                vty_out(vty, "  export %sroute-map %s\n",
-                                       (rfg->type == RFAPI_GROUP_CFG_VRF ? "" : "bgp "),
+                                       (rfg->type == RFAPI_GROUP_CFG_VRF
+                                                ? ""
+                                                : "bgp "),
                                        rfg->routemap_export_bgp_name);
                        }
                        if (rfg->routemap_export_zebra_name) {
                                vty_out(vty, "  export %sroute-map %s\n",
-                                       (rfg->type == RFAPI_GROUP_CFG_VRF ? "" : "zebra "),
+                                       (rfg->type == RFAPI_GROUP_CFG_VRF
+                                                ? ""
+                                                : "zebra "),
                                        rfg->routemap_export_zebra_name);
                        }
                        if (rfg->routemap_redist_name[ZEBRA_ROUTE_BGP_DIRECT]) {
@@ -4097,7 +4114,9 @@ int bgp_rfapi_cfg_write(struct vty *vty, struct bgp *bgp)
                        }
                }
 
-               if (hc->default_rd.prefixlen || hc->default_response_lifetime
+               if (hc->default_rd.prefixlen
+                   || hc->default_response_lifetime
+                              != BGP_VNC_DEFAULT_RESPONSE_LIFETIME_DEFAULT
                    || hc->default_rt_import_list || hc->default_rt_export_list
                    || hc->nve_groups_sequential->count) {
 
@@ -4125,7 +4144,8 @@ int bgp_rfapi_cfg_write(struct vty *vty, struct bgp *bgp)
                                                              buf,
                                                              sizeof(buf)));
                        }
-                       if (hc->default_response_lifetime) {
+                       if (hc->default_response_lifetime
+                           != BGP_VNC_DEFAULT_RESPONSE_LIFETIME_DEFAULT) {
                                vty_out(vty, "  response-lifetime ");
                                if (hc->default_response_lifetime != UINT32_MAX)
                                        vty_out(vty, "%d",
@@ -4182,8 +4202,8 @@ int bgp_rfapi_cfg_write(struct vty *vty, struct bgp *bgp)
 
                                        prefix2str(&rfg->vn_prefix, buf,
                                                   sizeof(buf));
-                                       vty_out(vty, "  prefix %s %s\n",
-                                               "vn", buf);
+                                       vty_out(vty, "  prefix %s %s\n", "vn",
+                                               buf);
                                }
 
                                if (rfg->un_prefix.family && rfg->un_node) {
@@ -4191,8 +4211,8 @@ int bgp_rfapi_cfg_write(struct vty *vty, struct bgp *bgp)
 
                                        prefix2str(&rfg->un_prefix, buf,
                                                   sizeof(buf));
-                                       vty_out(vty, "  prefix %s %s\n",
-                                               "un", buf);
+                                       vty_out(vty, "  prefix %s %s\n", "un",
+                                               buf);
                                }
 
 
@@ -4213,11 +4233,10 @@ int bgp_rfapi_cfg_write(struct vty *vty, struct bgp *bgp)
                                                        value);
 
                                        } else
-                                               vty_out(vty,
-                                                       "  rd %s\n",
-                                                       prefix_rd2str(&rfg->rd,
-                                                                     buf,
-                                                                     sizeof(buf)));
+                                               vty_out(vty, "  rd %s\n",
+                                                       prefix_rd2str(
+                                                               &rfg->rd, buf,
+                                                               sizeof(buf)));
                                }
                                if (rfg->flags & RFAPI_RFG_RESPONSE_LIFETIME) {
                                        vty_out(vty, "  response-lifetime ");
index 5ba7a96a8f99a4d9fff4f984be30183f0df46e72..9d169eed32c571e1f6aaaef43df8b44270c657cd 100644 (file)
@@ -31,6 +31,7 @@
 #include "lib/linklist.h"
 #include "lib/command.h"
 #include "lib/stream.h"
+#include "lib/ringbuf.h"
 
 #include "bgpd/bgpd.h"
 #include "bgpd/bgp_ecommunity.h"
@@ -912,7 +913,7 @@ void add_vnc_route(struct rfapi_descriptor *rfd, /* cookie, VPN UN addr, peer */
         *  aspath: points to interned hash from aspath hash table
         */
 
-       red = bgp_redist_lookup(bgp, afi, type, VRF_DEFAULT);
+       red = bgp_redist_lookup(bgp, afi, type, 0);
 
        if (red && red->redist_metric_flag) {
                attr.med = red->redist_metric;
@@ -1082,7 +1083,7 @@ void add_vnc_route(struct rfapi_descriptor *rfd, /* cookie, VPN UN addr, peer */
        /* save backref to rfapi handle */
        assert(bgp_info_extra_get(new));
        new->extra->vnc.export.rfapi_handle = (void *)rfd;
-       encode_label(label_val, &new->extra->label);
+       encode_label(label_val, &new->extra->label[0]);
 
        /* debug */
 
@@ -1310,7 +1311,7 @@ static int rfapi_open_inner(struct rfapi_descriptor *rfd, struct bgp *bgp,
                        stream_fifo_free(rfd->peer->obuf);
 
                if (rfd->peer->ibuf_work)
-                       stream_free(rfd->peer->ibuf_work);
+                       ringbuf_del(rfd->peer->ibuf_work);
                if (rfd->peer->obuf_work)
                        stream_free(rfd->peer->obuf_work);
 
index 8727c5d5ea5c20a1bb1eae186387df7ffd2935af..e1508dbd83bd0e858f7d50b7bf0ccc7366b407ca 100644 (file)
@@ -521,7 +521,7 @@ static struct bgp_info *rfapiBgpInfoCreate(struct attr *attr, struct peer *peer,
                rfapi_time(&new->extra->vnc.import.create_time);
        }
        if (label)
-               encode_label(*label, &new->extra->label);
+               encode_label(*label, &new->extra->label[0]);
        new->type = type;
        new->sub_type = sub_type;
        new->peer = peer;
@@ -1338,7 +1338,7 @@ rfapiRouteInfo2NextHopEntry(struct rfapi_ip_prefix *rprefix,
                vo->v.l2addr.local_nve_id = bi->extra->vnc.import.rd.val[1];
 
                /* label comes from MP_REACH_NLRI label */
-               vo->v.l2addr.label = decode_label(&bi->extra->label);
+               vo->v.l2addr.label = decode_label(&bi->extra->label[0]);
 
                new->vn_options = vo;
 
@@ -4242,7 +4242,7 @@ static void rfapiBgpTableFilteredImport(struct bgp *bgp,
 
                                        if (bi->extra)
                                                label = decode_label(
-                                                       &bi->extra->label);
+                                                       &bi->extra->label[0]);
                                        (*rfapiBgpInfoFilteredImportFunction(
                                                safi))(
                                                it, /* which import table */
index bd79518bfd75c7caa2d4d19d39508faf8ddaed49..271c74851018c9bb34b0592e5db57f61639450cd 100644 (file)
@@ -697,7 +697,7 @@ static void rfapiRibBi2Ri(struct bgp_info *bi, struct rfapi_info *ri,
                vo->v.l2addr.local_nve_id = bi->extra->vnc.import.rd.val[1];
 
                /* label comes from MP_REACH_NLRI label */
-               vo->v.l2addr.label = decode_label(&bi->extra->label);
+               vo->v.l2addr.label = decode_label(&bi->extra->label[0]);
 
                rfapi_vn_options_free(
                        ri->vn_options); /* maybe free old version */
index 37ca5edc96dfde0b2532c584a98e0f18f1586983..28d068cc578453ed273c3a8a1cdb0b31b1f2ed1d 100644 (file)
@@ -432,7 +432,7 @@ void rfapi_vty_out_vncinfo(struct vty *vty, struct prefix *p,
        }
 
        if (bi->extra != NULL)
-               vty_out(vty, " label=%u", decode_label(&bi->extra->label));
+               vty_out(vty, " label=%u", decode_label(&bi->extra->label[0]));
 
        if (!rfapiGetVncLifetime(bi->attr, &lifetime)) {
                vty_out(vty, " life=%d", lifetime);
@@ -494,7 +494,7 @@ void rfapiPrintBi(void *stream, struct bgp_info *bi)
        char *p = line;
        int r;
        int has_macaddr = 0;
-       struct ethaddr macaddr;
+       struct ethaddr macaddr = {{0}};
        struct rfapi_l2address_option l2o_buf;
        uint8_t l2hid = 0; /* valid if has_macaddr */
 
@@ -1068,7 +1068,7 @@ static int rfapiPrintRemoteRegBi(struct bgp *bgp, void *stream,
                         inet_ntop(pfx_vn.family, &pfx_vn.u.prefix, buf_ntop,
                                   BUFSIZ));
                if (bi->extra) {
-                       u_int32_t l = decode_label(&bi->extra->label);
+                       u_int32_t l = decode_label(&bi->extra->label[0]);
                        snprintf(buf_vn, BUFSIZ, "Label: %d", l);
                } else /* should never happen */
                {
@@ -1181,7 +1181,7 @@ static int rfapiPrintRemoteRegBi(struct bgp *bgp, void *stream,
                }
        }
        if (tun_type != BGP_ENCAP_TYPE_MPLS && bi->extra) {
-               u_int32_t l = decode_label(&bi->extra->label);
+               u_int32_t l = decode_label(&bi->extra->label[0]);
                if (!MPLS_LABEL_IS_NULL(l)) {
                        fp(out, "  Label: %d", l);
                        if (nlines == 1)
index d4921ce40a80ec6d49c05a81313a1c664544bc83..e88dd9399c565b01d6711e5c9222827b51fd89de 100644 (file)
@@ -317,7 +317,7 @@ void vnc_direct_bgp_add_route_ce(struct bgp *bgp, struct route_node *rn,
                   iattr,          /* bgp_update copies this attr */
                   afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT,
                   BGP_ROUTE_REDISTRIBUTE, NULL, /* RD not used for unicast */
-                  NULL,                         /* tag not used for unicast */
+                  NULL, 0,                      /* tag not used for unicast */
                   0, NULL);                     /* EVPN not used */
        bgp_attr_unintern(&iattr);
 }
@@ -398,7 +398,7 @@ void vnc_direct_bgp_del_route_ce(struct bgp *bgp, struct route_node *rn,
                     NULL,                /* attr, ignored */
                     afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT,
                     BGP_ROUTE_REDISTRIBUTE, NULL, /* RD not used for unicast */
-                    NULL, NULL); /* tag not used for unicast */
+                    NULL, 0, NULL); /* tag not used for unicast */
 }
 
 static void vnc_direct_bgp_vpn_enable_ce(struct bgp *bgp, afi_t afi)
@@ -498,7 +498,7 @@ static void vnc_direct_bgp_vpn_disable_ce(struct bgp *bgp, afi_t afi)
                                        ZEBRA_ROUTE_VNC_DIRECT,
                                        BGP_ROUTE_REDISTRIBUTE,
                                        NULL, /* RD not used for unicast */
-                                       NULL,
+                                       NULL, 0,
                                        NULL); /* tag not used for unicast */
                        }
                }
@@ -880,7 +880,7 @@ void vnc_direct_bgp_del_prefix(struct bgp *bgp,
                                     afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT,
                                     BGP_ROUTE_REDISTRIBUTE,
                                     NULL,      /* RD not used for unicast */
-                                    NULL, NULL); /* tag not used for unicast */
+                                    NULL, 0, NULL); /* tag not used for unicast */
                        /*
                         * yuck!
                         *  - but consistent with rest of function
@@ -909,7 +909,7 @@ void vnc_direct_bgp_del_prefix(struct bgp *bgp,
                                     afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT,
                                     BGP_ROUTE_REDISTRIBUTE,
                                     NULL,      /* RD not used for unicast */
-                                    NULL, NULL); /* tag not used for unicast */
+                                    NULL, 0, NULL); /* tag not used for unicast */
                }
        }
 }
@@ -1048,7 +1048,7 @@ void vnc_direct_bgp_add_nve(struct bgp *bgp, struct rfapi_descriptor *rfd)
                                                                unicast */
                                                   NULL,     /* tag not used for
                                                                unicast */
-                                                  0, NULL); /* EVPN not used */
+                                                  0, 0, NULL); /* EVPN not used */
 
                                        bgp_attr_unintern(&iattr);
                                }
@@ -1142,7 +1142,7 @@ void vnc_direct_bgp_del_nve(struct bgp *bgp, struct rfapi_descriptor *rfd)
                                                     BGP_ROUTE_REDISTRIBUTE,
                                                     NULL, /* RD not used for
                                                              unicast */
-                                                    NULL, NULL); /* tag not
+                                                    NULL, 0, NULL); /* tag not
                                                                     used for
                                                                     unicast */
                                }
@@ -1260,7 +1260,7 @@ static void vnc_direct_add_rn_group_rd(struct bgp *bgp,
                   BGP_ROUTE_REDISTRIBUTE,
                   NULL, /* RD not used for unicast */
                   NULL, /* tag not used for unicast */
-                  0, NULL); /* EVPN not used */
+                  0, 0, NULL); /* EVPN not used */
 
        bgp_attr_unintern(&iattr);
 
@@ -1374,7 +1374,7 @@ static void vnc_direct_del_rn_group_rd(struct bgp *bgp,
                     ZEBRA_ROUTE_VNC_DIRECT,
                     BGP_ROUTE_REDISTRIBUTE,
                     NULL, /* RD not used for unicast */
-                    NULL,
+                    NULL, 0,
                     NULL); /* tag not used for unicast */
        return;
 }
@@ -1496,7 +1496,7 @@ static void vnc_direct_bgp_unexport_table(afi_t afi, struct route_table *rt,
                                                     BGP_ROUTE_REDISTRIBUTE,
                                                     NULL, /* RD not used for
                                                              unicast */
-                                                    NULL, NULL); /* tag not
+                                                    NULL, 0, NULL); /* tag not
                                                                     used for
                                                                     unicast,
                                                                     EVPN
@@ -1719,7 +1719,7 @@ void vnc_direct_bgp_rh_add_route(struct bgp *bgp, afi_t afi,
                   afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT_RH,
                   BGP_ROUTE_REDISTRIBUTE, NULL, /* RD not used for unicast */
                   NULL,     /* tag not used for unicast, EVPN neither */
-                  0, NULL); /* EVPN not used */
+                  0, 0, NULL); /* EVPN not used */
        bgp_attr_unintern(&iattr);
 }
 
@@ -1734,7 +1734,7 @@ static int vncExportWithdrawTimer(struct thread *t)
                     NULL,                        /* attr, ignored */
                     family2afi(eti->node->p.family), SAFI_UNICAST, eti->type,
                     eti->subtype, NULL, /* RD not used for unicast */
-                    NULL, NULL); /* tag not used for unicast, EVPN neither */
+                    NULL, 0, NULL); /* tag not used for unicast, EVPN neither */
 
        /*
         * Free the eti
@@ -1965,7 +1965,7 @@ void vnc_direct_bgp_rh_vpn_enable(struct bgp *bgp, afi_t afi)
                                                   NULL,     /* tag not used for
                                                                unicast, EVPN
                                                                neither */
-                                                  0, NULL); /* EVPN not used */
+                                                  0, 0, NULL); /* EVPN not used */
                                        bgp_attr_unintern(&iattr);
                                }
                        }
@@ -2026,7 +2026,7 @@ void vnc_direct_bgp_rh_vpn_disable(struct bgp *bgp, afi_t afi)
                                             ZEBRA_ROUTE_VNC_DIRECT_RH,
                                             BGP_ROUTE_REDISTRIBUTE,
                                             NULL, /* RD not used for unicast */
-                                            NULL, NULL); /* tag not used for
+                                            NULL, 0, NULL); /* tag not used for
                                                             unicast, EVPN
                                                             neither */
                        }
index f7e86123b4f3422a5e4f372b9e9d30a6c2240c94..cfa4c599f2a1a44c4470fe163d9ae30c11949b7c 100644 (file)
@@ -495,7 +495,7 @@ static void vnc_import_bgp_add_route_mode_resolve_nve_one_bi(
                ecommunity_merge(new_ecom, bi->attr->ecommunity);
 
        if (bi->extra)
-               label = decode_label(&bi->extra->label);
+               label = decode_label(&bi->extra->label[0]);
 
        add_vnc_route(&vncHDResolveNve, bgp, SAFI_MPLS_VPN,
                      prefix,     /* unicast route prefix */
@@ -1783,7 +1783,7 @@ static void vnc_import_bgp_exterior_add_route_it(
                                        prd = &bi_interior->extra->vnc.import
                                                       .rd;
                                        label = decode_label(
-                                               &bi_interior->extra->label);
+                                               &bi_interior->extra->label[0]);
                                } else
                                        prd = NULL;
 
@@ -1958,7 +1958,7 @@ void vnc_import_bgp_exterior_del_route(
                                        prd = &bi_interior->extra->vnc.import
                                                       .rd;
                                        label = decode_label(
-                                               &bi_interior->extra->label);
+                                               &bi_interior->extra->label[0]);
                                } else
                                        prd = NULL;
 
@@ -2113,7 +2113,7 @@ void vnc_import_bgp_exterior_add_route_interior(
                        if (bi_interior->extra) {
                                prd = &bi_interior->extra->vnc.import.rd;
                                label = decode_label(
-                                       &bi_interior->extra->label);
+                                       &bi_interior->extra->label[0]);
                        } else
                                prd = NULL;
 
@@ -2226,7 +2226,7 @@ void vnc_import_bgp_exterior_add_route_interior(
                                        if (bi->extra) {
                                                prd = &bi->extra->vnc.import.rd;
                                                label = decode_label(
-                                                       &bi->extra->label);
+                                                       &bi->extra->label[0]);
                                        } else
                                                prd = NULL;
 
@@ -2248,7 +2248,7 @@ void vnc_import_bgp_exterior_add_route_interior(
                                        prd = &bi_interior->extra->vnc.import
                                                       .rd;
                                        label = decode_label(
-                                               &bi_interior->extra->label);
+                                               &bi_interior->extra->label[0]);
                                } else
                                        prd = NULL;
 
@@ -2369,7 +2369,7 @@ void vnc_import_bgp_exterior_add_route_interior(
                        if (bi_interior->extra) {
                                prd = &bi_interior->extra->vnc.import.rd;
                                label = decode_label(
-                                       &bi_interior->extra->label);
+                                       &bi_interior->extra->label[0]);
                        } else
                                prd = NULL;
 
@@ -2480,7 +2480,7 @@ void vnc_import_bgp_exterior_del_route_interior(
 
                if (bi_interior->extra) {
                        prd = &bi_interior->extra->vnc.import.rd;
-                       label = decode_label(&bi_interior->extra->label);
+                       label = decode_label(&bi_interior->extra->label[0]);
                } else
                        prd = NULL;
 
@@ -2556,7 +2556,8 @@ void vnc_import_bgp_exterior_del_route_interior(
 
                                if (bi->extra) {
                                        prd = &bi->extra->vnc.import.rd;
-                                       label = decode_label(&bi->extra->label);
+                                       label = decode_label(
+                                                       &bi->extra->label[0]);
                                } else
                                        prd = NULL;
 
index 07be7833b689b29d948a164add1205c27b4d38b2..6afcd21a102d60775cc0d9a14c0069d67d95da61 100644 (file)
@@ -30,6 +30,7 @@
 #include "lib/command.h"
 #include "lib/zclient.h"
 #include "lib/stream.h"
+#include "lib/ringbuf.h"
 #include "lib/memory.h"
 
 #include "bgpd/bgpd.h"
@@ -198,7 +199,7 @@ static void vnc_redistribute_add(struct prefix *p, u_int32_t metric,
                                        stream_fifo_free(vncHD1VR.peer->obuf);
 
                                if (vncHD1VR.peer->ibuf_work)
-                                       stream_free(vncHD1VR.peer->ibuf_work);
+                                       ringbuf_del(vncHD1VR.peer->ibuf_work);
                                if (vncHD1VR.peer->obuf_work)
                                        stream_free(vncHD1VR.peer->obuf_work);
 
@@ -384,6 +385,8 @@ static void vnc_zebra_route_msg(struct prefix *p, unsigned int nhp_count,
        struct zapi_route api;
        struct zapi_nexthop *api_nh;
        int i;
+       struct in_addr **nhp_ary4 = nhp_ary;
+       struct in6_addr **nhp_ary6 = nhp_ary;
 
        if (!nhp_count) {
                vnc_zlog_debug_verbose("%s: empty nexthop list, skipping",
@@ -401,20 +404,17 @@ static void vnc_zebra_route_msg(struct prefix *p, unsigned int nhp_count,
        SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP);
        api.nexthop_num = MIN(nhp_count, multipath_num);
        for (i = 0; i < api.nexthop_num; i++) {
-               struct in_addr *nhp_ary4;
-               struct in6_addr *nhp_ary6;
 
                api_nh = &api.nexthops[i];
+               api_nh->vrf_id = VRF_DEFAULT;
                switch (p->family) {
                case AF_INET:
-                       nhp_ary4 = nhp_ary;
-                       memcpy(&api_nh->gate.ipv4, &nhp_ary4[i],
+                       memcpy(&api_nh->gate.ipv4, nhp_ary4[i],
                               sizeof(api_nh->gate.ipv4));
                        api_nh->type = NEXTHOP_TYPE_IPV4;
                        break;
                case AF_INET6:
-                       nhp_ary6 = nhp_ary;
-                       memcpy(&api_nh->gate.ipv6, &nhp_ary6[i],
+                       memcpy(&api_nh->gate.ipv6, nhp_ary6[i],
                               sizeof(api_nh->gate.ipv6));
                        api_nh->type = NEXTHOP_TYPE_IPV6;
                        break;
index 911de537ecbaf9b608a03e5eb8559f2a2586097a..0d6c99acfa64b8f2f61b3310a81b4acb765fcf4e 100755 (executable)
@@ -7,7 +7,7 @@
 ##
 AC_PREREQ(2.60)
 
-AC_INIT(frr, 3.1-dev, [https://github.com/frrouting/frr/issues])
+AC_INIT(frr, 4.1-dev, [https://github.com/frrouting/frr/issues])
 PACKAGE_URL="https://frrouting.org/"
 AC_SUBST(PACKAGE_URL)
 PACKAGE_FULLNAME="FRRouting"
@@ -354,6 +354,8 @@ AC_ARG_ENABLE(logfile_mask,
   AS_HELP_STRING([--enable-logfile-mask=ARG], [set mask for log files]))
 AC_ARG_ENABLE(shell_access,
   AS_HELP_STRING([--enable-shell-access], [Allow users to access shell/telnet/ssh]))
+AC_ARG_ENABLE(realms,
+  AS_HELP_STRING([--enable-realms], [enable REALMS support under Linux]))
 AC_ARG_ENABLE(rtadv,
   AS_HELP_STRING([--disable-rtadv], [disable IPV6 router advertisement feature]))
 AC_ARG_ENABLE(irdp,
@@ -879,6 +881,7 @@ case "$host_os" in
 
     AC_DEFINE(OPEN_BSD,,OpenBSD)
     AC_DEFINE(KAME,1,KAME IPv6)
+    AC_DEFINE(BSD_V6_SYSCTL,1,BSD v6 sysctl to turn on and off forwarding)
 
     if test "x${enable_pimd}" != "xno"; then
       case "$host_os" in
@@ -895,12 +898,29 @@ case "$host_os" in
 
     AC_DEFINE(HAVE_NET_RT_IFLIST,,NET_RT_IFLIST)
     AC_DEFINE(KAME,1,KAME IPv6)
+    AC_DEFINE(BSD_V6_SYSCTL,1,BSD v6 sysctl to turn on and off forwarding)
     ;;
 esac
 AM_CONDITIONAL(SOLARIS, test "${SOLARIS}" = "solaris")
 
 AC_SYS_LARGEFILE
 
+dnl ------------------------
+dnl Integrated REALMS option
+dnl ------------------------
+if test "${enable_realms}" = "yes"; then
+    case "$host_os" in
+      linux*)
+       AC_DEFINE(SUPPORT_REALMS,, Realms support)
+       ;;
+      *)
+       echo "Sorry, only Linux has REALMS support"
+       exit 1
+       ;;
+    esac
+fi
+AM_CONDITIONAL([SUPPORT_REALMS], [test "${enable_realms}" = "yes"])
+
 dnl ---------------------
 dnl Integrated VTY option
 dnl ---------------------
@@ -1866,6 +1886,7 @@ AC_CONFIG_FILES([Makefile
          doc/eigrpd.8
          doc/ripngd.8
          doc/pimd.8
+         doc/mtracebis.8
          doc/nhrpd.8
          doc/vtysh.1
          doc/watchfrr.8
diff --git a/debianpkg/.gitignore b/debianpkg/.gitignore
new file mode 100644 (file)
index 0000000..6d10dce
--- /dev/null
@@ -0,0 +1 @@
+changelog
index 0d02bc3dc29ab62f225c6e14a95eef4f1f09b12b..889e83174416fe3100f43742d91e64da8ac38b37 100644 (file)
@@ -72,7 +72,7 @@ adding a new backport.
     (see `rules` file for available options)
 
         export WANT_BGP_VNC=1
-       export WANT_WANT_CUMULUS_MODE=1
+        export WANT_CUMULUS_MODE=1
         debuild -b -uc -us
 
 DONE.
index 17ceeb038148bc070886a902426cd7287a0d4dfc..9bae348840e3ff16762550fe07f03225885811a8 100644 (file)
@@ -13,7 +13,7 @@ Package: frr
 Architecture: any
 Depends: ${shlibs:Depends}, logrotate (>= 3.2-11), ${misc:Depends}
 Pre-Depends: adduser
-Conflicts: zebra, zebra-pj
+Conflicts: zebra, zebra-pj, quagga
 Replaces: zebra, zebra-pj
 Suggests: snmpd
 Description: BGP/OSPF/RIP/RIPng/ISIS/PIM/LDP routing daemon forked from Quagga
index 5c3e1363ce66f85c02e1ae7f80f53648cfac9bf6..2e9e84faa6006270c1d4d03bdb57450eea8d68ff 100755 (executable)
@@ -6,23 +6,27 @@
 #    WANT_xxxx   --> Set to 1 for enable, 0 for disable
 # The following are the defaults. They can be overridden by setting a 
 # env variable to a different value
-#
-#   export WANT_LDP=1
-#   export WANT_PIM=1
-#   export WANT_OSPFAPI=1
-#   export WANT_TCP_ZEBRA=0
-#   export WANT_BGP_VNC=0
-#   export WANT_CUMULUS_MODE=0
-#   export WANT_MULTIPATH=1
-#
+
+WANT_LDP ?= 1
+WANT_PIM ?= 1
+WANT_OSPFAPI ?= 1
+WANT_TCP_ZEBRA ?= 0
+WANT_BGP_VNC ?= 1
+WANT_CUMULUS_MODE ?= 0
+WANT_MULTIPATH ?= 1
+WANT_SNMP ?= 0
+
 # If multipath is enabled (WANT_MULTIPATH=1), then set number of multipaths here
 # Please be aware that 0 is NOT disabled, but treated as unlimited
-#   export MULTIPATH=256
-#
-# Set the following to the value required (or leave undefined for the default below)
+
+MULTIPATH ?= 256
+
+# Set the following to the value required (or leave alone for the default below)
 # WANT_FRR_USER is used for the username and groupname of the FRR user account
-#   export WANT_FRR_USER=frr
-#   export WANT_FRR_VTY_GROUP=frrvty
+
+WANT_FRR_USER ?= frr
+WANT_FRR_VTY_GROUP ?= frrvty
+
 #
 ####################################
 
@@ -34,22 +38,23 @@ ifeq ($(WANT_SNMP), 1)
   USE_SNMP=--enable-snmp
   $(warning "DEBIAN: SNMP enabled, sorry for your inconvenience")
 else
+  USE_SNMP=--disable-snmp
   $(warning "DEBIAN: SNMP disabled, see README.Debian")
 endif
 
-ifneq ($(WANT_LDP), 0)
+ifeq ($(WANT_LDP), 1)
   USE_LDP=--enable-ldpd
 else
   USE_LDP=--disable-ldpd
 endif
 
-ifneq ($(WANT_PIM), 0)
+ifeq ($(WANT_PIM), 1)
   USE_PIM=--enable-pimd
 else
   USE_PIM=--disable-pimd
 endif
 
-ifneq ($(WANT_OSPFAPI), 0)
+ifeq ($(WANT_OSPFAPI), 1)
   USE_OSPFAPI=--enable-ospfapi=yes
 else
   USE_OSPFAPI=--enable-ospfapi=no
@@ -57,39 +62,27 @@ endif
 
 ifeq ($(WANT_TCP_ZEBRA),1)
   USE_TCP_ZEBRA=--enable-tcp-zebra
+else
+  USE_TCP_ZEBRA=--disable-tcp-zebra
 endif
 
-ifneq ($(WANT_BGP_VNC), 0)
+ifeq ($(WANT_BGP_VNC), 1)
   USE_BGP_VNC=--enable-bgp-vnc=yes
 else
   USE_BGP_VNC=--enable-bgp-vnc=no
 endif
 
-ifndef WANT_FRR_USER
-  USE_FRR_USER=--enable-user=frr
-  USE_FRR_GROUP=--enable-group=frr
-else
-  USE_FRR_USER=$(WANT_FRR_USER)
-  USE_FRR_GROUP=$(WANT_FRR_USER)
-endif
-
-ifndef WANT_FRR_VTY_GROUP
-  USE_FRR_VTY_GROUP=--enable-vty-group=frrvty
-else
-  USE_FRR_VTY_GROUP=--enable-vty-group=$(WANT_FRR_VTY_GROUP)
-endif
+USE_FRR_USER=--enable-user=$(WANT_FRR_USER)
+USE_FRR_GROUP=--enable-group=$(WANT_FRR_USER)
+USE_FRR_VTY_GROUP=--enable-vty-group=$(WANT_FRR_VTY_GROUP)
 
-ifneq ($(WANT_MULTIPATH), 0)
-  ifdef MULTIPATH
-    USE_MULTIPATH=--enable-multipath=$(MULTIPATH)
-  else
-    USE_MULTIPATH=--enable-multipath=256
-  endif
+ifeq ($(WANT_MULTIPATH), 1)
+  USE_MULTIPATH=--enable-multipath=$(MULTIPATH)
 else
   USE_MULTIPATH=--disable-multipath
 endif
 
-ifeq ($(WANT_CUMULUS_NODE), 1)
+ifeq ($(WANT_CUMULUS_MODE), 1)
   USE_CUMULUS=--enable-cumulus=yes
 else
   USE_CUMULUS=--enable-cumulus=no
@@ -171,9 +164,12 @@ override_dh_auto_install:
        perl -pi -e 's#^!log file #!log file /var/log/frr/#' debian/tmp/usr/share/doc/frr/examples/*sample*
 
        # installing the Frr specific SNMP MIB
+ifeq ($(WANT_SNMP), 1)
        install -D -m 644 ./zebra/GNOME-PRODUCT-ZEBRA-MIB debian/tmp/usr/share/snmp/mibs/GNOME-PRODUCT-ZEBRA-MIB
+else
+       mkdir -p debian/tmp/usr/share/snmp/mibs
+endif
 
        # cleaning .la files
        sed -i "/dependency_libs/ s/'.*'/''/" debian/tmp/usr/lib/*.la
        sed -i "/dependency_libs/ s/'.*'/''/" debian/tmp/usr/lib/frr/modules/*.la
-
index c22bd3bd58469d3fb4f68b3c2a23dbd2ea313cc1..3f31f18462fdbabf916e58e473e0bd3ce9553d5a 100644 (file)
@@ -13,7 +13,7 @@ Package: frr
 Architecture: any
 Depends: ${shlibs:Depends}, logrotate (>= 3.2-11), ${misc:Depends}
 Pre-Depends: adduser
-Conflicts: zebra, zebra-pj
+Conflicts: zebra, zebra-pj, quagga
 Replaces: zebra, zebra-pj
 Suggests: snmpd
 Description: BGP/OSPF/RIP/RIPng/ISIS/PIM/LDP routing daemon forked from Quagga
index adce915e1f075d7083f7c51a8669184efd25c7f1..8e83bdf6df8a644c455b15517232df87699e24b7 100644 (file)
@@ -1,5 +1,6 @@
 etc/frr/
 usr/bin/vtysh
+usr/bin/mtracebis
 usr/include/frr/
 usr/lib/
 tools/frr etc/init.d/
@@ -15,6 +16,7 @@ usr/share/man/man8/ripngd.8
 usr/share/man/man8/zebra.8
 usr/share/man/man8/isisd.8
 usr/share/man/man8/watchfrr.8
+usr/share/man/man8/mtracebis.8
 usr/share/snmp/mibs/
 tools/etc/* etc/
 tools/*.service    lib/systemd/system
index b1f539def69b611f749810032a718035cd342cfb..4f82d772c900810c28eae44226748edbe80cb56a 100755 (executable)
@@ -6,23 +6,27 @@
 #    WANT_xxxx   --> Set to 1 for enable, 0 for disable
 # The following are the defaults. They can be overridden by setting a 
 # env variable to a different value
-#
-#   export WANT_LDP=1
-#   export WANT_PIM=1
-#   export WANT_OSPFAPI=1
-#   export WANT_TCP_ZEBRA=0
-#   export WANT_BGP_VNC=0
-#   export WANT_CUMULUS_MODE=0
-#   export WANT_MULTIPATH=1
-#
+
+WANT_LDP ?= 1
+WANT_PIM ?= 1
+WANT_OSPFAPI ?= 1
+WANT_TCP_ZEBRA ?= 0
+WANT_BGP_VNC ?= 1
+WANT_CUMULUS_MODE ?= 0
+WANT_MULTIPATH ?= 1
+WANT_SNMP ?= 0
+
 # If multipath is enabled (WANT_MULTIPATH=1), then set number of multipaths here
 # Please be aware that 0 is NOT disabled, but treated as unlimited
-#   export MULTIPATH=256
-#
-# Set the following to the value required (or leave undefined for the default below)
+
+MULTIPATH ?= 256
+
+# Set the following to the value required (or leave alone for the default below)
 # WANT_FRR_USER is used for the username and groupname of the FRR user account
-#   export WANT_FRR_USER=frr
-#   export WANT_FRR_VTY_GROUP=frrvty
+
+WANT_FRR_USER ?= frr
+WANT_FRR_VTY_GROUP ?= frrvty
+
 #
 ####################################
 
@@ -34,22 +38,23 @@ ifeq ($(WANT_SNMP), 1)
   USE_SNMP=--enable-snmp
   $(warning "DEBIAN: SNMP enabled, sorry for your inconvenience")
 else
+  USE_SNMP=--disable-snmp
   $(warning "DEBIAN: SNMP disabled, see README.Debian")
 endif
 
-ifneq ($(WANT_LDP), 0)
+ifeq ($(WANT_LDP), 1)
   USE_LDP=--enable-ldpd
 else
   USE_LDP=--disable-ldpd
 endif
 
-ifneq ($(WANT_PIM), 0)
+ifeq ($(WANT_PIM), 1)
   USE_PIM=--enable-pimd
 else
   USE_PIM=--disable-pimd
 endif
 
-ifneq ($(WANT_OSPFAPI), 0)
+ifeq ($(WANT_OSPFAPI), 1)
   USE_OSPFAPI=--enable-ospfapi=yes
 else
   USE_OSPFAPI=--enable-ospfapi=no
@@ -57,39 +62,27 @@ endif
 
 ifeq ($(WANT_TCP_ZEBRA),1)
   USE_TCP_ZEBRA=--enable-tcp-zebra
+else
+  USE_TCP_ZEBRA=--disable-tcp-zebra
 endif
 
-ifneq ($(WANT_BGP_VNC), 0)
+ifeq ($(WANT_BGP_VNC), 1)
   USE_BGP_VNC=--enable-bgp-vnc=yes
 else
   USE_BGP_VNC=--enable-bgp-vnc=no
 endif
 
-ifndef WANT_FRR_USER
-  USE_FRR_USER=--enable-user=frr
-  USE_FRR_GROUP=--enable-group=frr
-else
-  USE_FRR_USER=$(WANT_FRR_USER)
-  USE_FRR_GROUP=$(WANT_FRR_USER)
-endif
+USE_FRR_USER=--enable-user=$(WANT_FRR_USER)
+USE_FRR_GROUP=--enable-group=$(WANT_FRR_USER)
+USE_FRR_VTY_GROUP=--enable-vty-group=$(WANT_FRR_VTY_GROUP)
 
-ifndef WANT_FRR_VTY_GROUP
-  USE_FRR_VTY_GROUP=--enable-vty-group=frrvty
-else
-  USE_FRR_VTY_GROUP=--enable-vty-group=$(WANT_FRR_VTY_GROUP)
-endif
-
-ifneq ($(WANT_MULTIPATH), 0)
-  ifdef MULTIPATH
-    USE_MULTIPATH=--enable-multipath=$(MULTIPATH)
-  else
-    USE_MULTIPATH=--enable-multipath=256
-  endif
+ifeq ($(WANT_MULTIPATH), 1)
+  USE_MULTIPATH=--enable-multipath=$(MULTIPATH)
 else
   USE_MULTIPATH=--disable-multipath
 endif
 
-ifeq ($(WANT_CUMULUS_NODE), 1)
+ifeq ($(WANT_CUMULUS_MODE), 1)
   USE_CUMULUS=--enable-cumulus=yes
 else
   USE_CUMULUS=--enable-cumulus=no
@@ -171,7 +164,11 @@ override_dh_auto_install:
        perl -pi -e 's#^!log file #!log file /var/log/frr/#' debian/tmp/usr/share/doc/frr/examples/*sample*
 
        # installing the Frr specific SNMP MIB
+ifeq ($(WANT_SNMP), 1)
        install -D -m 644 ./zebra/GNOME-PRODUCT-ZEBRA-MIB debian/tmp/usr/share/snmp/mibs/GNOME-PRODUCT-ZEBRA-MIB
+else
+       mkdir -p debian/tmp/usr/share/snmp/mibs/
+endif
 
        # cleaning .la files
        sed -i "/dependency_libs/ s/'.*'/''/" debian/tmp/usr/lib/*.la
index 2d86009dba8a1b47354a1c91ed8c51ee2ea2db23..1aee4d540e8868b7f41cd86f203fae61efc63089 100644 (file)
@@ -1,5 +1,6 @@
 etc/frr/
 usr/bin/vtysh
+usr/bin/mtracebis
 usr/include/frr/
 usr/lib/
 tools/frr usr/lib/frr
@@ -16,6 +17,7 @@ usr/share/man/man8/zebra.8
 usr/share/man/man8/isisd.8
 usr/share/man/man8/watchfrr.8
 usr/share/man/man8/frr-args.8
+usr/share/man/man8/mtracebis.8
 usr/share/snmp/mibs/
 tools/etc/* etc/
 tools/*.service    lib/systemd/system
index a6a9077da181cafa2568b0c82beab6c725bb6650..574f448dffe997e434c8f5e097a59bb64a86dc45 100755 (executable)
@@ -6,23 +6,27 @@
 #    WANT_xxxx   --> Set to 1 for enable, 0 for disable
 # The following are the defaults. They can be overridden by setting a 
 # env variable to a different value
-#
-#   export WANT_LDP=1
-#   export WANT_PIM=1
-#   export WANT_OSPFAPI=1
-#   export WANT_TCP_ZEBRA=0
-#   export WANT_BGP_VNC=0
-#   export WANT_CUMULUS_MODE=0
-#   export WANT_MULTIPATH=1
-#
+
+WANT_LDP ?= 1
+WANT_PIM ?= 1
+WANT_OSPFAPI ?= 1
+WANT_TCP_ZEBRA ?= 0
+WANT_BGP_VNC ?= 1
+WANT_CUMULUS_MODE ?= 0
+WANT_MULTIPATH ?= 1
+WANT_SNMP ?= 0
+
 # If multipath is enabled (WANT_MULTIPATH=1), then set number of multipaths here
 # Please be aware that 0 is NOT disabled, but treated as unlimited
-#   export MULTIPATH=256
-#
-# Set the following to the value required (or leave undefined for the default below)
+
+MULTIPATH ?= 256
+
+# Set the following to the value required (or leave alone for the default below)
 # WANT_FRR_USER is used for the username and groupname of the FRR user account
-#   export WANT_FRR_USER=frr
-#   export WANT_FRR_VTY_GROUP=frrvty
+
+WANT_FRR_USER ?= frr
+WANT_FRR_VTY_GROUP ?= frrvty
+
 #
 ####################################
 
@@ -34,22 +38,23 @@ ifeq ($(WANT_SNMP), 1)
   USE_SNMP=--enable-snmp
   $(warning "DEBIAN: SNMP enabled, sorry for your inconvenience")
 else
+  USE_SNMP=--disable-snmp
   $(warning "DEBIAN: SNMP disabled, see README.Debian")
 endif
 
-ifneq ($(WANT_LDP), 0)
+ifeq ($(WANT_LDP), 1)
   USE_LDP=--enable-ldpd
 else
   USE_LDP=--disable-ldpd
 endif
 
-ifneq ($(WANT_PIM), 0)
+ifeq ($(WANT_PIM), 1)
   USE_PIM=--enable-pimd
 else
   USE_PIM=--disable-pimd
 endif
 
-ifneq ($(WANT_OSPFAPI), 0)
+ifeq ($(WANT_OSPFAPI), 1)
   USE_OSPFAPI=--enable-ospfapi=yes
 else
   USE_OSPFAPI=--enable-ospfapi=no
@@ -57,39 +62,27 @@ endif
 
 ifeq ($(WANT_TCP_ZEBRA),1)
   USE_TCP_ZEBRA=--enable-tcp-zebra
+else
+  USE_TCP_ZEBRA=--disable-tcp-zebra
 endif
 
-ifneq ($(WANT_BGP_VNC), 0)
+ifeq ($(WANT_BGP_VNC), 1)
   USE_BGP_VNC=--enable-bgp-vnc=yes
 else
   USE_BGP_VNC=--enable-bgp-vnc=no
 endif
 
-ifndef WANT_FRR_USER
-  USE_FRR_USER=--enable-user=frr
-  USE_FRR_GROUP=--enable-group=frr
-else
-  USE_FRR_USER=$(WANT_FRR_USER)
-  USE_FRR_GROUP=$(WANT_FRR_USER)
-endif
-
-ifndef WANT_FRR_VTY_GROUP
-  USE_FRR_VTY_GROUP=--enable-vty-group=frrvty
-else
-  USE_FRR_VTY_GROUP=--enable-vty-group=$(WANT_FRR_VTY_GROUP)
-endif
+USE_FRR_USER=--enable-user=$(WANT_FRR_USER)
+USE_FRR_GROUP=--enable-group=$(WANT_FRR_USER)
+USE_FRR_VTY_GROUP=--enable-vty-group=$(WANT_FRR_VTY_GROUP)
 
-ifneq ($(WANT_MULTIPATH), 0)
-  ifdef MULTIPATH
-    USE_MULTIPATH=--enable-multipath=$(MULTIPATH)
-  else
-    USE_MULTIPATH=--enable-multipath=256
-  endif
+ifeq ($(WANT_MULTIPATH), 1)
+  USE_MULTIPATH=--enable-multipath=$(MULTIPATH)
 else
   USE_MULTIPATH=--disable-multipath
 endif
 
-ifeq ($(WANT_CUMULUS_NODE), 1)
+ifeq ($(WANT_CUMULUS_MODE), 1)
   USE_CUMULUS=--enable-cumulus=yes
 else
   USE_CUMULUS=--enable-cumulus=no
index 1536c25932760fdc886701087d316892847602bc..e2d424a3eac44c0c85c7c3a91d8b61f2699d9dfd 100644 (file)
@@ -20,7 +20,7 @@ any packages**
 
     sudo addgroup --system --gid 92 frr
     sudo addgroup --system --gid 85 frrvty
-    sudo adduser --system --ingroup frr --home /var/run/frr/ \
+    sudo adduser --system --ingroup frr --home /var/opt/frr/ \
        --gecos "FRR suite" --shell /bin/false frr
     sudo usermod -a -G frrvty frr
 
@@ -34,7 +34,7 @@ an example.)
     ./bootstrap.sh
     ./configure \
         --enable-exampledir=/usr/share/doc/frr/examples/ \
-        --localstatedir=/var/run/frr \
+        --localstatedir=/var/opt/frr \
         --sbindir=/usr/lib/frr \
         --sysconfdir=/etc/frr \
         --enable-vtysh \
@@ -61,6 +61,7 @@ an example.)
 ### Create empty FRR configuration files
 
     sudo install -m 755 -o frr -g frr -d /var/log/frr
+    sudo install -m 755 -o frr -g frr -d /var/opt/frr
     sudo install -m 775 -o frr -g frrvty -d /etc/frr
     sudo install -m 640 -o frr -g frr /dev/null /etc/frr/zebra.conf
     sudo install -m 640 -o frr -g frr /dev/null /etc/frr/bgpd.conf
@@ -91,20 +92,6 @@ other settings)
 
 ### Troubleshooting
 
-**Local state directory**
-
-The local state directory must exist and have the correct permissions applied
-for the frrouting daemons to start.  In the above ./configure example the
-local state directory is set to /var/run/frr (--localstatedir=/var/run/frr)
-Debian considers /var/run/frr to be temporary and this is removed after a
-reboot.
-
-When using a different local state directory you need to create the new
-directory and change the ownership to the frr user, for example:
-
-    mkdir /var/opt/frr
-    chown frr /var/opt/frr
-
 **Shared library error**
 
 If you try and start any of the frrouting daemons you may see the below error
index 6c80ddeaa4a67febea3acfa0883283867a22e0f6..9c81202db9e7938500a0fcabf6d5888fb48c4516 100644 (file)
@@ -59,17 +59,37 @@ $(srcdir)/frr.info: $(frr_TEXINFOS) defines.texi
 frr.dvi: $(frr_TEXINFOS) defines.texi
 frr.html: $(frr_TEXINFOS) defines.texi
 
-frr_TEXINFOS = appendix.texi basic.texi bgpd.texi isisd.texi filter.texi \
+frr_TEXINFOS = \
+       appendix.texi \
+       basic.texi \
+       bgpd.texi \
+       isisd.texi \
+       filter.texi \
        vnc.texi \
        babeld.texi \
-       install.texi ipv6.texi kernel.texi main.texi \
+       install.texi \
+       ipv6.texi  \
+       kernel.texi \
+       main.texi \
        nhrpd.texi \
        eigrpd.texi \
-       ospf6d.texi ospfd.texi \
-       overview.texi protocol.texi ripd.texi ripngd.texi routemap.texi \
-       snmp.texi vtysh.texi routeserver.texi $(figures_png) \
-       snmptrap.texi ospf_fundamentals.texi isisd.texi $(figures_txt) \
-       rpki.texi
+       ospf6d.texi \
+       ospfd.texi \
+       overview.texi \
+       protocol.texi \
+       ripd.texi \
+       ripngd.texi \
+       routemap.texi \
+       snmp.texi \
+       vtysh.texi \
+       routeserver.texi \
+       $(figures_png) \
+       snmptrap.texi \
+       ospf_fundamentals.texi \
+       isisd.texi $(figures_txt) \
+       rpki.texi \
+       pimd.texi \
+       #END
 
 .png.eps:
        $(PNGTOEPS) $< "$@"
@@ -84,6 +104,7 @@ man_MANS = frr.1 frr-args.8
 
 if PIMD
 man_MANS += pimd.8
+man_MANS += mtracebis.8
 endif
 
 if BGPD
@@ -149,6 +170,7 @@ EXTRA_DIST = BGP-TypeCode draft-zebra-00.ms draft-zebra-00.txt \
        ripd.8.in \
        ripngd.8.in \
        pimd.8.in \
+       mtracebis.8.in \
        nhrpd.8.in \
        vtysh.1.in \
        watchfrr.8.in \
diff --git a/doc/OSPF-SR.rst b/doc/OSPF-SR.rst
new file mode 100644 (file)
index 0000000..0ee1a12
--- /dev/null
@@ -0,0 +1,269 @@
+OSPF Segment Routing
+====================
+
+This is an EXPERIMENTAL support of draft
+`draft-ietf-ospf-segment-routing-extensions-24`.
+DON'T use it for production network.
+
+Implementation details
+----------------------
+
+Concepts
+~~~~~~~~
+
+Segment Routing used 3 differents OPAQUE LSA in OSPF to carry the various
+information:
+
+* **Router Information:** flood the Segment Routing capabilities of the node.
+  This include the supported algorithms, the Segment Routing Global Block
+  (SRGB) and the Maximum Stack Depth (MSD).
+* **Extended Link:** flood the Adjaceny and Lan Adjacency Segment Identifier
+* **Extended Prefix:** flood the Prefix Segment Identifier
+
+The implementation follow previous TE and Router Information codes. It used the
+OPAQUE LSA functions defined in ospf_opaque.[c,h] as well as the OSPF API. This
+latter is mandatory for the implementation as it provides the Callback to
+Segment Routing functions (see below) when an Extended Link / Prefix or Router
+Information LSA s are received.
+
+Overview
+~~~~~~~~
+
+Following files where modified or added:
+
+* ospd_ri.[c,h] have been modified to add the new TLVs for Segment Routing.
+* ospf_ext.[c,h] implement RFC7684 as base support of Extended Link and Prefix
+  Opaque LSA.
+* ospf_sr.[c,h] implement the earth of Segment Routing. It adds a new Segment
+  Routing database to manage Segment Identifiers per Link and Prefix and
+  Segment Routing enable node, Callback functions to process incoming LSA and
+  install MPLS FIB entry through Zebra.
+
+The figure below shows the relation between the various files:
+
+* ospf_sr.c centralized all the Segment Routing processing. It receives Opaque
+  LSA Router Information (4.0.0.0) from ospf_ri.c and Extended Prefix
+  (7.0.0.X) Link (8.0.0.X) from ospf_ext.c. Once received, it parse TLVs and
+  SubTLVs and store information in SRDB (which is defined in ospf_sr.h). For
+  each received LSA, NHLFE is computed and send to Zebra to add/remove new
+  MPLS labels entries and FEC. New CLI configurations are also centralized in
+  ospf_sr.c. This CLI will trigger the flooding of new LSA Router Information
+  (4.0.0.0), Extended Prefix (7.0.0.X) and Link (8.0.0.X) by ospf_ri.c,
+  respectively ospf_ext.c.
+* ospf_ri.c send back to ospf_sr.c received Router Information LSA and update
+  Self Router Information LSA with paramters provided by ospf_sr.c i.e. SRGB
+  and MSD. It use ospf_opaque.c functions to send/received these Opaque LSAs.
+* ospf_ext.c send back to ospf_sr.c received Extended Prefix and Link Opaque
+  LSA and send self Extended Prefix and Link Opaque LSA through ospf_opaque.c
+  functions.
+
+::
+
+                    +-----------+     +-------+
+                    |           |     |       |
+                    | ospf_sr.c +-----+  SRDB |
+        +-----------+           +--+  |       |
+        |           +-^-------^-+  |  +-------+
+        |             |   |   |    |
+        |             |   |   |    |
+        |             |   |   |    +--------+
+        |             |   |   |             |
+    +---v----------+  |   |   |       +-----v-------+
+    |              |  |   |   |       |             |
+    | ospf_ri.c    +--+   |   +-------+ ospf_ext.c  |
+    | LSA 4.0.0.0  |      |           | LSA 7.0.0.X |
+    |              |      |           | LSA 8.0.0.X |
+    +---^----------+      |           |             |
+        |                 |           +-----^-------+
+        |                 |                 |
+        |                 |                 |
+        |        +--------v------------+    |
+        |        |                     |    |
+        |        | ZEBRA: Labels + FEC |    |
+        |        |                     |    |
+        |        +---------------------+    |
+        |                                   |
+        |                                   |
+        |         +---------------+         |
+        |         |               |         |
+        +---------> ospf_opaque.c <---------+
+                  |               |
+                  +---------------+
+
+      Figure 1: Overview of Segment Routing interaction
+
+Module interactions
+~~~~~~~~~~~~~~~~~~~
+
+To process incoming LSA, the code is based on the capability to call `hook()`
+functions when LSA are inserted or delete to / from the LSDB and the
+possibility to register particular treatment for Opaque LSA. The first point
+is provided by the OSPF API feature and the second by the Opaque implementation
+itself. Indeed, it is possible to register callback function for a given Opaque
+LSA ID (see `ospf_register_opaque_functab()` function defined in
+`ospf_opaque.c`). Each time a new LSA is added to the LSDB, the
+`new_lsa_hook()` function previously register for this LSA type is called. For
+Opaque LSA it is the `ospf_opaque_lsa_install_hook()`.  For deletion, it is
+`ospf_opaque_lsa_delete_hook()`.
+
+Note that incoming LSA which is already present in the LSDB will be inserted
+after the old instance of this LSA remove from the LSDB. Thus, after the first
+time, each incoming LSA will trigger a `delete` following by an `install`. This
+is not very helpfull to handle real LSA deletion. In fact, LSA deletion is done
+by Flushing LSA i.e. flood LSA after seting its age to MAX_AGE. Then, a garbage
+function has the role to remove all LSA with `age == MAX_AGE` in the LSDB. So,
+to handle LSA Flush, the best is to look to the LSA age to determine if it is
+an installation or a future deletion i.e. the flushed LSA is first store in the
+LSDB with MAX_AGE waiting for the garbage collector function.
+
+Router Information LSAs
+^^^^^^^^^^^^^^^^^^^^^^^
+
+To activate Segment Routing, new CLI command `segment-routing on` has been
+introduced. When this command is activated, function
+`ospf_router_info_update_sr()` is called to indicate to Router Information
+process that Segment Routing TLVs must be flood. Same function is called to
+modify the Segment Routing Global Block (SRGB) and Maximum Stack Depth (MSD)
+TLV. Only Shortest Path First (SPF) Algorithm is supported, so no possiblity
+to modify this TLV is offer by the code.
+
+When Opaque LSA Tyep 4 i.e. Router Information are stored in LSDB, function
+`ospf_opaque_lsa_install_hook()` will call the previously registered function
+`ospf_router_info_lsa_update()`. In turn, the function will simply trigger
+`ospf_sr_ri_lsa_update()` or `ospf_sr_ri_lsa_delete` in function of the LSA
+age. Before, it verifies that the LSA Opaque Type is 4 (Router Information).
+Self Opaque LSA are not send back to the Segment Routing functions as
+information are already stored.
+
+Extended Link Prefix LSAs
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Like for Router Information, Segment Routing is activate at the Extended
+Link/Prefix level with new `segment-routing on` command. This trigger
+automtically the flooding of Extended Link LSA for all ospf interface where
+adjacency is full. For Extended Prefix LSA, the new CLI command
+`segment-routing prefix ...` will trigger the flooding of Prefix SID
+TLV/SubTLVs.
+
+When Opaque LSA Type 7 i.e. Extended Prefix and Type 8 i.e. Extended Link are
+store in the LSDB, `ospf_ext_pref_update_lsa()` respectively
+`ospf_ext_link_update_lsa()` are called like for Router Information LSA. In
+turn, they respectively trigger `ospf_sr_ext_prefix_lsa_update()` /
+`ospf_sr_ext_link_lsa_update()` or `ospf_sr_ext_prefix_lsa_delete()` /
+`ospf_sr_ext_link_lsa_delete()` if the LSA age is equal to MAX_AGE.
+
+Zebra
+^^^^^
+
+When a new MPLS entry or new Forwarding Equivalent Class (FEC) must be added or
+deleted in the data plane, `add_sid_nhlfe()` respectively `del_sid_nhlfe()` are
+called. Once check the validity of labels, they are send to ZEBRA layer through
+`ZEBRA_MPLS_LABELS_ADD` command, respectively `ZEBRA_MPLS_LABELS_DELETE`
+command for deletion. This is completed by a new labelled route through
+`ZEBRA_ROUTE_ADD` command, respectively `ZEBRA_ROUTE_DELETE` command.
+
+Configuration
+-------------
+
+Linux Kernel
+~~~~~~~~~~~~
+
+In order to use OSPF Segment Routing, you must setup MPLS data plane. Up to
+know, only Linux Kernel version >= 4.5 is supported.
+
+First, the MPLS modules aren't loaded by default, so you'll need to load them
+yourself:
+
+::
+
+       modprobe mpls_router
+       modprobe mpls_gso
+       modprobe mpls_iptunnel
+
+Then, you must activate MPLS on the interface you would used:
+
+::
+
+       sysctl -w net.mpls.conf.enp0s9.input=1
+       sysctl -w net.mpls.conf.lo.input=1
+       sysctl -w net.mpls.platform_labels=1048575
+
+The last line fix the maximum MPLS label value.
+
+Once OSPFd start with Segment Routing, you could check that MPLS routes are
+enable with:
+
+::
+
+       ip -M route
+       ip route
+
+The first command show the MPLS LFIB table while the second show the FIB
+table which contains route with MPLS label encapsulation.
+
+If you disable Penultimate Hop Popping with the `no-php-flag` (see below), you
+MUST check that RP filter is not enable for the interface you intend to use,
+especially the `lo` one. For that purpose, disable RP filtering with:
+
+::
+
+       systcl -w net.ipv4.conf.all.rp_filter=0
+       sysctl -w net.ipv4.conf.lo.rp_filter=0
+
+OSPFd
+~~~~~
+
+Here it is a simple example of configuration to enable Segment Routing. Note
+that `opaque capability` and `router information` must be set to activate
+Opaque LSA prior to Segment
+Routing.
+
+::
+
+       router ospf
+        ospf router-id 192.168.1.11
+        capability opaque
+         mpls-te on
+         mpls-te router-address 192.168.1.11
+        router-info area 0.0.0.0
+        segment-routing on
+        segment-routing global-block 10000 19999
+        segment-routing node-msd 8
+        segment-routing prefix 192.168.1.11/32 index 1100
+
+The first segment-routing statement enable it. The Second one set the SRGB,
+third line the MSD and finally, set the Prefix SID index for a given prefix.
+Note that only prefix of Loopback interface could be configured with a Prefix
+SID. It is possible to add `no-php-flag` at the end of the prefix command to
+disbale Penultimate Hop Popping. This advertises peers that they MUST NOT pop
+the MPLS label prior to sending the packet.
+
+Known limitations
+-----------------
+
+* Runs only within default VRF
+* Only single Area is supported. ABR is not yet supported
+* Only SPF algorithm is supported
+* Extended Prefix Range is not supported
+* MPLS table are not flush at startup. Thus, restarting zebra process is
+  mandatory to remove old MPLS entries in the data plane after a crash of
+  ospfd daemon
+* Due to a bug in OSPF Opaque, LSA are not flood when enable Segment Routing
+  through CLI once OSPFd started. You must configure Segment Routing within
+  configuration file before launching OSPFd
+* With NO Penultimate Hop Popping, it is not possible to express a Segment
+  Path with an Adjacency SID due to the impossibility for the Linux Kernel to
+  perform double POP instruction.
+
+Credits
+-------
+
+* Author: Anselme Sawadogo <anselmesawadogo@gmail.com>
+* Author: Olivier Dugeon <olivier.dugeon@orange.com>
+* Copyright (C) 2016 - 2018 Orange Labs http://www.orange.com
+
+This work has been performed in the framework of the H2020-ICT-2014
+project 5GEx (Grant Agreement no. 671636), which is partially funded
+by the European Commission.
+
+
index d62c3a7516128a4610d109b5327c53050e53751e..83483f569739af7676816663c10dfc4d59ed420c 100644 (file)
@@ -823,22 +823,15 @@ Network Layer protocols. BGP supports multiple Address Family
 Identifier (AFI), namely IPv4 and IPv6. Support is also provided for
 multiple sets of per-AFI information via Subsequent Address Family
 Identifiers (SAFI).  In addition to unicast information, VPN information
-@cite{RFC4364} and @cite{RFC4659}, and Encapsulation information
+@cite{RFC4364} and @cite{RFC4659}, and Encapsulation attribute
 @cite{RFC5512} is supported.
 
-@deffn {Command} {show ip bgp vpnv4 all} {}
-@deffnx {Command} {show ipv6 bgp vpn all} {}
+@deffn {Command} {show ip bgp ipv4 vpn} {}
+@deffnx {Command} {show ipv6 bgp ipv6 vpn} {}
 Print active IPV4 or IPV6 routes advertised via the VPN SAFI.
 @end deffn
 
-@deffn {Command} {show ip bgp encap all} {}
-@deffnx {Command} {show ipv6 bgp encap all} {}
-Print active IPV4 or IPV6 routes advertised via the Encapsulation SAFI.
-@end deffn
-
-@deffn {Command} {show bgp ipv4 encap summary} {}
-@deffnx {Command} {show bgp ipv4 vpn summary} {}
-@deffnx {Command} {show bgp ipv6 encap summary} {}
+@deffn {Command} {show bgp ipv4 vpn summary} {}
 @deffnx {Command} {show bgp ipv6 vpn summary} {}
 Print a summary of neighbor connections for the specified AFI/SAFI combination.
 @end deffn
index 19d9614420f8788377855898eeaf5445fe5028b7..d0d56804b059ffb54dc92c9c553ff83a29c907fe 100644 (file)
@@ -85,6 +85,10 @@ Enable Traffic Engineering Extension for ISIS (RFC5305)
 @item --enable-multipath=@var{ARG}
 Enable support for Equal Cost Multipath. @var{ARG} is the maximum number
 of ECMP paths to allow, set to 0 to allow unlimited number of paths.
+@item --enable-realms
+Enable the support of linux Realms.  Convert tag values from 1-255
+into a realm value when inserting into the linux kernel.  Then
+routing policy can be assigned to the realm.  See the tc man page.
 @item --disable-rtadv
 Disable support IPV6 router advertisement in zebra.
 @item --enable-gcc-rdynamic
index bbc2896755e9d0b13b5de05e7830c6c24b03f131..404698d8053d6a0a429e276f89770d0386cf3f1b 100644 (file)
@@ -373,36 +373,37 @@ log file /var/log/zebra.log
 !
 interface eth0
  ip address 10.2.2.2/24
- mpls-te on
- mpls-te link metric 10
- mpls-te link max-bw 1.25e+06
- mpls-te link max-rsv-bw 1.25e+06
- mpls-te link unrsv-bw 0 1.25e+06
- mpls-te link unrsv-bw 1 1.25e+06
- mpls-te link unrsv-bw 2 1.25e+06
- mpls-te link unrsv-bw 3 1.25e+06
- mpls-te link unrsv-bw 4 1.25e+06
- mpls-te link unrsv-bw 5 1.25e+06
- mpls-te link unrsv-bw 6 1.25e+06
- mpls-te link unrsv-bw 7 1.25e+06
- mpls-te link rsc-clsclr 0xab
+ link-params
+  enable
+  metric 100
+  max-bw 1.25e+07
+  max-rsv-bw 1.25e+06
+  unrsv-bw 0 1.25e+06
+  unrsv-bw 1 1.25e+06
+  unrsv-bw 2 1.25e+06
+  unrsv-bw 3 1.25e+06
+  unrsv-bw 4 1.25e+06
+  unrsv-bw 5 1.25e+06
+  unrsv-bw 6 1.25e+06
+  unrsv-bw 7 1.25e+06
+  admin-grp 0xab
 !
 interface eth1
  ip address 10.1.1.1/24
- mpls-te on
- mpls-te link metric 10
- mpls-te link max-bw 1.25e+06
- mpls-te link max-rsv-bw 1.25e+06
mpls-te link unrsv-bw 0 1.25e+06
mpls-te link unrsv-bw 1 1.25e+06
mpls-te link unrsv-bw 2 1.25e+06
mpls-te link unrsv-bw 3 1.25e+06
mpls-te link unrsv-bw 4 1.25e+06
mpls-te link unrsv-bw 5 1.25e+06
mpls-te link unrsv-bw 6 1.25e+06
mpls-te link unrsv-bw 7 1.25e+06
- mpls-te link rsc-clsclr 0xab
mpls-te neighbor 10.1.1.2 as 65000
+ link-params
+  enable
+  metric 100
+  max-bw 1.25e+07
 max-rsv-bw 1.25e+06
 unrsv-bw 0 1.25e+06
 unrsv-bw 1 1.25e+06
 unrsv-bw 2 1.25e+06
 unrsv-bw 3 1.25e+06
 unrsv-bw 4 1.25e+06
 unrsv-bw 5 1.25e+06
 unrsv-bw 6 1.25e+06
+  unrsv-bw 7 1.25e+06
+  neighbor 10.1.1.2 as 65000
 @end group
 @end example
 
diff --git a/doc/mtracebis.8.in b/doc/mtracebis.8.in
new file mode 100644 (file)
index 0000000..3abc717
--- /dev/null
@@ -0,0 +1,25 @@
+.\" This file was originally generated by help2man 1.44.1.
+.TH MTRACEBIS "8" "February 2018" "mtracebis 0.1" "System Administration Utilities"
+.SH NAME
+mtracebis \- a program to initiate multicast traceroute "mtrace" queries
+.SH SYNOPSIS
+mtracebis
+<multicast source>
+.SH DESCRIPTION
+.B mtracebis
+is a program used to test multicast connectivity in a multicast and multicast
+traceroute enabled IP network.
+.PP
+Initial version of the program requires multicast source IP address and
+initiates a weak traceroute across the network. This tests whether the
+interfaces towards the source are multicast enabled. First query sent is a
+full query, capable of crossing the network all the way to the source. If this
+fails, hop-by-hop queries are initiated.
+.PP
+Hop-by-hop queries start by requesting only a response from the nearest router.
+Following that, next query is extended to the next two routers, and so on...
+until a set of routers is tested for connectivity.
+.SH SEE ALSO
+See the project homepage at <@PACKAGE_URL@>.
+.SH AUTHORS
+Copyright 2018 Mladen Sablic
index cc33211510378103ea51473b8510ea47cdd68311..33341d2be6de6a8e3a010d578bc7657548ec7297 100644 (file)
@@ -22,6 +22,7 @@ networks.
 * Opaque LSA::
 * OSPF Traffic Engineering::
 * Router Information::
+* Segment Routing::
 * Debugging OSPF::              
 * OSPF Configuration Examples::
 @end menu
@@ -724,6 +725,46 @@ Show Router Capabilities flag.
 Show Router Capabilities PCE parameters.
 @end deffn
 
+@node Segment Routing
+@section Segment Routing
+
+This is an EXPERIMENTAL support of Segment Routing as per draft
+ draft-ietf-ospf-segment-routing-extensions-24.txt for MPLS dataplane.
+
+@deffn {OSPF Command} {segment-routing on} {}
+@deffnx {OSPF Command} {no segment-routing} {}
+Enable Segment Routing. Even if this also activate routing information support,
+it is preferable to also activate routing information, and set accordingly the
+Area or AS flooding.
+@end deffn
+
+@deffn {OSPF Command} {segment-routing global-block (0-1048575) (0-1048575)} {}
+@deffnx {OSPF Command} {no segment-routing global-block} {}
+Fix the Segment Routing Global Block i.e. the label range used by MPLS to store
+label in the MPLS FIB.
+@end deffn
+
+@deffn {OSPF Command} {segment-routing node-msd (1-16)} {}
+@deffnx {OSPF Command} {no segment-routing node-msd} {}
+Fix the Maximum Stack Depth supported by the router. The value depend of the
+MPLS dataplane. E.g. for Linux kernel, since version 4.13 it is 32.
+@end deffn
+
+@deffn {OSPF Command} {segment-routing prefix A.B.C.D/M index (0-65535)} {}
+@deffnx {OSPF Command} {segment-routing prefix A.B.C.D/M index (0-65535) no-php-flag} {}
+@deffnx {OSPF Command} {no segment-routing prefix A.B.C.D/M} {}
+Set the Segment Rounting index for the specifyed prefix. Note
+that, only prefix with /32 corresponding to a loopback interface are
+currently supported. The 'no-php-flag' means NO Penultimate Hop Popping that
+allows SR node to request to its neighbor to not pop the label.
+@end deffn
+
+@deffn {Command} {show ip ospf database segment-routing} {}
+@deffnx {Command} {show ip ospf database segment-routing adv-router @var{adv-router}} {}
+@deffnx {Command} {show ip ospf database segment-routing self-originate} {}
+Show Segment Routing Data Base, all SR nodes, specific advertized router or self router.
+@end deffn
+
 @node Debugging OSPF
 @section Debugging OSPF
 
@@ -843,36 +884,37 @@ log file /var/log/zebra.log
 !
 interface eth0
  ip address 198.168.1.1/24
- mpls-te on
- mpls-te link metric 10
- mpls-te link max-bw 1.25e+06
- mpls-te link max-rsv-bw 1.25e+06
- mpls-te link unrsv-bw 0 1.25e+06
- mpls-te link unrsv-bw 1 1.25e+06
- mpls-te link unrsv-bw 2 1.25e+06
- mpls-te link unrsv-bw 3 1.25e+06
- mpls-te link unrsv-bw 4 1.25e+06
- mpls-te link unrsv-bw 5 1.25e+06
- mpls-te link unrsv-bw 6 1.25e+06
- mpls-te link unrsv-bw 7 1.25e+06
- mpls-te link rsc-clsclr 0xab
+ link-params
+  enable
+  admin-grp 0xa1
+  metric 100
+  max-bw 1.25e+07
+  max-rsv-bw 1.25e+06
+  unrsv-bw 0 1.25e+06
+  unrsv-bw 1 1.25e+06
+  unrsv-bw 2 1.25e+06
+  unrsv-bw 3 1.25e+06
+  unrsv-bw 4 1.25e+06
+  unrsv-bw 5 1.25e+06
+  unrsv-bw 6 1.25e+06
+  unrsv-bw 7 1.25e+06
 !
 interface eth1
  ip address 192.168.2.1/24
- mpls-te on
- mpls-te link metric 10
- mpls-te link max-bw 1.25e+06
- mpls-te link max-rsv-bw 1.25e+06
mpls-te link unrsv-bw 0 1.25e+06
mpls-te link unrsv-bw 1 1.25e+06
mpls-te link unrsv-bw 2 1.25e+06
mpls-te link unrsv-bw 3 1.25e+06
mpls-te link unrsv-bw 4 1.25e+06
mpls-te link unrsv-bw 5 1.25e+06
mpls-te link unrsv-bw 6 1.25e+06
mpls-te link unrsv-bw 7 1.25e+06
- mpls-te link rsc-clsclr 0xab
mpls-te neighbor 192.168.2.2 as 65000
+ link-params
+  enable
+  metric 10
+  max-bw 1.25e+07
 max-rsv-bw 1.25e+06
 unrsv-bw 0 1.25e+06
 unrsv-bw 1 1.25e+06
 unrsv-bw 2 1.25e+06
 unrsv-bw 3 1.25e+06
 unrsv-bw 4 1.25e+06
 unrsv-bw 5 1.25e+06
 unrsv-bw 6 1.25e+06
+  unrsv-bw 7 1.25e+06
+  neighbor 192.168.2.2 as 65000
 @end group
 @end example
 
diff --git a/doc/pimd.texi b/doc/pimd.texi
new file mode 100644 (file)
index 0000000..30e85af
--- /dev/null
@@ -0,0 +1,366 @@
+@c -*-texinfo-*-
+@c This is part of the Frr Manual.
+@c @value{COPYRIGHT_STR}
+@c See file frr.texi for copying conditions.
+@node PIM
+@chapter PIM
+
+PIM -- Protocol Independent Multicast
+
+@command{pimd} supports pim-sm as well as igmp v2 and v3.  pim is
+vrf aware and can work within the context of vrf's in order to
+do S,G mrouting.
+
+@menu
+* Starting and Stopping pimd::
+* PIM Configuration::
+* PIM Interface Configuration::
+* PIM Multicast RIB insertion::
+* Show PIM Information::
+* PIM Debug Commands::
+@end menu
+
+@node Starting and Stopping pimd
+@section Starting and Stopping pimd
+
+The default configuration file name of @command{pimd}'s is
+@file{pimd.conf}.  When invocation @command{pimd} searches directory
+@value{INSTALL_PREFIX_ETC}.  If @file{pimd.conf} is not there
+then next search current directory.
+
+@command{pimd} requires zebra for proper operation.  Additionally
+@command{pimd} depends on routing properly setup and working
+in the network that it is working on.
+
+@example
+@group
+# zebra -d
+# pimd -d
+@end group
+@end example
+
+Please note that @command{zebra} must be invoked before @command{pimd}.
+
+To stop @command{pimd}.  Please use @command{kill `cat
+/var/run/pimd.pid`}.  Certain signals have special meanings to @command{pimd}.
+
+@table @samp
+@item SIGUSR1
+Rotate @command{pimd} logfile.
+@item SIGINT
+@itemx SIGTERM
+@command{pimd} sweeps all installed PIM mroutes then terminates properly.
+@end table
+
+@command{pimd} invocation options.  Common options that can be specified
+(@pxref{Common Invocation Options}).
+
+@node PIM Configuration
+
+@deffn Command {ip pim rp A.B.C.D A.B.C.D/M} {}
+In order to use pim, it is necessary to configure a RP for join
+messages to be sent to.  Currently the only methodology to
+do this is via static rp commands.  All routers in the
+pim network must agree on these values.  The first ip address
+is the RP's address and the second value is the matching
+prefix of group ranges covered.  This command is vrf aware,
+to configure for a vrf, enter the vrf submode.
+@end deffn
+
+@deffn Command {ip pim spt-switchover infinity-and-beyond} {}
+On the last hop router if it is desired to not switch over
+to the SPT tree. Configure this command.  This command is
+vrf aware, to configure for a vrf, enter the vrf submode.
+#end deffn
+
+@deffn Comand {ip pim ecmp} {}
+If pim has the a choice of ECMP nexthops for a particular
+RPF, pim will cause S,G flows to be spread out amongst
+the nexthops.  If this command is not specified then
+the first nexthop found will be used.  This command
+is vrf aware, to configure for a vrf, enter the vrf submode.
+@end deffn
+
+@deffn Command {ip pim ecmp rebalance} {}
+If pim is using ECMP and an interface goes down, cause
+pim to rebalance all S,G flows aross the remaining
+nexthops.  If this command is not configured pim only
+modifies those S,G flows that were using the interface
+that went down.  This command is vrf aware, to configure
+for a vrf, enter the vrf submode.
+@end deffn
+
+@deffn Command {ip pim join-prune-interval (60-600)} {}
+Modify the join/prune interval that pim uses to the
+new value.  Time is specified in seconds.  This command
+is vrf aware, to configure for a vrf, enter the vrf submode.
+@end deffn
+
+@deffn Command {ip pim keep-alive-timer (31-60000)} {}
+Modify the time out value for a S,G flow from 31-60000
+seconds.  31 seconds is choosen for a lower bound
+because some hardware platforms cannot see data flowing
+in better than 30 second chunks.  This comand is vrf
+aware, to configure for a vrf, enter the vrf submode.
+@end deffn
+
+@deffn Command {ip pim packets (1-100)} {}
+When processing packets from a neighbor process the
+number of packets incoming at one time before moving
+on to the next task.  The default value is 3 packets.
+This command is only useful at scale when you can
+possibly have a large number of pim control packets
+flowing.  This command is vrf aware, to configure for
+a vrf, enter the vrf submode.
+@end deffn
+
+@deffn Command {ip pim register-suppress-time (5-60000)} {}
+Modify the time that pim will register suppress a FHR
+will send register notifications to the kernel.  This command
+is vrf aware, to configure for a vrf, enter the vrf submode.
+@end deffn
+
+@deffn Command {ip pim send-v6-secondary} {}
+When sending pim hello packets tell pim to send
+any v6 secondary addresses on the interface.  This
+information is used to allow pim to use v6 nexthops
+in it's decision for RPF lookup.  This command
+is vrf aware, to configure for a vrf, enter the vrf submode.
+@end deffn
+
+@deffn Command {ip pim ssm prefix-list WORD} {}
+Specify a range of group addresses via a prefix-list
+that forces pim to never do SM over.  This command
+is vrf aware, to configure for a vrf, enter the vrf submode.
+@end deffn
+
+@deffn Command {ip multicast rpf-lookup-mode WORD} {}
+Modify how PIM does RPF lookups in the zebra routing table.
+You can use these choices:
+@table @lookup_modes
+@item longer-prefix
+Lookup the RPF in both tables using the longer prefix as a match
+@item lower-distance
+Lookup the RPF in both tables using the lower distance as a match
+@item mrib-only
+Lookup in the Multicast RIB only
+@item mrib-then-urib
+Lookup in the Multicast RIB then the Unicast Rib, returning first found.
+This is the default value for lookup if this command is not entered
+@item urib-only
+Lookup in the Unicast Rib only.
+@end table
+@end deffn
+
+@node PIM Interface Configuration
+@section PIM Interface Configuration
+
+PIM interface commands allow you to configure an
+interface as either a Receiver or a interface
+that you would like to form pim neighbors on.  If the
+interface is in a vrf, enter the interface command with
+the vrf keyword at the end.
+
+@deffn {PIM Interface Command] {ip pim bfd} {}
+Turns on BFD support for PIM for this interface.
+@end deffn
+
+@deffn {PIM Interface Command} {ip pim drpriority (1-4294967295)} {}
+Set the DR Priority for the interface.  This command is useful
+to allow the user to influence what node becomes the DR for a
+lan segment.
+@end deffn
+
+@deffn {PIM Interface Command} {ip pim hello (1-180) (1-180)} {}
+Set the pim hello and hold interval for a interface.
+@end deffn
+
+@deffn {PIM Interface Command} {ip pim sm} {}
+Tell pim that we would like to use this interface to form
+pim neighbors over.  Please note we will *not* accept
+igmp reports over this interface with this command.
+@end deffn
+
+@deffn {PIM Interface Command} {ip igmp} {}
+Tell pim to receive IGMP reports and Query on this
+interface.  The default version is v3.  This command
+is useful on the LHR.
+@end deffn
+
+@deffn {PIM Interface Command} {ip igmp query-interval (1-1800)} {}
+Set the IGMP query interval that PIM will use.
+@end deffn
+
+@deffn {PIM Interface Command} {ip igmp query-max-response-time (10-250)} {}
+Set the IGMP query response timeout value.  If an report is not returned
+in the specified time we will assume the S,G or *,G has timed out.
+@end deffn
+
+@deffn {PIM Interface Command} {ip igmp version (2-3)} {}
+Set the IGMP version used on this interface.  The default value
+is 3.
+@end deffn
+
+@deffn {PIM Interface Command} {ip multicat boundary oil WORD} {}
+Set a pim multicast boundary, based upon the WORD prefix-list.  If
+a pim join or IGMP report is received on this interface and the Group
+is denyed by the prefix-list, PIM will ignore the join or report.
+@end deffn
+
+@node PIM Multicast RIB insertion::
+@section PIM Multicast RIB insertion::
+
+In order to influence Multicast RPF lookup, it is possible to insert
+into zebra routes for the Multicast RIB.  These routes are only
+used for RPF lookup and will not be used by zebra for insertion
+into the kernel *or* for normal rib processing.  As such it is
+possible to create weird states with these commands.  Use with
+caution.  Most of the time this will not be necessary.
+
+@deffn {PIM Multicast RIB insertion} {ip mroute A.B.C.D/M A.B.C.D (1-255)} {}
+Insert into the Multicast Rib Route A.B.C.D/M with specified nexthop.  The distance can be specified as well if desired.
+@end deffn
+
+@deffn {PIM Multicast RIB insertion} {ip mroute A.B.C.D/M INTERFACE (1-255)} {}
+Insert into the Multicast Rib Route A.B.C.D/M using the specified INTERFACE.
+The distance can be specified as well if desired.
+@end deffn
+
+@node Show PIM Information::
+@section Show PIM Information
+
+All PIM show commands are vrf aware and typically allow you to insert
+a specified vrf command if information is desired about a specific vrf.
+If no vrf is specified then the default vrf is assumed.  Finally
+the special keyword 'all' allows you to look at all vrfs for the command.
+Naming a vrf 'all' will cause great confusion.
+
+@deffn {Show PIM Information} {show ip multicast}
+Display various information about the interfaces used in this pim
+instance.
+@end deffn
+
+@deffn {Show PIM Information} {show ip mroute}
+Display information about installed into the kernel S,G mroutes.
+@end deffn
+
+@deffn {Show PIM Information} {show ip mroute count}
+Display information about installed into the kernel S,G mroutes
+and in addition display data about packet flow for the mroutes.
+@end deffn
+
+@deffn {Show PIM Information} {show ip pim assert}
+Display information about asserts in the PIM system for S,G mroutes.
+@end deffn
+
+@deffn {Show PIM Information} {show ip pim assert-internal}
+Display internal assert state for S,G mroutes
+@end deffn
+
+@deffn {Show PIM Information} {show ip pim assert-metric}
+Display metric information about assert state for S,G mroutes
+@end deffn
+
+@deffn {Show PIM Information} {show ip pim assert-winner-metric}
+Display winner metric for assert state for S,G mroutes
+@end deffn
+
+@deffn {Show PIM Information} {show ip pim group-type}
+Display SSM group ranges
+@end deffn
+
+@deffn {Show PIM Information} {show ip pim interface}
+Display information about interfaces PIM is using.
+@end deffn
+
+@deffn {Show PIM Information} {show ip pim join}
+Display information about PIM joins received.
+@end deffn
+
+@deffn {Show PIM Information} {show ip pim local-membership} {}
+Display information about PIM interface local-membership
+@end deffn
+
+@deffn {Show PIM Information} {show ip pim neighbor} {}
+Display information about PIM neighbors
+@end deffn
+
+@deffn {Show PIM Information} {show ip pim nexthop} {}
+Display information about pim nexthops that are being
+used
+@end deffn
+
+@deffn {Show PIM Information} {show ip pim nexthop-lookup} {}
+Display information about a S,G pair and how the RPF would
+be choosen.  This is especially useful if there are ECMP's
+available from the RPF lookup.
+@end deffn
+
+@deffn {Show PIM Information} {show ip pim rp-info} {}
+Display information about RP's that are configured on
+this router
+@end deffn
+
+@deffn {Show PIM Information} {show ip pim rpf} {}
+Display information about currently being used S,G's
+and their RPF lookup information.  Additionally display
+some statistics about what has been happening on the
+router
+@end deffn
+
+@deffn {show PIM Information} {show ip pim secondary} {}
+Display information about an interface and all the
+secondary addresses associated with it
+@end deffn
+
+@deffn {show PIM Information} {show ip pim state} {}
+Display information about known S,G's and incoming
+interface as well as the OIL and how they were choosen
+@end deffn
+
+@deffn {show PIM Information} {show ip pim upstream} {}
+Display upstream information about a S,G mroute
+@end deffn
+
+@deffn {show PIM Information} {show ip pim upstream-join-desired} {}
+Display upstream information for S,G's and if we desire to
+join the mcast tree
+@end deffn
+
+@deffn {show PIM Information} {show ip pim upstream-rpf} {}
+Display upstream information for S,G's and the RPF data
+associated with them
+@end deffn
+
+@deffn {show PIM Information} {show ip rpf} {}
+Display the multicast RIB created in zebra
+@end deffn
+
+@node  PIM Debug Commands
+@section PIM Debug Commands
+
+The debugging subsystem for PIM behaves in accordance with how FRR handles debugging.  You can specify debugging at the enable cli mode as well as the configure cli mode.  If you specify debug commands in the configuration cli mode, the debug commands can be persistent across restarts of the FRR pimd if the config was written out.
+
+@deffn {PIM Debug Commands} {debug pim events}
+This turns on debugging for PIM system events.  Especially timers.
+@end deffn
+
+@deffn {PIM Debug Commands} {debug pim nht}
+This turns on debugging for PIM nexthop tracking.  It will display information about RPF lookups and information about when a nexthop changes.
+@end deffn
+
+@deffn {PIM Debug Commands} {debug pim packet-dump}
+This turns on an extraordinary amount of data.  Each pim packet sent and received is dumped for debugging purposes.  This should be considered a developer only command
+@end deffn
+
+@deffn {PIM Debug Commands} {debug pim packets}
+This turns on information about packet generation for sending and about packet handling from a received packet
+@end deffn
+
+@deffn {PIM Debug Commands} {debug pim trace}
+This traces pim code and how it is running.
+@end deffn
+
+@deffn {PIM Debug Commands} {debug pim zebra}
+This gathers data about events from zebra that come up through the zapi
+@end deffn
index b72f539c466604ebe7452e9884e2f5c5a577cd18..3e683f44d19841f3e438acd67379fb1dd4f757ae 100644 (file)
@@ -171,6 +171,11 @@ Matches the specified @var{as_path}.
 Matches the specified @var{metric}.
 @end deffn
 
+@deffn {Route-map Command} {match tag @var{tag}} {}
+Matches the specified tag value associated with the route.
+This tag value can be in the range of (1-4294967295).
+@end deffn
+
 @deffn {Route-map Command} {match local-preference @var{metric}} {}
 Matches the specified @var{local-preference}.
 @end deffn
@@ -198,6 +203,14 @@ in this manner.
 @node Route Map Set Command
 @section Route Map Set Command
 
+@deffn {Route-map Command} {set tag @var{tag}} {}
+Set a tag on the matched route.  This tag value can be from
+(1-4294967295).  Additionally if you have compiled with
+the --enable-realms configure option.  Tag values from (1-255)
+are sent to the linux kernel as a realm value.  Then route
+policy can be applied.  See the tc man page.
+@end deffn
+
 @deffn {Route-map Command} {set ip next-hop @var{ipv4_address}} {}
 Set the BGP nexthop address.
 @end deffn
index c44519a9f3af6dba08c479255768eac604db7d0a..6193d3c906f6275db27a3c2c0a9ea3b653768f22 100644 (file)
@@ -22,8 +22,8 @@ BGP, with IP VPNs and Tunnel Encapsulation, is used to distribute VN
 information between NVAs. BGP based IP VPN support is defined in
 @cite{RFC4364, BGP/MPLS IP Virtual Private Networks (VPNs)}, and
 @cite{RFC4659, BGP-MPLS IP Virtual Private Network (VPN) Extension for
-IPv6 VPN }.  Both the Encapsulation Subsequent Address Family Identifier
-(SAFI) and the Tunnel Encapsulation Attribute, @cite{RFC5512, The BGP
+IPv6 VPN }.  Encapsulation information is provided via
+the Tunnel Encapsulation Attribute, @cite{RFC5512, The BGP
 Encapsulation Subsequent Address Family Identifier (SAFI) and the BGP
 Tunnel Encapsulation Attribute}, are supported.
 
@@ -83,12 +83,10 @@ operating within a VN.
 @node General VNC Configuration
 @subsection General VNC Configuration
 
-@deffn {VNC} {vnc advertise-un-method encap-safi|encap-attr} {}
-Advertise NVE underlay-network IP addresses using the encapsulation SAFI
-(@code{encap-safi}) or the UN address sub-TLV of the Tunnel Encapsulation attribute
-(@code{encap-attr}). When @code{encap-safi} is used, neighbors under 
-@code{address-family encap} and/or @code{address-family encapv6} must be
-configured.  The default is @code{encap-attr}. 
+@deffn {VNC} {vnc advertise-un-method encap-attr} {}
+Advertise NVE underlay-network IP addresses using
+the UN address sub-TLV of the Tunnel Encapsulation attribute
+(@code{encap-attr}). The default is @code{encap-attr}. 
 @end deffn
 
 @node RFP Related Configuration
@@ -356,8 +354,7 @@ by receiving NVAs.
 The second form, @code{rt import} specifies an @var{import rt-list},
 which is a filter for incoming routes.
 In order to be made available to NVEs in the group,
-incoming BGP VPN and @w{ENCAP} @w{SAFI} (when @code{vnc
-advertise-un-method encap-safi} is set) routes must have
+incoming BGP VPN @w{SAFI} routes must have
 RT lists that have at least one route target in common with the
 group's @var{import rt-list}.
 
@@ -1010,7 +1007,7 @@ router bgp 64512
     neighbor 192.168.1.101  remote-as 64512
     neighbor 192.168.1.102  remote-as 64512
 
-    address-family vpnv4
+    address-family ipv4 vpn
         neighbor 192.168.1.101 activate
         neighbor 192.168.1.102 activate
     exit-address-family
@@ -1043,7 +1040,7 @@ router bgp 64512
     neighbor 192.168.1.100  remote-as 64512
     neighbor 192.168.1.102  remote-as 64512
 
-    address-family vpnv4
+    address-family ipv4 vpn
         neighbor 192.168.1.100 activate
         neighbor 192.168.1.102 activate
     exit-address-family
@@ -1066,7 +1063,7 @@ router bgp 64512
     neighbor 192.168.1.101  remote-as 64512
     neighbor 192.168.1.102  remote-as 64512
 
-    address-family vpnv4
+    address-family ipv4 vpn
         neighbor 192.168.1.100 activate
         neighbor 192.168.1.101 activate
     exit-address-family
@@ -1131,7 +1128,7 @@ router bgp 64512
   neighbor 172.16.2.2 route-reflector-client
  exit-address-family
  !
- address-family vpnv4 unicast
+ address-family ipv4 vpn
    neighbor 192.168.1.102 activate
    neighbor 192.168.1.103 activate
    neighbor 192.168.1.104 activate
@@ -1161,7 +1158,7 @@ router bgp 64512
   no neighbor 192.168.1.103 activate
  exit-address-family
  !
- address-family vpnv4 unicast
+ address-family ipv4 vpn
    neighbor 192.168.1.101 activate
    neighbor 192.168.1.102 activate
    neighbor 192.168.1.103 activate
@@ -1250,7 +1247,7 @@ router bgp 64512
         neighbor 192.168.1.102 route-reflector-client
     exit-address-family
 
-    address-family vpnv4
+    address-family ipv4 vpn
         neighbor 192.168.1.101 activate
         neighbor 192.168.1.102 activate
 
@@ -1269,7 +1266,7 @@ router bgp 64512
 
     neighbor 192.168.1.100  remote-as 64512
 
-    address-family vpnv4
+    address-family ipv4 vpn
         neighbor 192.168.1.100 activate
     exit-address-family
 
@@ -1290,7 +1287,7 @@ router bgp 64512
 
     neighbor 192.168.1.100  remote-as 64512
 
-    address-family vpnv4
+    address-family ipv4 vpn
         neighbor 192.168.1.100 activate
     exit-address-family
 
@@ -1381,7 +1378,7 @@ router bgp 64512
 
     neighbor 192.168.1.100  remote-as 64512
 
-    address-family vpnv4
+    address-family ipv4 vpn
         neighbor 192.168.1.100 activate
     exit-address-family
 
@@ -1402,7 +1399,7 @@ router bgp 64512
 
     neighbor 192.168.1.100  remote-as 64512
 
-    address-family vpnv4
+    address-family ipv4 vpn
         neighbor 192.168.1.100 activate
     exit-address-family
 
@@ -1450,7 +1447,7 @@ router bgp 64512
     neighbor 192.168.1.102 description iBGP-client-192-168-1-102
     neighbor 192.168.1.102 route-reflector-client
 
-    address-family vpnv4
+    address-family ipv4 vpn
        neighbor 192.168.1.101 activate
        neighbor 192.168.1.102 activate
        neighbor 192.168.1.104 activate
@@ -1470,7 +1467,7 @@ router bgp 64512
     neighbor 192.168.1.100  remote-as 64512
     neighbor 192.168.1.104  remote-as 64512
 
-    address-family vpnv4
+    address-family ipv4 vpn
         neighbor 192.168.1.100 activate
         neighbor 192.168.1.104 activate
     exit-address-family
@@ -1493,7 +1490,7 @@ router bgp 64512
     neighbor 192.168.1.100  remote-as 64512
     neighbor 192.168.1.104  remote-as 64512
 
-    address-family vpnv4
+    address-family ipv4 vpn
         neighbor 192.168.1.100 activate
         neighbor 192.168.1.104 activate
     exit-address-family
index 00438f2f47c0c2f7d69e19b4ac84a2b9ce75d853..3759c6414838c8cba7570c4d0ca1e54dc05011ca 100644 (file)
@@ -377,6 +377,7 @@ void eigrp_zebra_route_add(struct prefix *p, struct list *successors)
                if (count >= MULTIPATH_NUM)
                        break;
                api_nh = &api.nexthops[count];
+               api_nh->vrf_id = VRF_DEFAULT;
                if (te->adv_router->src.s_addr) {
                        api_nh->gate.ipv4 = te->adv_router->src;
                        api_nh->type = NEXTHOP_TYPE_IPV4_IFINDEX;
index a2c18e556df93018bd0ca7ad91af8a694d68c240..560c13c77d140075d9fc315e560c5fb3b346e7df 100644 (file)
--- a/indent.py
+++ b/indent.py
@@ -6,7 +6,7 @@ import sys, re, subprocess, os
 
 # find all DEFUNs
 defun_re = re.compile(
-        r'^(DEF(UN(_NOSH|_HIDDEN)?|PY)\s*\(.*?)^(?=\s*\{)',
+        r'^((DEF(UN(_NOSH|_HIDDEN)?|PY)|ALIAS)\s*\(.*?)^(?=\s*\{)',
         re.M | re.S)
 define_re = re.compile(
         r'((^#\s*define[^\n]+[^\\]\n)+)',
index a5ee922318d8cd29e38ca6c3e2b02e4d59d02daa..32683c57d58a054fcd057f62ca1d5c46eca66dde 100644 (file)
@@ -14,8 +14,6 @@
  * into proprietary software; there is no requirement for such software to
  * contain a copyright notice related to this source.
  *
- * $Id: dict.h,v 1.3 2005/09/25 12:04:25 hasso Exp $
- * $Name:  $
  */
 
 #ifndef DICT_H
index 591af3b8eddf3a3dbc813b948a79a95b6d2cf7ed..a4c6b4c75d055a3e6e089b02e237c11defc00c7a 100644 (file)
 #include "privs.h"
 
 struct bpf_insn llcfilter[] = {
-       /* check first byte */
-       BPF_STMT(BPF_LD + BPF_B + BPF_ABS, ETH_ALEN),
+       BPF_STMT(BPF_LD + BPF_B + BPF_ABS,
+                ETHER_HDR_LEN), /* check first byte */
        BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ISO_SAP, 0, 5),
-       /* check second byte */
-       BPF_STMT(BPF_LD + BPF_B + BPF_ABS, ETH_ALEN + 1),
-       BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ISO_SAP, 0, 3),
-       /* check third byte */
-       BPF_STMT(BPF_LD + BPF_B + BPF_ABS, ETH_ALEN + 2),
-       BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x03, 0, 1),
+       BPF_STMT(BPF_LD + BPF_B + BPF_ABS, ETHER_HDR_LEN + 1),
+       BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ISO_SAP, 0,
+                3), /* check second byte */
+       BPF_STMT(BPF_LD + BPF_B + BPF_ABS, ETHER_HDR_LEN + 2),
+       BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x03, 0, 1), /* check third byte */
        BPF_STMT(BPF_RET + BPF_K, (u_int)-1),
        BPF_STMT(BPF_RET + BPF_K, 0)};
 u_int readblen = 0;
@@ -242,14 +241,15 @@ int isis_recv_pdu_bcast(struct isis_circuit *circuit, u_char *ssnpa)
 
        assert(bpf_hdr->bh_caplen == bpf_hdr->bh_datalen);
 
-       offset = bpf_hdr->bh_hdrlen + LLC_LEN + ETH_ALEN;
+       offset = bpf_hdr->bh_hdrlen + LLC_LEN + ETHER_HDR_LEN;
 
        /* then we lose the BPF, LLC and ethernet headers */
        stream_write(circuit->rcv_stream, readbuff + offset,
-                    bpf_hdr->bh_caplen - LLC_LEN - ETH_ALEN);
+                    bpf_hdr->bh_caplen - LLC_LEN - ETHER_HDR_LEN);
        stream_set_getp(circuit->rcv_stream, 0);
 
-       memcpy(ssnpa, readbuff + bpf_hdr->bh_hdrlen + ETH_ALEN, ETH_ALEN);
+       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));
@@ -263,7 +263,7 @@ int isis_send_pdu_bcast(struct isis_circuit *circuit, int level)
        ssize_t written;
        size_t buflen;
 
-       buflen = stream_get_endp(circuit->snd_stream) + LLC_LEN + ETH_ALEN;
+       buflen = stream_get_endp(circuit->snd_stream) + LLC_LEN + ETHER_HDR_LEN;
        if (buflen > sizeof(sock_buff)) {
                zlog_warn(
                        "isis_send_pdu_bcast: sock_buff size %zu is less than "
@@ -289,12 +289,12 @@ int isis_send_pdu_bcast(struct isis_circuit *circuit, int level)
        /*
         * Then the LLC
         */
-       sock_buff[ETH_ALEN] = ISO_SAP;
-       sock_buff[ETH_ALEN + 1] = ISO_SAP;
-       sock_buff[ETH_ALEN + 2] = 0x03;
+       sock_buff[ETHER_HDR_LEN] = ISO_SAP;
+       sock_buff[ETHER_HDR_LEN + 1] = ISO_SAP;
+       sock_buff[ETHER_HDR_LEN + 2] = 0x03;
 
        /* then we copy the data */
-       memcpy(sock_buff + (LLC_LEN + ETH_ALEN), circuit->snd_stream->data,
+       memcpy(sock_buff + (LLC_LEN + ETHER_HDR_LEN), circuit->snd_stream->data,
               stream_get_endp(circuit->snd_stream));
 
        /* now we can send this */
index 0b7dc86ad6c88f58294d58ec3a0562135d965ddc..20ce0f1fade63f7ba8c806240f170ffdb5730c10 100644 (file)
@@ -293,6 +293,7 @@ void isis_circuit_del_addr(struct isis_circuit *circuit,
 
                if (ip) {
                        listnode_delete(circuit->ip_addrs, ip);
+                       prefix_ipv4_free(ip);
                        if (circuit->area)
                                lsp_regenerate_schedule(circuit->area,
                                                        circuit->is_type, 0);
@@ -328,6 +329,7 @@ void isis_circuit_del_addr(struct isis_circuit *circuit,
                        }
                        if (ip6) {
                                listnode_delete(circuit->ipv6_link, ip6);
+                               prefix_ipv6_free(ip6);
                                found = 1;
                        }
                } else {
@@ -339,6 +341,7 @@ void isis_circuit_del_addr(struct isis_circuit *circuit,
                        }
                        if (ip6) {
                                listnode_delete(circuit->ipv6_non_link, ip6);
+                               prefix_ipv6_free(ip6);
                                found = 1;
                        }
                }
@@ -554,7 +557,7 @@ void isis_circuit_stream(struct isis_circuit *circuit, struct stream **stream)
 
 void isis_circuit_prepare(struct isis_circuit *circuit)
 {
-#ifdef GNU_LINUX
+#if ISIS_METHOD != ISIS_METHOD_DLPI
        thread_add_read(master, isis_receive, circuit, circuit->fd,
                        &circuit->t_read);
 #else
@@ -1165,7 +1168,6 @@ void isis_circuit_af_set(struct isis_circuit *circuit, bool ip_router,
        struct isis_area *area = circuit->area;
        bool change = circuit->ip_router != ip_router
                      || circuit->ipv6_router != ipv6_router;
-       bool was_enabled = !!circuit->area;
 
        area->ip_circuits += ip_router - circuit->ip_router;
        area->ipv6_circuits += ipv6_router - circuit->ipv6_router;
@@ -1179,8 +1181,6 @@ void isis_circuit_af_set(struct isis_circuit *circuit, bool ip_router,
 
        if (!ip_router && !ipv6_router)
                isis_csm_state_change(ISIS_DISABLE, circuit, area);
-       else if (!was_enabled)
-               isis_csm_state_change(ISIS_ENABLE, circuit, area);
        else
                lsp_regenerate_schedule(circuit->area, circuit->is_type, 0);
 }
index 614f46c78bb6795dcd63be2b9e2f7963b6d7c284..e1e9ccee48fd30629db20b4a15d09de721bf63ba 100644 (file)
@@ -286,7 +286,7 @@ static void put_lsp_hdr(struct isis_lsp *lsp, size_t *len_pointer, bool keep)
                (lsp->level == IS_LEVEL_1) ? L1_LINK_STATE : L2_LINK_STATE;
        struct isis_lsp_hdr *hdr = &lsp->hdr;
        struct stream *stream = lsp->pdu;
-       size_t orig_getp, orig_endp;
+       size_t orig_getp = 0, orig_endp = 0;
 
        if (keep) {
                orig_getp = stream_get_getp(lsp->pdu);
index b7389947b7c0140b8631d3d6640e659be1a69af1..55b0a362f63b17c6ba95364cb76278f9e4cc144c 100644 (file)
@@ -1312,7 +1312,7 @@ static int unpack_tlv_dynamic_hostname(enum isis_tlv_context context,
        bool sane = true;
        for (uint8_t i = 0; i < tlv_len; i++) {
                if ((unsigned char)tlvs->hostname[i] > 127
-                   || !isprint(tlvs->hostname[i])) {
+                   || !isprint((int)tlvs->hostname[i])) {
                        sane = false;
                        tlvs->hostname[i] = '?';
                }
index 573b81591cf7f0122f26a25ed55bd3db8385fd8a..ac640c5e4909c4b0ce4f729d4c44adcb858ebc44 100644 (file)
@@ -280,6 +280,7 @@ static void isis_zebra_route_add_route(struct prefix *prefix,
                        if (count >= MULTIPATH_NUM)
                                break;
                        api_nh = &api.nexthops[count];
+                       api_nh->vrf_id = VRF_DEFAULT;
                        /* FIXME: can it be ? */
                        if (nexthop->ip.s_addr != INADDR_ANY) {
                                api_nh->type = NEXTHOP_TYPE_IPV4_IFINDEX;
@@ -302,6 +303,7 @@ static void isis_zebra_route_add_route(struct prefix *prefix,
                        }
 
                        api_nh = &api.nexthops[count];
+                       api_nh->vrf_id = VRF_DEFAULT;
                        api_nh->gate.ipv6 = nexthop6->ip6;
                        api_nh->ifindex = nexthop6->ifindex;
                        api_nh->type = NEXTHOP_TYPE_IPV6_IFINDEX;
index 5662038a58528cca6418f737541c2d0c717ccc08..944f93331f002a3fb1ef6c6ae3cfaa4a6b27171f 100644 (file)
@@ -320,9 +320,9 @@ recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type)
                                /* do not accept invalid labels */
                                if (label > MPLS_LABEL_MAX ||
                                    (label <= MPLS_LABEL_RESERVED_MAX &&
-                                    label != MPLS_LABEL_IPV4NULL &&
-                                    label != MPLS_LABEL_IPV6NULL &&
-                                    label != MPLS_LABEL_IMPLNULL)) {
+                                    label != MPLS_LABEL_IPV4_EXPLICIT_NULL &&
+                                    label != MPLS_LABEL_IPV6_EXPLICIT_NULL &&
+                                    label != MPLS_LABEL_IMPLICIT_NULL)) {
                                        session_shutdown(nbr, S_BAD_TLV_VAL,
                                            msg.id, msg.type);
                                        goto err;
@@ -396,7 +396,7 @@ recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type)
                case MAP_TYPE_PREFIX:
                        switch (me->map.fec.prefix.af) {
                        case AF_INET:
-                               if (label == MPLS_LABEL_IPV6NULL) {
+                               if (label == MPLS_LABEL_IPV6_EXPLICIT_NULL) {
                                        session_shutdown(nbr, S_BAD_TLV_VAL,
                                            msg.id, msg.type);
                                        goto err;
@@ -405,7 +405,7 @@ recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type)
                                        goto next;
                                break;
                        case AF_INET6:
-                               if (label == MPLS_LABEL_IPV4NULL) {
+                               if (label == MPLS_LABEL_IPV4_EXPLICIT_NULL) {
                                        session_shutdown(nbr, S_BAD_TLV_VAL,
                                            msg.id, msg.type);
                                        goto err;
index 63e1e399463688a544cf16a4b9d97cdd9d9f10b2..a70b97d06b129c6b86fa2394ba235827af6f8c6c 100644 (file)
@@ -702,20 +702,20 @@ lde_update_label(struct fec_node *fn)
                switch (fn->fec.type) {
                case FEC_TYPE_IPV4:
                        if (!(ldeconf->ipv4.flags & F_LDPD_AF_EXPNULL))
-                               return (MPLS_LABEL_IMPLNULL);
+                               return (MPLS_LABEL_IMPLICIT_NULL);
                        if (lde_acl_check(ldeconf->ipv4.acl_label_expnull_for,
                            AF_INET, (union ldpd_addr *)&fn->fec.u.ipv4.prefix,
                            fn->fec.u.ipv4.prefixlen) != FILTER_PERMIT)
-                               return (MPLS_LABEL_IMPLNULL);
-                       return (MPLS_LABEL_IPV4NULL);
+                               return (MPLS_LABEL_IMPLICIT_NULL);
+                       return MPLS_LABEL_IPV4_EXPLICIT_NULL;
                case FEC_TYPE_IPV6:
                        if (!(ldeconf->ipv6.flags & F_LDPD_AF_EXPNULL))
-                               return (MPLS_LABEL_IMPLNULL);
+                               return (MPLS_LABEL_IMPLICIT_NULL);
                        if (lde_acl_check(ldeconf->ipv6.acl_label_expnull_for,
                            AF_INET6, (union ldpd_addr *)&fn->fec.u.ipv6.prefix,
                            fn->fec.u.ipv6.prefixlen) != FILTER_PERMIT)
-                               return (MPLS_LABEL_IMPLNULL);
-                       return (MPLS_LABEL_IPV6NULL);
+                               return (MPLS_LABEL_IMPLICIT_NULL);
+                       return MPLS_LABEL_IPV6_EXPLICIT_NULL;
                default:
                        fatalx("lde_update_label: unexpected fec type");
                        break;
@@ -1522,11 +1522,15 @@ lde_change_egress_label(int af)
 
        /* explicitly withdraw all null labels */
        RB_FOREACH(ln, nbr_tree, &lde_nbrs) {
-               lde_send_labelwithdraw_wcard(ln, MPLS_LABEL_IMPLNULL);
+               lde_send_labelwithdraw_wcard(ln, MPLS_LABEL_IMPLICIT_NULL);
                if (ln->v4_enabled)
-                       lde_send_labelwithdraw_wcard(ln, MPLS_LABEL_IPV4NULL);
+                       lde_send_labelwithdraw_wcard(
+                               ln,
+                               MPLS_LABEL_IPV4_EXPLICIT_NULL);
                if (ln->v6_enabled)
-                       lde_send_labelwithdraw_wcard(ln, MPLS_LABEL_IPV6NULL);
+                       lde_send_labelwithdraw_wcard(
+                               ln,
+                               MPLS_LABEL_IPV6_EXPLICIT_NULL);
        }
 
        /* update label of connected routes */
index c819b33b431694f3370e9791bd5025fde7b0d9e0..a9b066a3dade3304d0f51de5bcc80dcf8a2135a1 100644 (file)
@@ -115,11 +115,11 @@ log_label(uint32_t label)
        case NO_LABEL:
                snprintf(buf, TF_LEN, "-");
                break;
-       case MPLS_LABEL_IMPLNULL:
+       case MPLS_LABEL_IMPLICIT_NULL:
                snprintf(buf, TF_LEN, "imp-null");
                break;
-       case MPLS_LABEL_IPV4NULL:
-       case MPLS_LABEL_IPV6NULL:
+       case MPLS_LABEL_IPV4_EXPLICIT_NULL:
+       case MPLS_LABEL_IPV6_EXPLICIT_NULL:
                snprintf(buf, TF_LEN, "exp-null");
                break;
        default:
index 83c91c4c6078452fed3659b3b4b2c686c36da116..d17f2c3d48cb99bce0a48420cad0ecb4b9c4db43 100644 (file)
@@ -96,7 +96,6 @@ const char *node_names[] = {
        "ldp l2vpn",                // LDP_L2VPN_NODE,
        "ldp",                      // LDP_PSEUDOWIRE_NODE,
        "isis",                     // ISIS_NODE,
-       "pim",                      // PIM_NODE,
        "masc",                     // MASC_NODE,
        "irdp",                     // IRDP_NODE,
        "static ip",                // IP_NODE,
@@ -1308,7 +1307,6 @@ void cmd_exit(struct vty *vty)
        case KEYCHAIN_NODE:
        case MASC_NODE:
        case RMAP_NODE:
-       case PIM_NODE:
        case VTY_NODE:
                vty->node = CONFIG_NODE;
                break;
@@ -1414,7 +1412,6 @@ DEFUN (config_end,
        case KEYCHAIN_NODE:
        case KEYCHAIN_KEY_NODE:
        case MASC_NODE:
-       case PIM_NODE:
        case VTY_NODE:
        case LINK_PARAMS_NODE:
                vty_config_unlock(vty);
@@ -1865,7 +1862,7 @@ DEFUN (config_password,
                return CMD_SUCCESS;
        }
 
-       if (!isalnum(argv[idx_8]->arg[0])) {
+       if (!isalnum((int)argv[idx_8]->arg[0])) {
                vty_out(vty,
                        "Please specify string starting with alphanumeric\n");
                return CMD_WARNING_CONFIG_FAILED;
@@ -1917,7 +1914,7 @@ DEFUN (config_enable_password,
                }
        }
 
-       if (!isalnum(argv[idx_8]->arg[0])) {
+       if (!isalnum((int)argv[idx_8]->arg[0])) {
                vty_out(vty,
                        "Please specify string starting with alphanumeric\n");
                return CMD_WARNING_CONFIG_FAILED;
index 42dd1c5325d9e517bb19e0421de9f228b0668290..e1edc1ef321901001acf80a271600692b5e19017 100644 (file)
@@ -119,7 +119,6 @@ enum node_type {
        LDP_L2VPN_NODE,         /* LDP L2VPN node */
        LDP_PSEUDOWIRE_NODE,    /* LDP Pseudowire node */
        ISIS_NODE,              /* ISIS protocol mode */
-       PIM_NODE,               /* PIM protocol mode */
        MASC_NODE,              /* MASC for multicast.  */
        IRDP_NODE,              /* ICMP Router Discovery Protocol mode. */
        IP_NODE,                /* Static ip route node. */
@@ -190,7 +189,7 @@ struct cmd_node {
 #define CMD_NOT_MY_INSTANCE    14
 
 /* Argc max counts. */
-#define CMD_ARGC_MAX   25
+#define CMD_ARGC_MAX   256
 
 /* Turn off these macros when uisng cpp with extract.pl */
 #ifndef VTYSH_EXTRACT_PL
@@ -358,6 +357,7 @@ struct cmd_node {
 #define OSPF_RI_STR "OSPF Router Information specific commands\n"
 #define PCE_STR "PCE Router Information specific commands\n"
 #define MPLS_STR "MPLS information\n"
+#define SR_STR "Segment-Routing specific commands\n"
 #define WATCHFRR_STR "watchfrr information\n"
 #define ZEBRA_STR "Zebra information\n"
 
index fce11a70cc9053deed10e5f03611814ea7d33953..f00b126536e98e4774b7374e9c6a34501821c056 100644 (file)
@@ -97,7 +97,7 @@ void cmd_token_varname_set(struct cmd_token *token, const char *varname)
                        token->varname[i] = '_';
                        break;
                default:
-                       token->varname[i] = tolower(varname[i]);
+                       token->varname[i] = tolower((int)varname[i]);
                }
        token->varname[len] = '\0';
 }
index 436f3a241d8ae85455e3f5c4df535f4504b6c1c7..530900659b6c9edd2b95a95cc15044d29f3b8ad0 100644 (file)
@@ -23,8 +23,9 @@
  */
 
 %{
-/* ignore harmless bug in old versions of flex */
+/* ignore harmless bugs in old versions of flex */
 #pragma GCC diagnostic ignored "-Wsign-compare"
+#pragma GCC diagnostic ignored "-Wmissing-prototypes"
 
 #include "command_parse.h"
 
index c60373f910abec5244698a944b04dc4797466631..f6b07a0b20892d4bac482aa512c20cf109d3729a 100644 (file)
@@ -28,8 +28,6 @@
 
 DEFINE_MTYPE_STATIC(LIB, CMD_MATCHSTACK, "Command Match Stack")
 
-#define MAXDEPTH 256
-
 #ifdef TRACE_MATCHER
 #define TM 1
 #else
@@ -84,7 +82,7 @@ static enum match_type match_mac(const char *, bool);
 enum matcher_rv command_match(struct graph *cmdgraph, vector vline,
                              struct list **argv, const struct cmd_element **el)
 {
-       struct graph_node *stack[MAXDEPTH];
+       struct graph_node *stack[CMD_ARGC_MAX];
        enum matcher_rv status;
        *argv = NULL;
 
@@ -200,7 +198,7 @@ static enum matcher_rv command_match_r(struct graph_node *start, vector vline,
        /* check history/stack of tokens
         * this disallows matching the same one more than once if there is a
         * circle in the graph (used for keyword arguments) */
-       if (n == MAXDEPTH)
+       if (n == CMD_ARGC_MAX)
                return MATCHER_NO_MATCH;
        if (!token->allowrepeat)
                for (size_t s = 0; s < n; s++)
index 024445be638ca20c57e11a925664b63418e63f0f..87775a0e7550f1532d93f2cad14b8e7e56791fb9 100644 (file)
@@ -34,8 +34,9 @@
  * code documentation in it.
  */
 
-/* ignore harmless bug in old versions of flex */
+/* ignore harmless bugs in old versions of flex */
 #pragma GCC diagnostic ignored "-Wsign-compare"
+#pragma GCC diagnostic ignored "-Wunused-value"
 
 #include "config.h"
 #include <Python.h>
index 8b23640fa40ecb0a13e25a2c942884c5a642e8d1..72b47ae5c32ad76a1c6bbabc17abc988d98820db 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Utilities and interfaces for managing POSIX threads
+ * Utilities and interfaces for managing POSIX threads within FRR.
  * Copyright (C) 2017  Cumulus Networks
  *
  * This program is free software; you can redistribute it and/or modify
 
 #include <zebra.h>
 #include <pthread.h>
+#include <sched.h>
 
 #include "frr_pthread.h"
 #include "memory.h"
 #include "hash.h"
 
-DEFINE_MTYPE_STATIC(LIB, FRR_PTHREAD, "FRR POSIX Thread");
+DEFINE_MTYPE(LIB, FRR_PTHREAD, "FRR POSIX Thread");
+DEFINE_MTYPE(LIB, PTHREAD_PRIM, "POSIX synchronization primitives");
 
+/* id for next created pthread */
 static unsigned int next_id = 0;
 
-/* Hash table of all frr_pthreads along with synchronization primitive(s) and
- * hash table callbacks.
- * ------------------------------------------------------------------------ */
-static struct hash *pthread_table;
-static pthread_mutex_t pthread_table_mtx = PTHREAD_MUTEX_INITIALIZER;
+/* default frr_pthread start/stop routine prototypes */
+static void *fpt_run(void *arg);
+static int fpt_halt(struct frr_pthread *fpt, void **res);
 
-/* pthread_table->hash_cmp */
-static int pthread_table_hash_cmp(const void *value1, const void *value2)
+/* default frr_pthread attributes */
+struct frr_pthread_attr frr_pthread_attr_default = {
+       .id = 0,
+       .start = fpt_run,
+       .stop = fpt_halt,
+       .name = "Anonymous",
+};
+
+/* hash table to keep track of all frr_pthreads */
+static struct hash *frr_pthread_hash;
+static pthread_mutex_t frr_pthread_hash_mtx = PTHREAD_MUTEX_INITIALIZER;
+
+/* frr_pthread_hash->hash_cmp */
+static int frr_pthread_hash_cmp(const void *value1, const void *value2)
 {
        const struct frr_pthread *tq1 = value1;
        const struct frr_pthread *tq2 = value2;
 
-       return (tq1->id == tq2->id);
+       return (tq1->attr.id == tq2->attr.id);
 }
 
-/* pthread_table->hash_key */
-static unsigned int pthread_table_hash_key(void *value)
+/* frr_pthread_hash->hash_key */
+static unsigned int frr_pthread_hash_key(void *value)
 {
-       return ((struct frr_pthread *)value)->id;
+       return ((struct frr_pthread *)value)->attr.id;
 }
+
 /* ------------------------------------------------------------------------ */
 
 void frr_pthread_init()
 {
-       pthread_mutex_lock(&pthread_table_mtx);
+       pthread_mutex_lock(&frr_pthread_hash_mtx);
        {
-               pthread_table = hash_create(pthread_table_hash_key,
-                                           pthread_table_hash_cmp, NULL);
+               frr_pthread_hash = hash_create(frr_pthread_hash_key,
+                                              frr_pthread_hash_cmp, NULL);
        }
-       pthread_mutex_unlock(&pthread_table_mtx);
+       pthread_mutex_unlock(&frr_pthread_hash_mtx);
 }
 
 void frr_pthread_finish()
 {
-       pthread_mutex_lock(&pthread_table_mtx);
+       pthread_mutex_lock(&frr_pthread_hash_mtx);
        {
-               hash_clean(pthread_table,
+               hash_clean(frr_pthread_hash,
                           (void (*)(void *))frr_pthread_destroy);
-               hash_free(pthread_table);
+               hash_free(frr_pthread_hash);
        }
-       pthread_mutex_unlock(&pthread_table_mtx);
+       pthread_mutex_unlock(&frr_pthread_hash_mtx);
 }
 
-struct frr_pthread *frr_pthread_new(const char *name, unsigned int id,
-                                   void *(*start_routine)(void *),
-                                   int (*stop_routine)(void **,
-                                                       struct frr_pthread *))
+struct frr_pthread *frr_pthread_new(struct frr_pthread_attr *attr)
 {
        static struct frr_pthread holder = {0};
        struct frr_pthread *fpt = NULL;
 
-       pthread_mutex_lock(&pthread_table_mtx);
+       attr = attr ? attr : &frr_pthread_attr_default;
+
+       pthread_mutex_lock(&frr_pthread_hash_mtx);
        {
-               holder.id = id;
-
-               if (!hash_lookup(pthread_table, &holder)) {
-                       struct frr_pthread *fpt = XCALLOC(
-                               MTYPE_FRR_PTHREAD, sizeof(struct frr_pthread));
-                       fpt->id = id;
-                       fpt->master = thread_master_create(name);
-                       fpt->start_routine = start_routine;
-                       fpt->stop_routine = stop_routine;
-                       fpt->name = XSTRDUP(MTYPE_FRR_PTHREAD, name);
-
-                       hash_get(pthread_table, fpt, hash_alloc_intern);
+               holder.attr.id = attr->id;
+
+               if (!hash_lookup(frr_pthread_hash, &holder)) {
+                       fpt = XCALLOC(MTYPE_FRR_PTHREAD,
+                                     sizeof(struct frr_pthread));
+                       /* create new thread master */
+                       fpt->master = thread_master_create(attr->name);
+                       /* set attributes */
+                       fpt->attr = *attr;
+                       if (attr == &frr_pthread_attr_default)
+                               fpt->attr.id = frr_pthread_get_id();
+                       /* initialize startup synchronization primitives */
+                       fpt->running_cond_mtx = XCALLOC(
+                               MTYPE_PTHREAD_PRIM, sizeof(pthread_mutex_t));
+                       fpt->running_cond = XCALLOC(MTYPE_PTHREAD_PRIM,
+                                                   sizeof(pthread_cond_t));
+                       pthread_mutex_init(fpt->running_cond_mtx, NULL);
+                       pthread_cond_init(fpt->running_cond, NULL);
+
+                       /* insert into global thread hash */
+                       hash_get(frr_pthread_hash, fpt, hash_alloc_intern);
                }
        }
-       pthread_mutex_unlock(&pthread_table_mtx);
+       pthread_mutex_unlock(&frr_pthread_hash_mtx);
 
        return fpt;
 }
@@ -103,7 +125,11 @@ struct frr_pthread *frr_pthread_new(const char *name, unsigned int id,
 void frr_pthread_destroy(struct frr_pthread *fpt)
 {
        thread_master_free(fpt->master);
-       XFREE(MTYPE_FRR_PTHREAD, fpt->name);
+
+       pthread_mutex_destroy(fpt->running_cond_mtx);
+       pthread_cond_destroy(fpt->running_cond);
+       XFREE(MTYPE_PTHREAD_PRIM, fpt->running_cond_mtx);
+       XFREE(MTYPE_PTHREAD_PRIM, fpt->running_cond);
        XFREE(MTYPE_FRR_PTHREAD, fpt);
 }
 
@@ -112,73 +138,143 @@ struct frr_pthread *frr_pthread_get(unsigned int id)
        static struct frr_pthread holder = {0};
        struct frr_pthread *fpt;
 
-       pthread_mutex_lock(&pthread_table_mtx);
+       pthread_mutex_lock(&frr_pthread_hash_mtx);
        {
-               holder.id = id;
-               fpt = hash_lookup(pthread_table, &holder);
+               holder.attr.id = id;
+               fpt = hash_lookup(frr_pthread_hash, &holder);
        }
-       pthread_mutex_unlock(&pthread_table_mtx);
+       pthread_mutex_unlock(&frr_pthread_hash_mtx);
 
        return fpt;
 }
 
-int frr_pthread_run(unsigned int id, const pthread_attr_t *attr, void *arg)
+int frr_pthread_run(struct frr_pthread *fpt, const pthread_attr_t *attr)
 {
-       struct frr_pthread *fpt = frr_pthread_get(id);
        int ret;
 
-       if (!fpt)
-               return -1;
+       ret = pthread_create(&fpt->thread, attr, fpt->attr.start, fpt);
 
-       ret = pthread_create(&fpt->thread, attr, fpt->start_routine, arg);
-
-       /* Per pthread_create(3), the contents of fpt->thread are undefined if
-        * pthread_create() did not succeed. Reset this value to zero. */
+       /*
+        * Per pthread_create(3), the contents of fpt->thread are undefined if
+        * pthread_create() did not succeed. Reset this value to zero.
+        */
        if (ret < 0)
                memset(&fpt->thread, 0x00, sizeof(fpt->thread));
 
        return ret;
 }
 
-/**
- * Calls the stop routine for the frr_pthread and resets any relevant fields.
- *
- * @param fpt - the frr_pthread to stop
- * @param result - pointer to result pointer
- * @return the return code from the stop routine
- */
-static int frr_pthread_stop_actual(struct frr_pthread *fpt, void **result)
+void frr_pthread_wait_running(struct frr_pthread *fpt)
 {
-       int ret = (*fpt->stop_routine)(result, fpt);
-       memset(&fpt->thread, 0x00, sizeof(fpt->thread));
-       return ret;
+       pthread_mutex_lock(fpt->running_cond_mtx);
+       {
+               while (!fpt->running)
+                       pthread_cond_wait(fpt->running_cond,
+                                         fpt->running_cond_mtx);
+       }
+       pthread_mutex_unlock(fpt->running_cond_mtx);
+}
+
+void frr_pthread_notify_running(struct frr_pthread *fpt)
+{
+       pthread_mutex_lock(fpt->running_cond_mtx);
+       {
+               fpt->running = true;
+               pthread_cond_signal(fpt->running_cond);
+       }
+       pthread_mutex_unlock(fpt->running_cond_mtx);
 }
 
-int frr_pthread_stop(unsigned int id, void **result)
+int frr_pthread_stop(struct frr_pthread *fpt, void **result)
 {
-       struct frr_pthread *fpt = frr_pthread_get(id);
-       return frr_pthread_stop_actual(fpt, result);
+       int ret = (*fpt->attr.stop)(fpt, result);
+       memset(&fpt->thread, 0x00, sizeof(fpt->thread));
+       return ret;
 }
 
-/**
+/*
  * Callback for hash_iterate to stop all frr_pthread's.
  */
 static void frr_pthread_stop_all_iter(struct hash_backet *hb, void *arg)
 {
        struct frr_pthread *fpt = hb->data;
-       frr_pthread_stop_actual(fpt, NULL);
+       frr_pthread_stop(fpt, NULL);
 }
 
 void frr_pthread_stop_all()
 {
-       pthread_mutex_lock(&pthread_table_mtx);
+       pthread_mutex_lock(&frr_pthread_hash_mtx);
        {
-               hash_iterate(pthread_table, frr_pthread_stop_all_iter, NULL);
+               hash_iterate(frr_pthread_hash, frr_pthread_stop_all_iter, NULL);
        }
-       pthread_mutex_unlock(&pthread_table_mtx);
+       pthread_mutex_unlock(&frr_pthread_hash_mtx);
 }
 
 unsigned int frr_pthread_get_id()
 {
+       /* just a sanity check, this should never happen */
+       assert(next_id <= INT_MAX - 1);
        return next_id++;
 }
+
+void frr_pthread_yield(void)
+{
+       (void)sched_yield();
+}
+
+/*
+ * ----------------------------------------------------------------------------
+ * Default Event Loop
+ * ----------------------------------------------------------------------------
+ */
+
+/* dummy task for sleeper pipe */
+static int fpt_dummy(struct thread *thread)
+{
+       return 0;
+}
+
+/* poison pill task to end event loop */
+static int fpt_finish(struct thread *thread)
+{
+       struct frr_pthread *fpt = THREAD_ARG(thread);
+       atomic_store_explicit(&fpt->running, false, memory_order_relaxed);
+       return 0;
+}
+
+/* stop function, called from other threads to halt this one */
+static int fpt_halt(struct frr_pthread *fpt, void **res)
+{
+       thread_add_event(fpt->master, &fpt_finish, fpt, 0, NULL);
+       pthread_join(fpt->thread, res);
+       fpt = NULL;
+
+       return 0;
+}
+
+/* entry pthread function & main event loop */
+static void *fpt_run(void *arg)
+{
+       struct frr_pthread *fpt = arg;
+       fpt->master->owner = pthread_self();
+
+       int sleeper[2];
+       pipe(sleeper);
+       thread_add_read(fpt->master, &fpt_dummy, NULL, sleeper[0], NULL);
+
+       fpt->master->handle_signals = false;
+
+       frr_pthread_notify_running(fpt);
+
+       struct thread task;
+       while (atomic_load_explicit(&fpt->running, memory_order_relaxed)) {
+               if (thread_fetch(fpt->master, &task)) {
+                       thread_call(&task);
+               }
+       }
+
+       close(sleeper[1]);
+       close(sleeper[0]);
+
+       return NULL;
+}
index 9dee5fcca4a35bc9517cdfec626b4240fd1c3d90..2cc50196a897b81ca103c0c6f3c6ba56314653ae 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Utilities and interfaces for managing POSIX threads
+ * Utilities and interfaces for managing POSIX threads within FRR.
  * Copyright (C) 2017  Cumulus Networks
  *
  * This program is free software; you can redistribute it and/or modify
 #define _FRR_PTHREAD_H
 
 #include <pthread.h>
+#include "frratomic.h"
+#include "memory.h"
 #include "thread.h"
 
+DECLARE_MTYPE(FRR_PTHREAD);
+DECLARE_MTYPE(PTHREAD_PRIM);
+
+struct frr_pthread;
+struct frr_pthread_attr;
+
+struct frr_pthread_attr {
+       int id;
+       void *(*start)(void *);
+       int (*stop)(struct frr_pthread *, void **);
+       const char *name;
+};
+
 struct frr_pthread {
 
        /* pthread id */
        pthread_t thread;
 
-       /* frr thread identifier */
-       unsigned int id;
-
        /* thread master for this pthread's thread.c event loop */
        struct thread_master *master;
 
-       /* start routine */
-       void *(*start_routine)(void *);
-
-       /* stop routine */
-       int (*stop_routine)(void **, struct frr_pthread *);
-
-       /* the (hopefully descriptive) name of this thread */
-       char *name;
+       /* caller-specified data; start & stop funcs, name, id */
+       struct frr_pthread_attr attr;
+
+       /*
+        * Notification mechanism for allowing pthreads to notify their parents
+        * when they are ready to do work. This mechanism has two associated
+        * functions:
+        *
+        * - frr_pthread_wait_running()
+        *   This function should be called by the spawning thread after
+        *   frr_pthread_run(). It safely waits until the spawned thread
+        *   indicates that is ready to do work by posting to the condition
+        *   variable.
+        *
+        * - frr_pthread_notify_running()
+        *   This function should be called by the spawned thread when it is
+        *   ready to do work. It will wake up any threads waiting on the
+        *   previously described condition.
+        */
+       pthread_cond_t *running_cond;
+       pthread_mutex_t *running_cond_mtx;
+       _Atomic bool running;
+
+       /*
+        * Fake thread-specific storage. No constraints on usage. Helpful when
+        * creating reentrant pthread implementations. Can be used to pass
+        * argument to pthread entry function.
+        */
+       void *data;
 };
 
-/* Initializes this module.
+extern struct frr_pthread_attr frr_pthread_attr_default;
+
+/*
+ * Initializes this module.
  *
  * Must be called before using any of the other functions.
  */
 void frr_pthread_init(void);
 
-/* Uninitializes this module.
+/*
+ * Uninitializes this module.
  *
  * Destroys all registered frr_pthread's and internal data structures.
  *
@@ -59,34 +96,23 @@ void frr_pthread_init(void);
  */
 void frr_pthread_finish(void);
 
-/* Creates a new frr_pthread.
- *
- * If the provided ID is already assigned to an existing frr_pthread, the
- * return value will be NULL.
- *
- * @param name - the name of the thread. Doesn't have to be unique, but it
- * probably should be. This value is copied and may be safely free'd upon
- * return.
- *
- * @param id - the integral ID of the thread. MUST be unique. The caller may
- * use this id to retrieve the thread.
- *
- * @param start_routine - start routine for the pthread, will be passed to
- * pthread_create (see those docs for details)
+/*
+ * Creates a new frr_pthread with the given attributes.
  *
- * @param stop_routine - stop routine for the pthread, called to terminate the
- * thread. This function should gracefully stop the pthread and clean up any
- * thread-specific resources. The passed pointer is used to return a data
- * result.
+ * The 'attr' argument should be filled out with the desired attributes,
+ * including ID, start and stop functions and the desired name. Alternatively,
+ * if attr is NULL, the default attributes will be used. The pthread will be
+ * set up to run a basic threadmaster loop and the name will be "Anonymous".
+ * Scheduling tasks onto the threadmaster in the 'master' field of the returned
+ * frr_pthread will cause them to run on that pthread.
  *
+ * @param attr - the thread attributes
  * @return the created frr_pthread upon success, or NULL upon failure
  */
-struct frr_pthread *frr_pthread_new(const char *name, unsigned int id,
-                                   void *(*start_routine)(void *),
-                                   int (*stop_routine)(void **,
-                                                       struct frr_pthread *));
+struct frr_pthread *frr_pthread_new(struct frr_pthread_attr *attr);
 
-/* Destroys an frr_pthread.
+/*
+ * Destroys an frr_pthread.
  *
  * Assumes that the associated pthread, if any, has already terminated.
  *
@@ -94,43 +120,75 @@ struct frr_pthread *frr_pthread_new(const char *name, unsigned int id,
  */
 void frr_pthread_destroy(struct frr_pthread *fpt);
 
-/* Gets an existing frr_pthread by its id.
+/*
+ * Gets an existing frr_pthread by its id.
  *
  * @return frr_thread associated with the provided id, or NULL on error
  */
 struct frr_pthread *frr_pthread_get(unsigned int id);
 
-/* Creates a new pthread and binds it to a frr_pthread.
+/*
+ * Creates a new pthread and binds it to a frr_pthread.
  *
  * This function is a wrapper for pthread_create. The first parameter is the
  * frr_pthread to bind the created pthread to. All subsequent arguments are
- * passed unmodified to pthread_create().
+ * passed unmodified to pthread_create(). The frr_pthread * provided will be
+ * used as the argument to the pthread entry function. If it is necessary to
+ * pass additional data, the 'data' field in the frr_pthread may be used.
  *
  * This function returns the same code as pthread_create(). If the value is
  * zero, the provided frr_pthread is bound to a running POSIX thread. If the
  * value is less than zero, the provided frr_pthread is guaranteed to be a
  * clean instance that may be susbsequently passed to frr_pthread_run().
  *
- * @param id - frr_pthread to bind the created pthread to
+ * @param fpt - frr_pthread * to run
  * @param attr - see pthread_create(3)
- * @param arg - see pthread_create(3)
  *
  * @return see pthread_create(3)
  */
-int frr_pthread_run(unsigned int id, const pthread_attr_t *attr, void *arg);
+int frr_pthread_run(struct frr_pthread *fpt, const pthread_attr_t *attr);
+
+/*
+ * Waits until the specified pthread has finished setting up and is ready to
+ * begin work.
+ *
+ * If the pthread's code makes use of the startup synchronization mechanism,
+ * this function should be called before attempting to use the functionality
+ * exposed by the pthread. It waits until the 'running' condition is satisfied
+ * (see struct definition of frr_pthread).
+ *
+ * @param fpt - the frr_pthread * to wait on
+ */
+void frr_pthread_wait_running(struct frr_pthread *fpt);
 
-/* Stops an frr_pthread with a result.
+/*
+ * Notifies other pthreads that the calling thread has finished setting up and
+ * is ready to begin work.
  *
- * @param id - frr_pthread to stop
+ * This will allow any other pthreads waiting in 'frr_pthread_wait_running' to
+ * proceed.
+ *
+ * @param fpt - the frr_pthread * that has finished setting up
+ */
+void frr_pthread_notify_running(struct frr_pthread *fpt);
+
+/*
+ * Stops a frr_pthread with a result.
+ *
+ * @param fpt - frr_pthread * to stop
  * @param result - where to store the thread's result, if any. May be NULL if a
  * result is not needed.
  */
-int frr_pthread_stop(unsigned int id, void **result);
+int frr_pthread_stop(struct frr_pthread *fpt, void **result);
 
 /* Stops all frr_pthread's. */
 void frr_pthread_stop_all(void);
 
-/* Returns a unique identifier for use with frr_pthread_new().
+/* Yields the current thread of execution */
+void frr_pthread_yield(void);
+
+/*
+ * Returns a unique identifier for use with frr_pthread_new().
  *
  * Internally, this is an integer that increments after each call to this
  * function. Because the number of pthreads created should never exceed INT_MAX
index 66b042ad974c3a1183cfd62c638e450b08b551ac..79c951dd6916ac3bf1e6c17bc29158944c49a57e 100644 (file)
@@ -33,8 +33,6 @@
 
 DEFINE_MTYPE_STATIC(LIB, CMD_TOKENS, "Command desc")
 
-#define MAXDEPTH 64
-
 /** headers **/
 void grammar_sandbox_init(void);
 void pretty_print_graph(struct vty *vty, struct graph_node *, int, int,
@@ -262,7 +260,7 @@ DEFUN (grammar_test_show,
 {
        check_nodegraph();
 
-       struct graph_node *stack[MAXDEPTH];
+       struct graph_node *stack[CMD_ARGC_MAX];
        pretty_print_graph(vty, vector_slot(nodegraph->nodes, 0), 0, argc >= 3,
                           stack, 0);
        return CMD_SUCCESS;
@@ -277,8 +275,8 @@ DEFUN (grammar_test_dot,
 {
        check_nodegraph();
 
-       struct graph_node *stack[MAXDEPTH];
-       struct graph_node *visited[MAXDEPTH * MAXDEPTH];
+       struct graph_node *stack[CMD_ARGC_MAX];
+       struct graph_node *visited[CMD_ARGC_MAX * CMD_ARGC_MAX];
        size_t vpos = 0;
 
        FILE *ofd = fopen(argv[2]->arg, "w");
@@ -334,7 +332,7 @@ static void cmd_graph_permute(struct list *out, struct graph_node **stack,
                return;
        }
 
-       if (++stackpos == MAXDEPTH)
+       if (++stackpos == CMD_ARGC_MAX)
                return;
 
        for (i = 0; i < vector_active(gn->to); i++) {
@@ -354,7 +352,7 @@ static void cmd_graph_permute(struct list *out, struct graph_node **stack,
 static struct list *cmd_graph_permutations(struct graph *graph)
 {
        char accumulate[2048] = "";
-       struct graph_node *stack[MAXDEPTH];
+       struct graph_node *stack[CMD_ARGC_MAX];
 
        struct list *rv = list_new();
        rv->cmp = cmd_permute_cmp;
@@ -532,7 +530,7 @@ void pretty_print_graph(struct vty *vty, struct graph_node *start, int level,
                vty_out(vty, " ?'%s'", tok->desc);
        vty_out(vty, " ");
 
-       if (stackpos == MAXDEPTH) {
+       if (stackpos == CMD_ARGC_MAX) {
                vty_out(vty, " -aborting! (depth limit)\n");
                return;
        }
@@ -586,7 +584,7 @@ static void pretty_print_dot(FILE *ofd, unsigned opts, struct graph_node *start,
                if (visited[i] == start)
                        return;
        visited[(*visitpos)++] = start;
-       if ((*visitpos) == MAXDEPTH * MAXDEPTH)
+       if ((*visitpos) == CMD_ARGC_MAX * CMD_ARGC_MAX)
                return;
 
        snprintf(tokennum, sizeof(tokennum), "%d?", tok->type);
@@ -626,7 +624,7 @@ static void pretty_print_dot(FILE *ofd, unsigned opts, struct graph_node *start,
        }
        fprintf(ofd, ">, style = filled, fillcolor = \"%s\" ];\n", color);
 
-       if (stackpos == MAXDEPTH)
+       if (stackpos == CMD_ARGC_MAX)
                return;
        stack[stackpos++] = start;
 
index 0fe7da1c0d532dfa72ccff91539f49d83b3e22ae..7866ddb8c446ffa08711d59dc4ce7b1b69c87e32 100644 (file)
--- a/lib/if.c
+++ b/lib/if.c
@@ -210,6 +210,9 @@ void if_delete(struct interface *ifp)
 
        if_link_params_free(ifp);
 
+       if (ifp->desc)
+               XFREE(MTYPE_TMP, ifp->desc);
+
        XFREE(MTYPE_IF, ifp);
 }
 
@@ -219,6 +222,18 @@ struct interface *if_lookup_by_index(ifindex_t ifindex, vrf_id_t vrf_id)
        struct vrf *vrf;
        struct interface if_tmp;
 
+       if (vrf_id == VRF_UNKNOWN) {
+               struct interface *ifp;
+
+               RB_FOREACH(vrf, vrf_id_head, &vrfs_by_id) {
+                       ifp = if_lookup_by_index(ifindex, vrf->vrf_id);
+                       if (ifp)
+                               return ifp;
+               }
+
+               return NULL;
+       }
+
        vrf = vrf_lookup_by_id(vrf_id);
        if (!vrf)
                return NULL;
@@ -663,8 +678,9 @@ DEFUN_NOSH (no_interface,
            "Interface's name\n"
            VRF_CMD_HELP_STR)
 {
+       int idx_vrf = 4;
        const char *ifname = argv[2]->arg;
-       const char *vrfname = (argc > 3) ? argv[3]->arg : NULL;
+       const char *vrfname = (argc > 3) ? argv[idx_vrf]->arg : NULL;
 
        // deleting interface
        struct interface *ifp;
index eb8af2041b21fdb0f8f62cde261cf2a9712c766c..79f96a7c452ee5306fd965a3668fe96ec5cc8648 100644 (file)
--- a/lib/if.h
+++ b/lib/if.h
@@ -452,6 +452,13 @@ struct nbr_connected {
 /* Prototypes. */
 extern int if_cmp_name_func(char *, char *);
 
+/*
+ * Passing in VRF_UNKNOWN is a valid thing to do, unless we
+ * are creating a new interface.
+ *
+ * This is useful for vrf route-leaking.  So more than anything
+ * else think before you use VRF_UNKNOWN
+ */
 extern void if_update_to_new_vrf(struct interface *, vrf_id_t vrf_id);
 extern struct interface *if_create(const char *name,  vrf_id_t vrf_id);
 extern struct interface *if_lookup_by_index(ifindex_t, vrf_id_t vrf_id);
index bb2c17335429cd2866b474291d5cc0ed71f6eae7..d9a09a3e416df0278b46ab17d4f93565e26009ef 100644 (file)
@@ -715,6 +715,24 @@ DEFUN (accept_lifetime_duration_month_day,
                argv[idx_number_3]->arg);
 }
 
+DEFUN (no_accept_lifetime,
+       no_accept_lifetime_cmd,
+       "no accept-lifetime",
+       NO_STR
+       "Unset accept-lifetime\n")
+{
+       VTY_DECLVAR_CONTEXT_SUB(key, key);
+
+       if (key->accept.start)
+               key->accept.start = 0;
+       if (key->accept.end)
+               key->accept.end = 0;
+       if (key->accept.duration)
+               key->accept.duration = 0;
+
+       return CMD_SUCCESS;
+}
+
 DEFUN (send_lifetime_day_month_day_month,
        send_lifetime_day_month_day_month_cmd,
        "send-lifetime HH:MM:SS (1-31) MONTH (1993-2035) HH:MM:SS (1-31) MONTH (1993-2035)",
@@ -925,6 +943,24 @@ DEFUN (send_lifetime_duration_month_day,
                argv[idx_number_3]->arg);
 }
 
+DEFUN (no_send_lifetime,
+       no_send_lifetime_cmd,
+       "no send-lifetime",
+       NO_STR
+       "Unset send-lifetime\n")
+{
+       VTY_DECLVAR_CONTEXT_SUB(key, key);
+
+       if (key->send.start)
+               key->send.start = 0;
+       if (key->send.end)
+               key->send.end = 0;
+       if (key->send.duration)
+               key->send.duration = 0;
+
+       return CMD_SUCCESS;
+}
+
 static struct cmd_node keychain_node = {KEYCHAIN_NODE, "%s(config-keychain)# ",
                                        1};
 
@@ -1047,6 +1083,8 @@ void keychain_init()
                        &accept_lifetime_duration_day_month_cmd);
        install_element(KEYCHAIN_KEY_NODE,
                        &accept_lifetime_duration_month_day_cmd);
+       install_element(KEYCHAIN_KEY_NODE,
+                       &no_accept_lifetime_cmd);
 
        install_element(KEYCHAIN_KEY_NODE,
                        &send_lifetime_day_month_day_month_cmd);
@@ -1064,4 +1102,6 @@ void keychain_init()
                        &send_lifetime_duration_day_month_cmd);
        install_element(KEYCHAIN_KEY_NODE,
                        &send_lifetime_duration_month_day_cmd);
+       install_element(KEYCHAIN_KEY_NODE,
+                       &no_send_lifetime_cmd);
 }
index 7589934b69420e031a91b729adea64d06b3f0e92..9fc19ff683bf70e23a1a0f7ea95d224994ea48eb 100644 (file)
--- a/lib/log.c
+++ b/lib/log.c
@@ -929,6 +929,7 @@ static const struct zebra_desc_table command_types[] = {
        DESC_ENTRY(ZEBRA_VRF_UNREGISTER),
        DESC_ENTRY(ZEBRA_VRF_ADD),
        DESC_ENTRY(ZEBRA_VRF_DELETE),
+       DESC_ENTRY(ZEBRA_VRF_LABEL),
        DESC_ENTRY(ZEBRA_INTERFACE_VRF_UPDATE),
        DESC_ENTRY(ZEBRA_BFD_CLIENT_REGISTER),
        DESC_ENTRY(ZEBRA_INTERFACE_ENABLE_RADV),
@@ -943,12 +944,17 @@ static const struct zebra_desc_table command_types[] = {
        DESC_ENTRY(ZEBRA_RELEASE_LABEL_CHUNK),
        DESC_ENTRY(ZEBRA_ADVERTISE_ALL_VNI),
        DESC_ENTRY(ZEBRA_ADVERTISE_DEFAULT_GW),
+       DESC_ENTRY(ZEBRA_ADVERTISE_SUBNET),
        DESC_ENTRY(ZEBRA_VNI_ADD),
        DESC_ENTRY(ZEBRA_VNI_DEL),
+       DESC_ENTRY(ZEBRA_L3VNI_ADD),
+       DESC_ENTRY(ZEBRA_L3VNI_DEL),
        DESC_ENTRY(ZEBRA_REMOTE_VTEP_ADD),
        DESC_ENTRY(ZEBRA_REMOTE_VTEP_DEL),
        DESC_ENTRY(ZEBRA_MACIP_ADD),
        DESC_ENTRY(ZEBRA_MACIP_DEL),
+       DESC_ENTRY(ZEBRA_IP_PREFIX_ROUTE_ADD),
+       DESC_ENTRY(ZEBRA_IP_PREFIX_ROUTE_DEL),
        DESC_ENTRY(ZEBRA_REMOTE_MACIP_ADD),
        DESC_ENTRY(ZEBRA_REMOTE_MACIP_DEL),
        DESC_ENTRY(ZEBRA_PW_ADD),
index cce67d7ec1d299e5d0a7cc9b9d904d90e36bb308..8989a93c597b2fb133c4e009b4f00fca5609a4b0 100644 (file)
--- a/lib/md5.c
+++ b/lib/md5.c
@@ -1,7 +1,3 @@
-/* $USAGI: md5.c,v 1.2 2000/11/02 11:59:24 yoshfuji Exp $ */
-/*     $KAME: md5.c,v 1.2 2000/05/27 07:07:48 jinmei Exp $     */
-/*     $Id: md5.c,v 1.6 2006/01/17 23:39:04 vincent Exp $ */
-
 /*
  * Copyright (C) 2004 6WIND
  *                          <Vincent.Jardin@6WIND.com>
index adc92d670da8abb0f65458ecb5844b5b90d935f9..59291c7df3bdd233f8fc510c9a50ea36bbbfb73e 100644 (file)
--- a/lib/md5.h
+++ b/lib/md5.h
@@ -1,7 +1,3 @@
-/* $USAGI: md5.h,v 1.2 2000/11/02 11:59:25 yoshfuji Exp $ */
-/*     $KAME: md5.h,v 1.4 2000/03/27 04:36:22 sumikawa Exp $   */
-/*     $Id: md5.h,v 1.3 2006/01/17 17:40:45 paul Exp $ */
-
 /*
  * Copyright (C) 2004 6WIND
  *                          <Vincent.Jardin@6WIND.com>
index bf98eecd81615adafe8b22f4002579a3610ba18a..1a1819c2c09096bf4a14afd156dfec77e0cfb072 100644 (file)
 
 #include <arpa/inet.h>
 
+#ifdef MPLS_LABEL_MAX
+#undef MPLS_LABEL_MAX
+#endif
+
 /* Well-known MPLS label values (RFC 3032 etc). */
-#define MPLS_V4_EXP_NULL_LABEL             0
-#define MPLS_RA_LABEL                      1
-#define MPLS_V6_EXP_NULL_LABEL             2
-#define MPLS_IMP_NULL_LABEL                3
-#define MPLS_ENTROPY_LABEL_INDICATOR       7
-#define MPLS_GAL_LABEL                     13
-#define MPLS_OAM_ALERT_LABEL               14
-#define MPLS_EXTENSION_LABEL               15
+#define MPLS_LABEL_IPV4_EXPLICIT_NULL  0       /* [RFC3032] */
+#define MPLS_LABEL_ROUTER_ALERT        1       /* [RFC3032] */
+#define MPLS_LABEL_IPV6_EXPLICIT_NULL  2       /* [RFC3032] */
+#define MPLS_LABEL_IMPLICIT_NULL       3       /* [RFC3032] */
+#define MPLS_LABEL_ELI                 7       /* [RFC6790] */
+#define MPLS_LABEL_GAL                 13      /* [RFC5586] */
+#define MPLS_LABEL_OAM_ALERT           14      /* [RFC3429] */
+#define MPLS_LABEL_EXTENSION           15      /* [RFC7274] */
+#define MPLS_LABEL_MAX                 1048575
+#define MPLS_LABEL_NONE                0xFFFFFFFF /* for internal use only */
 
 /* Minimum and maximum label values */
-#define MPLS_MIN_RESERVED_LABEL            0
-#define MPLS_MAX_RESERVED_LABEL            15
-#define MPLS_MIN_UNRESERVED_LABEL          16
-#define MPLS_MAX_UNRESERVED_LABEL          1048575
+#define MPLS_LABEL_RESERVED_MIN            0
+#define MPLS_LABEL_RESERVED_MAX            15
+#define MPLS_LABEL_UNRESERVED_MIN          16
+#define MPLS_LABEL_UNRESERVED_MAX          1048575
 
 /* Default min and max SRGB label range */
-#define MPLS_DEFAULT_MIN_SRGB_LABEL        16000
-#define MPLS_DEFAULT_MAX_SRGB_LABEL        23999
+/* Even if the SRGB allows to manage different Label space between routers,
+ * if an operator want to use the same SRGB for all its router, we must fix
+ * a common range. However, Cisco start its SRGB at 16000 and Juniper ends
+ * its SRGB at 16384 for OSPF. Thus, by fixing the minimum SRGB label to
+ * 8000 we could deal with both Cisco and Juniper.
+ */
+#define MPLS_DEFAULT_MIN_SRGB_LABEL        8000
+#define MPLS_DEFAULT_MAX_SRGB_LABEL        50000
+#define MPLS_DEFAULT_MIN_SRGB_SIZE         5000
+#define MPLS_DEFAULT_MAX_SRGB_SIZE         20000
 
 /* Maximum # labels that can be pushed. */
 #define MPLS_MAX_LABELS                    16
 
 #define IS_MPLS_RESERVED_LABEL(label)                                          \
-       (label >= MPLS_MIN_RESERVED_LABEL && label <= MPLS_MAX_RESERVED_LABEL)
+       (label >= MPLS_LABEL_RESERVED_MIN && label <= MPLS_LABEL_RESERVED_MAX)
 
 #define IS_MPLS_UNRESERVED_LABEL(label)                                        \
-       (label >= MPLS_MIN_UNRESERVED_LABEL                                    \
-        && label <= MPLS_MAX_UNRESERVED_LABEL)
+       (label >= MPLS_LABEL_UNRESERVED_MIN                                    \
+        && label <= MPLS_LABEL_UNRESERVED_MAX)
 
 /* Definitions for a MPLS label stack entry (RFC 3032). This encodes the
  * label, EXP, BOS and TTL fields.
@@ -81,6 +95,12 @@ typedef unsigned int mpls_lse_t;
 /* MPLS label value as a 32-bit (mostly we only care about the label value). */
 typedef unsigned int mpls_label_t;
 
+struct mpls_label_stack {
+       uint8_t num_labels;
+       uint8_t reserved[3];
+       mpls_label_t label[0]; /* 1 or more labels */
+};
+
 /* The MPLS explicit-null label is 0 which means when you memset a mpls_label_t
  * to zero you have set that variable to explicit-null which was probably not
  * your intent. The work-around is to use one bit to indicate if the
@@ -94,7 +114,9 @@ enum lsp_types_t {
        ZEBRA_LSP_NONE = 0,   /* No LSP. */
        ZEBRA_LSP_STATIC = 1, /* Static LSP. */
        ZEBRA_LSP_LDP = 2,    /* LDP LSP. */
-       ZEBRA_LSP_BGP = 3     /* BGP LSP. */
+       ZEBRA_LSP_BGP = 3,    /* BGP LSP. */
+       ZEBRA_LSP_SR = 4,     /* Segment Routing LSP. */
+       ZEBRA_LSP_SHARP = 5,  /* Identifier for test protocol */
 };
 
 /* Functions for basic label operations. */
@@ -138,28 +160,28 @@ static inline void mpls_lse_decode(mpls_lse_t lse, mpls_label_t *label,
 static inline char *label2str(mpls_label_t label, char *buf, size_t len)
 {
        switch (label) {
-       case MPLS_V4_EXP_NULL_LABEL:
+       case MPLS_LABEL_IPV4_EXPLICIT_NULL:
                strlcpy(buf, "IPv4 Explicit Null", len);
                return (buf);
-       case MPLS_RA_LABEL:
+       case MPLS_LABEL_ROUTER_ALERT:
                strlcpy(buf, "Router Alert", len);
                return (buf);
-       case MPLS_V6_EXP_NULL_LABEL:
+       case MPLS_LABEL_IPV6_EXPLICIT_NULL:
                strlcpy(buf, "IPv6 Explict Null", len);
                return (buf);
-       case MPLS_IMP_NULL_LABEL:
+       case MPLS_LABEL_IMPLICIT_NULL:
                strlcpy(buf, "implicit-null", len);
                return (buf);
-       case MPLS_ENTROPY_LABEL_INDICATOR:
+       case MPLS_LABEL_ELI:
                strlcpy(buf, "Entropy Label Indicator", len);
                return (buf);
-       case MPLS_GAL_LABEL:
+       case MPLS_LABEL_GAL:
                strlcpy(buf, "Generic Associated Channel", len);
                return (buf);
-       case MPLS_OAM_ALERT_LABEL:
+       case MPLS_LABEL_OAM_ALERT:
                strlcpy(buf, "OAM Alert", len);
                return (buf);
-       case MPLS_EXTENSION_LABEL:
+       case MPLS_LABEL_EXTENSION:
                strlcpy(buf, "Extension", len);
                return (buf);
        default:
@@ -171,13 +193,5 @@ static inline char *label2str(mpls_label_t label, char *buf, size_t len)
        }
 }
 
-/* constants used by ldpd */
-#define MPLS_LABEL_IPV4NULL    0               /* IPv4 Explicit NULL Label */
-#define MPLS_LABEL_RTALERT     1               /* Router Alert Label       */
-#define MPLS_LABEL_IPV6NULL    2               /* IPv6 Explicit NULL Label */
-#define MPLS_LABEL_IMPLNULL    3               /* Implicit NULL Label      */
-       /*      MPLS_LABEL_RESERVED     4-15 */ /* Values 4-15 are reserved */
-#define MPLS_LABEL_RESERVED_MAX 15
-#define MPLS_LABEL_MAX         ((1 << 20) - 1)
 
 #endif
index f6b2c9788d50a4757649f76d12b593ad821cbcbb..a094c0e38da624f04badeca8e10ce60c7beccf93 100644 (file)
@@ -124,7 +124,7 @@ const char *nexthop_type_to_str(enum nexthop_types_t nh_type)
  */
 int nexthop_labels_match(struct nexthop *nh1, struct nexthop *nh2)
 {
-       struct nexthop_label *nhl1, *nhl2;
+       struct mpls_label_stack *nhl1, *nhl2;
 
        nhl1 = nh1->nh_label;
        nhl2 = nh2->nh_label;
@@ -167,6 +167,7 @@ void copy_nexthops(struct nexthop **tnh, struct nexthop *nh,
 
        for (nh1 = nh; nh1; nh1 = nh1->next) {
                nexthop = nexthop_new();
+               nexthop->vrf_id = nh1->vrf_id;
                nexthop->ifindex = nh1->ifindex;
                nexthop->type = nh1->type;
                nexthop->flags = nh1->flags;
@@ -210,12 +211,12 @@ void nexthops_free(struct nexthop *nexthop)
 void nexthop_add_labels(struct nexthop *nexthop, enum lsp_types_t type,
                        u_int8_t num_labels, mpls_label_t *label)
 {
-       struct nexthop_label *nh_label;
+       struct mpls_label_stack *nh_label;
        int i;
 
        nexthop->nh_label_type = type;
        nh_label = XCALLOC(MTYPE_NH_LABEL,
-                          sizeof(struct nexthop_label)
+                          sizeof(struct mpls_label_stack)
                                   + num_labels * sizeof(mpls_label_t));
        nh_label->num_labels = num_labels;
        for (i = 0; i < num_labels; i++)
index 20b0cd522773b96760b980c75fb0ceb9794d1476..b502f293bc478cb911e027d7222832a20584f3ce 100644 (file)
@@ -55,18 +55,16 @@ enum blackhole_type {
        ((type) == NEXTHOP_TYPE_IFINDEX || (type) == NEXTHOP_TYPE_BLACKHOLE) \
                ? (type) : ((type) | 1)
 
-/* Nexthop label structure. */
-struct nexthop_label {
-       u_int8_t num_labels;
-       u_int8_t reserved[3];
-       mpls_label_t label[0]; /* 1 or more labels. */
-};
-
 /* Nexthop structure. */
 struct nexthop {
        struct nexthop *next;
        struct nexthop *prev;
 
+       /*
+        * What vrf is this nexthop associated with?
+        */
+       vrf_id_t vrf_id;
+
        /* Interface index. */
        ifindex_t ifindex;
 
@@ -80,6 +78,7 @@ struct nexthop {
 #define NEXTHOP_FLAG_MATCHED    (1 << 4) /* Already matched vs a nexthop */
 #define NEXTHOP_FLAG_FILTERED   (1 << 5) /* rmap filtered, used by static only */
 #define NEXTHOP_FLAG_DUPLICATE  (1 << 6) /* nexthop duplicates another active one */
+#define NEXTHOP_FLAG_EVPN_RVTEP (1 << 7) /* EVPN remote vtep nexthop */
 #define NEXTHOP_IS_ACTIVE(flags) \
        (CHECK_FLAG(flags, NEXTHOP_FLAG_ACTIVE) \
                && !CHECK_FLAG(flags, NEXTHOP_FLAG_DUPLICATE))
@@ -106,7 +105,7 @@ struct nexthop {
        enum lsp_types_t nh_label_type;
 
        /* Label(s) associated with this nexthop. */
-       struct nexthop_label *nh_label;
+       struct mpls_label_stack *nh_label;
 };
 
 /* The following for loop allows to iterate over the nexthop
@@ -122,18 +121,6 @@ struct nexthop {
        (nexthop);                                                             \
        (nexthop) = nexthop_next(nexthop)
 
-extern int zebra_rnh_ip_default_route;
-extern int zebra_rnh_ipv6_default_route;
-
-static inline int nh_resolve_via_default(int family)
-{
-       if (((family == AF_INET) && zebra_rnh_ip_default_route)
-           || ((family == AF_INET6) && zebra_rnh_ipv6_default_route))
-               return 1;
-       else
-               return 0;
-}
-
 struct nexthop *nexthop_new(void);
 void nexthop_add(struct nexthop **target, struct nexthop *nexthop);
 
index c492d6600bed18a1a007509679a26cbf1f6974aa..79b4cab04d03c8bb5e3b2d187f2ca2c0faf43b5f 100644 (file)
--- a/lib/ns.h
+++ b/lib/ns.h
 #include "openbsd-tree.h"
 #include "linklist.h"
 
-typedef u_int16_t ns_id_t;
+typedef u_int32_t ns_id_t;
 
-/* The default NS ID */
+/* the default NS ID */
 #define NS_DEFAULT 0
+#define NS_UNKNOWN UINT32_MAX
 
 /* Default netns directory (Linux) */
 #define NS_RUN_DIR         "/var/run/netns"
index 10f77bda875ad4c2d58dd2837592e25b595b1ed7..9f13cb8bb13b75b2a124fb326c64ea49bdcd37ea 100644 (file)
@@ -301,7 +301,7 @@ static const struct in6_addr maskbytes6[] = {
 
 #define MASKBIT(offset)  ((0xff << (PNBBY - (offset))) & 0xff)
 
-static int is_zero_mac(const struct ethaddr *mac)
+int is_zero_mac(struct ethaddr *mac)
 {
        int i = 0;
 
@@ -1043,10 +1043,11 @@ static const char *prefixevpn2str(const struct prefix *p, char *str, int size)
                family = IS_EVPN_PREFIX_IPADDR_V4((struct prefix_evpn *)p)
                                 ? AF_INET
                                 : AF_INET6;
-               snprintf(str, size, "[%d]:[%u][%s]/%d",
+               snprintf(str, size, "[%d]:[%u][%s/%d]/%d",
                         p->u.prefix_evpn.route_type, p->u.prefix_evpn.eth_tag,
                         inet_ntop(family, &p->u.prefix_evpn.ip.ip.addr, buf,
                                   PREFIX2STR_BUFFER),
+                        p->u.prefix_evpn.ip_prefix_length,
                         p->prefixlen);
        } else {
                sprintf(str, "Unsupported EVPN route type %d",
index 0732cf12905a6489cf31d65093d711870d1b349f..5bf7d498c1ca7073e8f34b1a8870e0c332c2563b 100644 (file)
 #define ETH_ALEN 6
 #endif
 
-/* for compatibility */
-#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*ETH_ALEN)
 /*
  * there isn't a portable ethernet address type. We define our
@@ -245,6 +239,7 @@ static inline void ipv4_addr_copy(struct in_addr *dst,
 #define IPV4_NET127(a)  ((((u_int32_t) (a)) & 0xff000000) == 0x7f000000)
 #define IPV4_LINKLOCAL(a) ((((u_int32_t) (a)) & 0xffff0000) == 0xa9fe0000)
 #define IPV4_CLASS_DE(a)  ((((u_int32_t) (a)) & 0xe0000000) == 0xe0000000)
+#define IPV4_MC_LINKLOCAL(a)  ((((u_int32_t) (a)) & 0xffffff00) == 0xe0000000)
 
 /* Max bit/byte length of IPv6 address. */
 #define IPV6_MAX_BYTELEN    16
@@ -348,6 +343,7 @@ extern void masklen2ip6(const int, struct in6_addr *);
 
 extern const char *inet6_ntoa(struct in6_addr);
 
+extern int is_zero_mac(struct ethaddr *mac);
 extern int prefix_str2mac(const char *str, struct ethaddr *mac);
 extern char *prefix_mac2str(const struct ethaddr *mac, char *buf, int size);
 
@@ -398,4 +394,13 @@ static inline int is_default_prefix(const struct prefix *p)
        return 0;
 }
 
+static inline int is_host_route(struct prefix *p)
+{
+       if (p->family == AF_INET)
+               return (p->prefixlen == IPV4_MAX_BITLEN);
+       else if (p->family == AF_INET6)
+               return (p->prefixlen == IPV6_MAX_BITLEN);
+       return 0;
+}
+
 #endif /* _ZEBRA_PREFIX_H */
index 28d26149e5d39afc6f3107c67d8a49d0d4333266..fea5a8cc4015ba6ac858dc1f8a91891b67bcd5e4 100644 (file)
@@ -120,7 +120,7 @@ static int _ptm_lib_decode_header(csv_t *csv, int *msglen, int *version,
        }
        /* remove leading spaces */
        for (i = j = 0; i < csv_field_len(fld); i++) {
-               if (!isspace(hdr[i])) {
+               if (!isspace((int)hdr[i])) {
                        client_name[j] = hdr[i];
                        j++;
                }
@@ -347,7 +347,7 @@ int ptm_lib_process_msg(ptm_lib_handle_t *hdl, int fd, char *inbuf, int inlen,
 {
        int rc, len;
        char client_name[32];
-       int cmd_id, type, ver, msglen;
+       int cmd_id = 0, type = 0, ver = 0, msglen = 0;
        csv_t *csv;
        ptm_lib_msg_ctxt_t *p_ctxt = NULL;
 
diff --git a/lib/ringbuf.c b/lib/ringbuf.c
new file mode 100644 (file)
index 0000000..11db502
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * Circular buffer implementation.
+ * Copyright (C) 2017 Cumulus Networks
+ * Quentin Young
+ *
+ * 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 "ringbuf.h"
+#include "memory.h"
+
+DEFINE_MTYPE_STATIC(LIB, RINGBUFFER, "Ring buffer")
+
+struct ringbuf *ringbuf_new(size_t size)
+{
+       struct ringbuf *buf = XCALLOC(MTYPE_RINGBUFFER, sizeof(struct ringbuf));
+       buf->data = XCALLOC(MTYPE_RINGBUFFER, size);
+       buf->size = size;
+       buf->empty = true;
+       return buf;
+}
+
+void ringbuf_del(struct ringbuf *buf)
+{
+       XFREE(MTYPE_RINGBUFFER, buf->data);
+       XFREE(MTYPE_RINGBUFFER, buf);
+}
+
+size_t ringbuf_remain(struct ringbuf *buf)
+{
+       ssize_t diff = buf->end - buf->start;
+       diff += ((diff == 0) && !buf->empty) ? buf->size : 0;
+       diff += (diff < 0) ? buf->size : 0;
+       return (size_t)diff;
+}
+
+size_t ringbuf_space(struct ringbuf *buf)
+{
+       return buf->size - ringbuf_remain(buf);
+}
+
+size_t ringbuf_put(struct ringbuf *buf, const void *data, size_t size)
+{
+       const uint8_t *dp = data;
+       size_t space = ringbuf_space(buf);
+       size_t copysize = MIN(size, space);
+       size_t tocopy = copysize;
+       if (tocopy >= buf->size - buf->end) {
+               size_t ts = buf->size - buf->end;
+               memcpy(buf->data + buf->end, dp, ts);
+               buf->end = 0;
+               tocopy -= ts;
+               dp += ts;
+       }
+       memcpy(buf->data + buf->end, dp, tocopy);
+       buf->end += tocopy;
+       buf->empty = (buf->start == buf->end) && (buf->empty && !copysize);
+       return copysize;
+}
+
+size_t ringbuf_get(struct ringbuf *buf, void *data, size_t size)
+{
+       uint8_t *dp = data;
+       size_t remain = ringbuf_remain(buf);
+       size_t copysize = MIN(remain, size);
+       size_t tocopy = copysize;
+       if (tocopy >= buf->size - buf->start) {
+               size_t ts = buf->size - buf->start;
+               memcpy(dp, buf->data + buf->start, ts);
+               buf->start = 0;
+               tocopy -= ts;
+               dp += ts;
+       }
+       memcpy(dp, buf->data + buf->start, tocopy);
+       buf->start = buf->start + tocopy;
+       buf->empty = (buf->start == buf->end) && (buf->empty || copysize);
+       return copysize;
+}
+
+size_t ringbuf_peek(struct ringbuf *buf, size_t offset, void *data, size_t size)
+{
+       uint8_t *dp = data;
+       size_t remain = ringbuf_remain(buf);
+       if (offset >= remain)
+               return 0;
+       size_t copysize = MAX(MIN(remain - offset, size), (size_t) 0);
+       size_t tocopy = copysize;
+       size_t cstart = (buf->start + offset) % buf->size;
+       if (tocopy >= buf->size - cstart) {
+               size_t ts = buf->size - cstart;
+               memcpy(dp, buf->data + cstart, ts);
+               cstart = 0;
+               tocopy -= ts;
+               dp += ts;
+       }
+       memcpy(dp, buf->data + cstart, tocopy);
+       return copysize;
+}
+
+size_t ringbuf_copy(struct ringbuf *to, struct ringbuf *from, size_t size)
+{
+       size_t tocopy = MIN(ringbuf_space(to), size);
+       uint8_t *cbuf = XCALLOC(MTYPE_TMP, tocopy);
+       tocopy = ringbuf_peek(from, 0, cbuf, tocopy);
+       size_t put = ringbuf_put(to, cbuf, tocopy);
+       XFREE(MTYPE_TMP, cbuf);
+       return put;
+}
+
+void ringbuf_reset(struct ringbuf *buf)
+{
+       buf->start = buf->end = 0;
+       buf->empty = true;
+}
+
+void ringbuf_wipe(struct ringbuf *buf)
+{
+       memset(buf->data, 0x00, buf->size);
+       ringbuf_reset(buf);
+}
diff --git a/lib/ringbuf.h b/lib/ringbuf.h
new file mode 100644 (file)
index 0000000..15049e3
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * Circular buffer implementation.
+ * Copyright (C) 2017 Cumulus Networks
+ * Quentin Young
+ *
+ * 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_RINGBUF_H_
+#define _FRR_RINGBUF_H_
+
+#include <zebra.h>
+#include <stdint.h>
+
+#include "memory.h"
+
+struct ringbuf {
+       size_t size;
+       ssize_t start;
+       ssize_t end;
+       bool empty;
+       uint8_t *data;
+};
+
+/*
+ * Creates a new ring buffer.
+ *
+ * @param size buffer size, in bytes
+ * @return the newly created buffer
+ */
+struct ringbuf *ringbuf_new(size_t size);
+
+/*
+ * Deletes a ring buffer and frees all associated resources.
+ *
+ * @param buf  the ring buffer to destroy
+ */
+void ringbuf_del(struct ringbuf *buf);
+
+/*
+ * Get amount of data left to read from the buffer.
+ *
+ * @return number of readable bytes
+ */
+size_t ringbuf_remain(struct ringbuf *buf);
+
+/*
+ * Get amount of space left to write to the buffer
+ *
+ * @return number of writeable bytes
+ */
+size_t ringbuf_space(struct ringbuf *buf);
+
+
+/*
+ * Put data into the ring buffer.
+ *
+ * @param data the data to put in the buffer
+ * @param size how much of data to put in
+ * @return number of bytes written; will be less than size if there was not
+ * enough space
+ */
+size_t ringbuf_put(struct ringbuf *buf, const void *data, size_t size);
+
+/*
+ * Get data from the ring buffer.
+ *
+ * @param data where to put the data
+ * @param size how much of data to get
+ * @return number of bytes read into data; will be less than size if there was
+ * not enough data to read
+ */
+size_t ringbuf_get(struct ringbuf *buf, void *data, size_t size);
+
+/*
+ * Peek data from the ring buffer.
+ *
+ * @param offset       where to get the data from, in bytes offset from the
+ *                     start of the data
+ * @param data         where to put the data
+ * @param size         how much data to get
+ * @return             number of bytes read into data; will be less than size
+ *                     if there was not enough data to read; will be -1 if the
+ *                     offset exceeds the amount of data left in the ring
+ *                     buffer
+ */
+size_t ringbuf_peek(struct ringbuf *buf, size_t offset, void *data,
+                   size_t size);
+
+/*
+ * Copy data from one ringbuf to another.
+ *
+ * @param to   destination ringbuf
+ * @param from source ringbuf
+ * @param size how much data to copy
+ * @return amount of data copied
+ */
+size_t ringbuf_copy(struct ringbuf *to, struct ringbuf *from, size_t size);
+
+/*
+ * Reset buffer. Does not wipe.
+ *
+ * @param buf
+ */
+void ringbuf_reset(struct ringbuf *buf);
+
+/*
+ * Reset buffer. Wipes.
+ *
+ * @param buf
+ */
+void ringbuf_wipe(struct ringbuf *buf);
+
+#endif /* _FRR_RINGBUF_H_ */
index 92b7620edac5cd3ab3f76bb7f8dc379b93722557..d7907fafdf7ff26caf858dceb8e043eefeeb971c 100644 (file)
@@ -205,7 +205,7 @@ static const char *timeval_format(struct timeval *tv)
 
        size_t offset = strlen(timebuf);
        snprintf(timebuf + offset, sizeof(timebuf) - offset, ".%ld",
-                tv->tv_usec);
+                (long int)tv->tv_usec);
 
        return timebuf;
 }
index c8eddc8e25b5c2831e98475f2893e1c846df2890..44870917bd3c9060fc4e373be7ee7a3271234eef 100644 (file)
@@ -51,6 +51,7 @@ lib_libfrr_la_SOURCES = \
        lib/privs.c \
        lib/ptm_lib.c \
        lib/qobj.c \
+       lib/ringbuf.c \
        lib/routemap.c \
        lib/sbuf.c \
        lib/sha256.c \
@@ -130,6 +131,7 @@ pkginclude_HEADERS += \
        lib/pw.h \
        lib/qobj.h \
        lib/queue.h \
+       lib/ringbuf.h \
        lib/routemap.h \
        lib/sbuf.h \
        lib/sha256.h \
index d26db8855029a2c2346044621f32396987016d2f..9d64663d9c0de829aba030b68c61569e856a7a77 100644 (file)
@@ -919,6 +919,8 @@ struct thread *funcname_thread_add_event(struct thread_master *m,
  */
 static void thread_cancel_rw(struct thread_master *master, int fd, short state)
 {
+       bool found = false;
+
        /* Cancel POLLHUP too just in case some bozo set it */
        state |= POLLHUP;
 
@@ -926,8 +928,18 @@ static void thread_cancel_rw(struct thread_master *master, int fd, short state)
        nfds_t i;
 
        for (i = 0; i < master->handler.pfdcount; i++)
-               if (master->handler.pfds[i].fd == fd)
+               if (master->handler.pfds[i].fd == fd) {
+                       found = true;
                        break;
+               }
+
+       if (!found) {
+               zlog_debug(
+                       "[!] Received cancellation request for nonexistent rw job");
+               zlog_debug("[!] threadmaster: %s | fd: %d",
+                        master->name ? master->name : "", fd);
+               return;
+       }
 
        /* NOT out event. */
        master->handler.pfds[i].events &= ~(state);
index 056f778a3e41fad559d19309a6012df5c9b7c00f..2e15fa2f5c2c0c884b99cd6f2fdc0b68d3e1ab79 100644 (file)
--- a/lib/vrf.c
+++ b/lib/vrf.c
@@ -94,7 +94,7 @@ struct vrf *vrf_get(vrf_id_t vrf_id, const char *name)
        int new = 0;
 
        if (debug_vrf)
-               zlog_debug("VRF_GET: %s(%d)", name, vrf_id);
+               zlog_debug("VRF_GET: %s(%u)", name, vrf_id);
 
        /* Nothing to see, move along here */
        if (!name && vrf_id == VRF_UNKNOWN)
@@ -141,7 +141,9 @@ struct vrf *vrf_get(vrf_id_t vrf_id, const char *name)
        return vrf;
 }
 
-/* Delete a VRF. This is called in vrf_terminate(). */
+/* Delete a VRF. This is called when the underlying VRF goes away, a
+ * pre-configured VRF is deleted or when shutting down (vrf_terminate()).
+ */
 void vrf_delete(struct vrf *vrf)
 {
        if (debug_vrf)
@@ -150,6 +152,23 @@ void vrf_delete(struct vrf *vrf)
        if (vrf_is_enabled(vrf))
                vrf_disable(vrf);
 
+       /* If the VRF is user configured, it'll stick around, just remove
+        * the ID mapping. Interfaces assigned to this VRF should've been
+        * removed already as part of the VRF going down.
+        */
+       if (vrf_is_user_cfged(vrf)) {
+               if (vrf->vrf_id != VRF_UNKNOWN) {
+                       /* Delete any VRF interfaces - should be only
+                        * the VRF itself, other interfaces should've
+                        * been moved out of the VRF.
+                        */
+                       if_terminate(vrf);
+                       RB_REMOVE(vrf_id_head, &vrfs_by_id, vrf);
+                       vrf->vrf_id = VRF_UNKNOWN;
+               }
+               return;
+       }
+
        if (vrf_master.vrf_delete_hook)
                (*vrf_master.vrf_delete_hook)(vrf);
 
@@ -172,14 +191,6 @@ struct vrf *vrf_lookup_by_id(vrf_id_t vrf_id)
        return (RB_FIND(vrf_id_head, &vrfs_by_id, &vrf));
 }
 
-/*
- * Check whether the VRF is enabled.
- */
-static int vrf_is_enabled(struct vrf *vrf)
-{
-       return vrf && CHECK_FLAG(vrf->status, VRF_ACTIVE);
-}
-
 /*
  * Enable a VRF - that is, let the VRF be ready to use.
  * The VRF_ENABLE_HOOK callback will be called to inform
@@ -225,6 +236,17 @@ static void vrf_disable(struct vrf *vrf)
                (*vrf_master.vrf_disable_hook)(vrf);
 }
 
+const char *vrf_id_to_name(vrf_id_t vrf_id)
+{
+       struct vrf *vrf;
+
+       vrf = vrf_lookup_by_id(vrf_id);
+       if (vrf)
+               return vrf->name;
+
+       return "n/a";
+}
+
 vrf_id_t vrf_name_to_id(const char *name)
 {
        struct vrf *vrf;
@@ -256,8 +278,8 @@ void *vrf_info_lookup(vrf_id_t vrf_id)
  * VRF bit-map
  */
 
-#define VRF_BITMAP_NUM_OF_GROUPS            8
-#define VRF_BITMAP_NUM_OF_BITS_IN_GROUP (UINT16_MAX / VRF_BITMAP_NUM_OF_GROUPS)
+#define VRF_BITMAP_NUM_OF_GROUPS            1024
+#define VRF_BITMAP_NUM_OF_BITS_IN_GROUP (UINT32_MAX / VRF_BITMAP_NUM_OF_GROUPS)
 #define VRF_BITMAP_NUM_OF_BYTES_IN_GROUP                                       \
        (VRF_BITMAP_NUM_OF_BITS_IN_GROUP / CHAR_BIT + 1) /* +1 for ensure */
 
@@ -344,7 +366,7 @@ static void vrf_autocomplete(vector comps, struct cmd_token *token)
        struct vrf *vrf = NULL;
 
        RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
-               if (vrf->vrf_id != 0)
+               if (vrf->vrf_id != VRF_DEFAULT)
                        vector_set(comps, XSTRDUP(MTYPE_COMPLETION, vrf->name));
        }
 }
@@ -397,10 +419,16 @@ void vrf_terminate(void)
                zlog_debug("%s: Shutting down vrf subsystem",
                           __PRETTY_FUNCTION__);
 
-       while ((vrf = RB_ROOT(vrf_id_head, &vrfs_by_id)) != NULL)
+       while ((vrf = RB_ROOT(vrf_id_head, &vrfs_by_id)) != NULL) {
+               /* Clear configured flag and invoke delete. */
+               UNSET_FLAG(vrf->status, VRF_CONFIGURED);
                vrf_delete(vrf);
-       while ((vrf = RB_ROOT(vrf_name_head, &vrfs_by_name)) != NULL)
+       }
+       while ((vrf = RB_ROOT(vrf_name_head, &vrfs_by_name)) != NULL) {
+               /* Clear configured flag and invoke delete. */
+               UNSET_FLAG(vrf->status, VRF_CONFIGURED);
                vrf_delete(vrf);
+       }
 }
 
 /* Create a socket for the VRF. */
@@ -462,6 +490,8 @@ DEFUN_NOSH (no_vrf,
                return CMD_WARNING_CONFIG_FAILED;
        }
 
+       /* Clear configured flag and invoke delete. */
+       UNSET_FLAG(vrfp->status, VRF_CONFIGURED);
        vrf_delete(vrfp);
 
        return CMD_SUCCESS;
index e93e9937769437f47c9c97241dca8a4f9a48b8f1..99c048c7025361987d7ab700fb05d0a2dff2b740 100644 (file)
--- a/lib/vrf.h
+++ b/lib/vrf.h
@@ -32,8 +32,7 @@
 
 /* The default VRF ID */
 #define VRF_DEFAULT 0
-#define VRF_UNKNOWN UINT16_MAX
-#define VRF_ALL UINT16_MAX - 1
+#define VRF_UNKNOWN UINT32_MAX
 
 /* Pending: May need to refine this. */
 #ifndef IFLA_VRF_MAX
@@ -76,7 +75,8 @@ struct vrf {
 
        /* Zebra internal VRF status */
        u_char status;
-#define VRF_ACTIVE     (1 << 0)
+#define VRF_ACTIVE     (1 << 0) /* VRF is up in kernel */
+#define VRF_CONFIGURED (1 << 1) /* VRF has some FRR configuration */
 
        /* Interfaces belonging to this VRF */
        struct if_name_head ifaces_by_name;
@@ -103,6 +103,7 @@ extern struct vrf_name_head vrfs_by_name;
 extern struct vrf *vrf_lookup_by_id(vrf_id_t);
 extern struct vrf *vrf_lookup_by_name(const char *);
 extern struct vrf *vrf_get(vrf_id_t, const char *);
+extern const char *vrf_id_to_name(vrf_id_t vrf_id);
 extern vrf_id_t vrf_name_to_id(const char *);
 
 #define VRF_GET_ID(V, NAME)                                                    \
@@ -119,6 +120,32 @@ extern vrf_id_t vrf_name_to_id(const char *);
                (V) = vrf->vrf_id;                                             \
        } while (0)
 
+/*
+ * Check whether the VRF is enabled.
+ */
+static inline int vrf_is_enabled(struct vrf *vrf)
+{
+       return vrf && CHECK_FLAG(vrf->status, VRF_ACTIVE);
+}
+
+/* check if the vrf is user configured */
+static inline int vrf_is_user_cfged(struct vrf *vrf)
+{
+       return vrf && CHECK_FLAG(vrf->status, VRF_CONFIGURED);
+}
+
+/* Mark that VRF has user configuration */
+static inline void vrf_set_user_cfged(struct vrf *vrf)
+{
+       SET_FLAG(vrf->status, VRF_CONFIGURED);
+}
+
+/* Mark that VRF no longer has any user configuration */
+static inline void vrf_reset_user_cfged(struct vrf *vrf)
+{
+       UNSET_FLAG(vrf->status, VRF_CONFIGURED);
+}
+
 /*
  * Utilities to obtain the user data
  */
index 4026e0cf8ab1a389d3cd7b93fe14526326e560df..43a53b773288266b67f1418669cb7d24f8b49ec6 100644 (file)
--- a/lib/vty.c
+++ b/lib/vty.c
@@ -732,7 +732,6 @@ static void vty_end_config(struct vty *vty)
        case KEYCHAIN_NODE:
        case KEYCHAIN_KEY_NODE:
        case MASC_NODE:
-       case PIM_NODE:
        case VTY_NODE:
        case BGP_EVPN_VNI_NODE:
                vty_config_unlock(vty);
@@ -1130,7 +1129,6 @@ static void vty_stop_input(struct vty *vty)
        case KEYCHAIN_NODE:
        case KEYCHAIN_KEY_NODE:
        case MASC_NODE:
-       case PIM_NODE:
        case VTY_NODE:
                vty_config_unlock(vty);
                vty->node = ENABLE_NODE;
index 5c06d933e6fb277d38d9d537f793c5354e728d94..d45e1be5f8392c26e8fdff60609fffd38daca7d8 100644 (file)
@@ -1,6 +1,4 @@
 /*
- * $Id: zassert.h,v 1.2 2004/12/03 18:01:04 ajs Exp $
- *
  * This file is part of Quagga.
  *
  * Quagga is free software; you can redistribute it and/or modify it
index 655e4e1a800ea7365e200efc29c3632d00d8d76a..714888a3f3f260625fe4621c5de3828e38cd2e64 100644 (file)
@@ -291,7 +291,7 @@ void zclient_create_header(struct stream *s, uint16_t command, vrf_id_t vrf_id)
        stream_putw(s, ZEBRA_HEADER_SIZE);
        stream_putc(s, ZEBRA_HEADER_MARKER);
        stream_putc(s, ZSERV_VERSION);
-       stream_putw(s, vrf_id);
+       stream_putl(s, vrf_id);
        stream_putw(s, command);
 }
 
@@ -306,7 +306,7 @@ int zclient_read_header(struct stream *s, int sock, u_int16_t *size,
        *size -= ZEBRA_HEADER_SIZE;
        STREAM_GETC(s, *marker);
        STREAM_GETC(s, *version);
-       STREAM_GETW(s, *vrf_id);
+       STREAM_GETL(s, *vrf_id);
        STREAM_GETW(s, *cmd);
 
        if (*version != ZSERV_VERSION || *marker != ZEBRA_HEADER_MARKER) {
@@ -363,6 +363,22 @@ static int zebra_hello_send(struct zclient *zclient)
        return 0;
 }
 
+void zclient_send_vrf_label(struct zclient *zclient, vrf_id_t vrf_id, afi_t afi,
+                           mpls_label_t label, enum lsp_types_t ltype)
+{
+       struct stream *s;
+
+       s = zclient->obuf;
+       stream_reset(s);
+
+       zclient_create_header(s, ZEBRA_VRF_LABEL, vrf_id);
+       stream_putl(s, label);
+       stream_putc(s, afi);
+       stream_putc(s, ltype);
+       stream_putw_at(s, 0, stream_get_endp(s));
+       zclient_send_message(zclient);
+}
+
 /* Send register requests to zebra daemon for the information in a VRF. */
 void zclient_send_reg_requests(struct zclient *zclient, vrf_id_t vrf_id)
 {
@@ -389,25 +405,28 @@ void zclient_send_reg_requests(struct zclient *zclient, vrf_id_t vrf_id)
                               vrf_id);
 
        /* Flush all redistribute request. */
-       if (vrf_id == VRF_DEFAULT)
-               for (afi = AFI_IP; afi < AFI_MAX; afi++)
-                       for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
-                               if (zclient->mi_redist[afi][i].enabled) {
-                                       struct listnode *node;
-                                       u_short *id;
-
-                                       for (ALL_LIST_ELEMENTS_RO(
-                                                    zclient->mi_redist[afi][i]
-                                                            .instances,
-                                                    node, id))
-                                               if (!(i == zclient->redist_default
-                                                     && *id == zclient->instance))
-                                                       zebra_redistribute_send(
-                                                               ZEBRA_REDISTRIBUTE_ADD,
-                                                               zclient, afi, i,
-                                                               *id,
-                                                               VRF_DEFAULT);
-                               }
+       if (vrf_id == VRF_DEFAULT) {
+               for (afi = AFI_IP; afi < AFI_MAX; afi++) {
+                       for (i = 0; i < ZEBRA_ROUTE_MAX; i++) {
+                               if (!zclient->mi_redist[afi][i].enabled)
+                                       continue;
+
+                               struct listnode *node;
+                               u_short *id;
+
+                               for (ALL_LIST_ELEMENTS_RO(
+                                            zclient->mi_redist[afi][i]
+                                            .instances, node, id))
+                                       if (!(i == zclient->redist_default
+                                             && *id == zclient->instance))
+                                               zebra_redistribute_send(
+                                                       ZEBRA_REDISTRIBUTE_ADD,
+                                                       zclient, afi, i,
+                                                       *id,
+                                                       VRF_DEFAULT);
+                       }
+               }
+       }
 
        /* Flush all redistribute request. */
        for (afi = AFI_IP; afi < AFI_MAX; afi++)
@@ -447,29 +466,32 @@ void zclient_send_dereg_requests(struct zclient *zclient, vrf_id_t vrf_id)
 
        /* Set unwanted redistribute route. */
        for (afi = AFI_IP; afi < AFI_MAX; afi++)
-               vrf_bitmap_set(zclient->redist[afi][zclient->redist_default],
-                              vrf_id);
+               vrf_bitmap_unset(zclient->redist[afi][zclient->redist_default],
+                                vrf_id);
 
        /* Flush all redistribute request. */
-       if (vrf_id == VRF_DEFAULT)
-               for (afi = AFI_IP; afi < AFI_MAX; afi++)
-                       for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
-                               if (zclient->mi_redist[afi][i].enabled) {
-                                       struct listnode *node;
-                                       u_short *id;
-
-                                       for (ALL_LIST_ELEMENTS_RO(
-                                                    zclient->mi_redist[afi][i]
-                                                            .instances,
-                                                    node, id))
-                                               if (!(i == zclient->redist_default
-                                                     && *id == zclient->instance))
-                                                       zebra_redistribute_send(
-                                                               ZEBRA_REDISTRIBUTE_DELETE,
-                                                               zclient, afi, i,
-                                                               *id,
-                                                               VRF_DEFAULT);
-                               }
+       if (vrf_id == VRF_DEFAULT) {
+               for (afi = AFI_IP; afi < AFI_MAX; afi++) {
+                       for (i = 0; i < ZEBRA_ROUTE_MAX; i++) {
+                               if (!zclient->mi_redist[afi][i].enabled)
+                                       continue;
+
+                               struct listnode *node;
+                               u_short *id;
+
+                               for (ALL_LIST_ELEMENTS_RO(
+                                            zclient->mi_redist[afi][i]
+                                            .instances, node, id))
+                                       if (!(i == zclient->redist_default
+                                             && *id == zclient->instance))
+                                               zebra_redistribute_send(
+                                                       ZEBRA_REDISTRIBUTE_DELETE,
+                                                       zclient, afi, i,
+                                                       *id,
+                                                       VRF_DEFAULT);
+                       }
+               }
+       }
 
        /* Flush all redistribute request. */
        for (afi = AFI_IP; afi < AFI_MAX; afi++)
@@ -608,6 +630,33 @@ static int zclient_connect(struct thread *t)
        return zclient_start(zclient);
 }
 
+int zclient_send_rnh(struct zclient *zclient, int command, struct prefix *p,
+                    bool exact_match, vrf_id_t vrf_id)
+{
+       struct stream *s;
+
+       s = zclient->obuf;
+       stream_reset(s);
+       zclient_create_header(s, command, vrf_id);
+       stream_putc(s, (exact_match) ? 1 : 0);
+
+       stream_putw(s, PREFIX_FAMILY(p));
+       stream_putc(s, p->prefixlen);
+       switch (PREFIX_FAMILY(p)) {
+       case AF_INET:
+               stream_put_in_addr(s, &p->u.prefix4);
+               break;
+       case AF_INET6:
+               stream_put(s, &(p->u.prefix6), 16);
+               break;
+       default:
+               break;
+       }
+       stream_putw_at(s, 0, stream_get_endp(s));
+
+       return zclient_send_message(zclient);
+}
+
 /*
  * "xdr_encode"-like interface that allows daemon (client) to send
  * a message to zebra server for a route that needs to be
@@ -912,6 +961,8 @@ int zapi_route_encode(u_char cmd, struct stream *s, struct zapi_route *api)
        stream_putl(s, api->flags);
        stream_putc(s, api->message);
        stream_putc(s, api->safi);
+       if (CHECK_FLAG(api->flags, ZEBRA_FLAG_EVPN_ROUTE))
+               stream_put(s, &(api->rmac), sizeof(struct ethaddr));
 
        /* Put prefix information. */
        stream_putc(s, api->prefix.family);
@@ -944,6 +995,7 @@ int zapi_route_encode(u_char cmd, struct stream *s, struct zapi_route *api)
                for (i = 0; i < api->nexthop_num; i++) {
                        api_nh = &api->nexthops[i];
 
+                       stream_putl(s, api_nh->vrf_id);
                        stream_putc(s, api_nh->type);
                        switch (api_nh->type) {
                        case NEXTHOP_TYPE_BLACKHOLE:
@@ -1032,6 +1084,8 @@ int zapi_route_decode(struct stream *s, struct zapi_route *api)
        STREAM_GETL(s, api->flags);
        STREAM_GETC(s, api->message);
        STREAM_GETC(s, api->safi);
+       if (CHECK_FLAG(api->flags, ZEBRA_FLAG_EVPN_ROUTE))
+               stream_get(&(api->rmac), s, sizeof(struct ethaddr));
 
        /* Prefix. */
        STREAM_GETC(s, api->prefix.family);
@@ -1090,6 +1144,7 @@ int zapi_route_decode(struct stream *s, struct zapi_route *api)
                for (i = 0; i < api->nexthop_num; i++) {
                        api_nh = &api->nexthops[i];
 
+                       STREAM_GETL(s, api_nh->vrf_id);
                        STREAM_GETC(s, api_nh->type);
                        switch (api_nh->type) {
                        case NEXTHOP_TYPE_BLACKHOLE:
@@ -1170,6 +1225,73 @@ stream_failure:
        return false;
 }
 
+struct nexthop *nexthop_from_zapi_nexthop(struct zapi_nexthop *znh)
+{
+       struct nexthop *n = nexthop_new();
+
+       n->type = znh->type;
+       n->vrf_id = znh->vrf_id;
+       n->ifindex = znh->ifindex;
+       n->gate = znh->gate;
+
+       /*
+        * This function does not currently handle labels
+        */
+
+       return n;
+}
+
+bool zapi_nexthop_update_decode(struct stream *s, struct zapi_route *nhr)
+{
+       uint32_t i;
+
+       memset(nhr, 0, sizeof(*nhr));
+
+       STREAM_GETW(s, nhr->prefix.family);
+       STREAM_GETC(s, nhr->prefix.prefixlen);
+       switch(nhr->prefix.family) {
+       case AF_INET:
+               STREAM_GET(&nhr->prefix.u.prefix4.s_addr, s, IPV4_MAX_BYTELEN);
+               break;
+       case AF_INET6:
+               STREAM_GET(&nhr->prefix.u.prefix6, s, IPV6_MAX_BYTELEN);
+               break;
+       default:
+               break;
+       }
+
+       STREAM_GETC(s, nhr->distance);
+       STREAM_GETL(s, nhr->metric);
+       STREAM_GETC(s, nhr->nexthop_num);
+
+       for (i = 0; i < nhr->nexthop_num ; i++) {
+               STREAM_GETC(s, nhr->nexthops[i].type);
+               switch (nhr->nexthops[i].type) {
+               case NEXTHOP_TYPE_IPV4:
+               case NEXTHOP_TYPE_IPV4_IFINDEX:
+                       STREAM_GET(&nhr->nexthops[i].gate.ipv4.s_addr,
+                                  s, IPV4_MAX_BYTELEN);
+                       STREAM_GETL(s, nhr->nexthops[i].ifindex);
+                       break;
+               case NEXTHOP_TYPE_IFINDEX:
+                       STREAM_GETL(s, nhr->nexthops[i].ifindex);
+                       break;
+               case NEXTHOP_TYPE_IPV6:
+               case NEXTHOP_TYPE_IPV6_IFINDEX:
+                       STREAM_GET(&nhr->nexthops[i].gate.ipv6,
+                                  s, IPV6_MAX_BYTELEN);
+                       STREAM_GETL(s, nhr->nexthops[i].ifindex);
+                       break;
+               case NEXTHOP_TYPE_BLACKHOLE:
+                       break;
+               }
+       }
+
+       return true;
+stream_failure:
+       return false;
+}
+
 /*
  * send a ZEBRA_REDISTRIBUTE_ADD or ZEBRA_REDISTRIBUTE_DELETE
  * for the route type (ZEBRA_ROUTE_KERNEL etc.). The zebra server will
@@ -1673,7 +1795,7 @@ struct interface *zebra_interface_vrf_update_read(struct stream *s,
 {
        unsigned int ifindex;
        struct interface *ifp;
-       vrf_id_t new_id = VRF_DEFAULT;
+       vrf_id_t new_id;
 
        /* Get interface index. */
        ifindex = stream_getl(s);
@@ -1871,8 +1993,8 @@ int lm_get_label_chunk(struct zclient *zclient, u_char keep,
                        __func__, *start, *end, keep, response_keep);
        }
        /* sanity */
-       if (*start > *end || *start < MPLS_MIN_UNRESERVED_LABEL
-           || *end > MPLS_MAX_UNRESERVED_LABEL) {
+       if (*start > *end || *start < MPLS_LABEL_UNRESERVED_MIN
+           || *end > MPLS_LABEL_UNRESERVED_MAX) {
                zlog_err("%s: Invalid Label chunk: %u - %u", __func__, *start,
                         *end);
                return -1;
@@ -2039,7 +2161,7 @@ static int zclient_read(struct thread *thread)
        length = stream_getw(zclient->ibuf);
        marker = stream_getc(zclient->ibuf);
        version = stream_getc(zclient->ibuf);
-       vrf_id = stream_getw(zclient->ibuf);
+       vrf_id = stream_getl(zclient->ibuf);
        command = stream_getw(zclient->ibuf);
 
        if (marker != ZEBRA_HEADER_MARKER || version != ZSERV_VERSION) {
@@ -2205,6 +2327,16 @@ static int zclient_read(struct thread *thread)
                        (*zclient->local_vni_del)(command, zclient, length,
                                                  vrf_id);
                break;
+       case ZEBRA_L3VNI_ADD:
+               if (zclient->local_l3vni_add)
+                       (*zclient->local_l3vni_add)(command, zclient, length,
+                                                   vrf_id);
+               break;
+       case ZEBRA_L3VNI_DEL:
+               if (zclient->local_l3vni_del)
+                       (*zclient->local_l3vni_del)(command, zclient, length,
+                                                   vrf_id);
+               break;
        case ZEBRA_MACIP_ADD:
                if (zclient->local_macip_add)
                        (*zclient->local_macip_add)(command, zclient, length,
@@ -2215,6 +2347,16 @@ static int zclient_read(struct thread *thread)
                        (*zclient->local_macip_del)(command, zclient, length,
                                                    vrf_id);
                break;
+       case ZEBRA_IP_PREFIX_ROUTE_ADD:
+               if (zclient->local_ip_prefix_add)
+                       (*zclient->local_ip_prefix_add)(command, zclient,
+                                                       length, vrf_id);
+               break;
+       case ZEBRA_IP_PREFIX_ROUTE_DEL:
+               if (zclient->local_ip_prefix_del)
+                       (*zclient->local_ip_prefix_del)(command, zclient,
+                                                       length, vrf_id);
+               break;
        case ZEBRA_PW_STATUS_UPDATE:
                if (zclient->pw_status_update)
                        (*zclient->pw_status_update)(command, zclient, length,
@@ -2332,9 +2474,9 @@ void zclient_interface_set_master(struct zclient *client,
 
        zclient_create_header(s, ZEBRA_INTERFACE_SET_MASTER, master->vrf_id);
 
-       stream_putw(s, master->vrf_id);
+       stream_putl(s, master->vrf_id);
        stream_putl(s, master->ifindex);
-       stream_putw(s, slave->vrf_id);
+       stream_putl(s, slave->vrf_id);
        stream_putl(s, slave->ifindex);
 
        stream_putw_at(s, 0, stream_get_endp(s));
index de580446712bb111b12451e85b7c332248b9b908..d8a70c6cf339a263774152eee3f5dfc59b946c0d 100644 (file)
@@ -40,7 +40,7 @@
 #define ZEBRA_MAX_PACKET_SIZ          4096
 
 /* Zebra header size. */
-#define ZEBRA_HEADER_SIZE             8
+#define ZEBRA_HEADER_SIZE             10
 
 /* special socket path name to use TCP
  * @ is used as first character because that's abstract socket names on Linux
@@ -93,6 +93,7 @@ typedef enum {
        ZEBRA_VRF_UNREGISTER,
        ZEBRA_VRF_ADD,
        ZEBRA_VRF_DELETE,
+       ZEBRA_VRF_LABEL,
        ZEBRA_INTERFACE_VRF_UPDATE,
        ZEBRA_BFD_CLIENT_REGISTER,
        ZEBRA_INTERFACE_ENABLE_RADV,
@@ -109,13 +110,18 @@ typedef enum {
        ZEBRA_FEC_UNREGISTER,
        ZEBRA_FEC_UPDATE,
        ZEBRA_ADVERTISE_DEFAULT_GW,
+       ZEBRA_ADVERTISE_SUBNET,
        ZEBRA_ADVERTISE_ALL_VNI,
        ZEBRA_VNI_ADD,
        ZEBRA_VNI_DEL,
+       ZEBRA_L3VNI_ADD,
+       ZEBRA_L3VNI_DEL,
        ZEBRA_REMOTE_VTEP_ADD,
        ZEBRA_REMOTE_VTEP_DEL,
        ZEBRA_MACIP_ADD,
        ZEBRA_MACIP_DEL,
+       ZEBRA_IP_PREFIX_ROUTE_ADD,
+       ZEBRA_IP_PREFIX_ROUTE_DEL,
        ZEBRA_REMOTE_MACIP_ADD,
        ZEBRA_REMOTE_MACIP_DEL,
        ZEBRA_PW_ADD,
@@ -200,6 +206,10 @@ struct zclient {
        int (*fec_update)(int, struct zclient *, uint16_t);
        int (*local_vni_add)(int, struct zclient *, uint16_t, vrf_id_t);
        int (*local_vni_del)(int, struct zclient *, uint16_t, vrf_id_t);
+       int (*local_l3vni_add)(int, struct zclient *, uint16_t, vrf_id_t);
+       int (*local_l3vni_del)(int, struct zclient *, uint16_t, vrf_id_t);
+       void (*local_ip_prefix_add)(int, struct zclient *, uint16_t, vrf_id_t);
+       void (*local_ip_prefix_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);
@@ -223,13 +233,14 @@ struct zserv_header {
                         * always set to 255 in new zserv.
                         */
        uint8_t version;
-#define ZSERV_VERSION  4
+#define ZSERV_VERSION  5
        vrf_id_t vrf_id;
        uint16_t command;
 };
 
 struct zapi_nexthop {
        enum nexthop_types_t type;
+       vrf_id_t vrf_id;
        ifindex_t ifindex;
        union {
                union g_addr gate;
@@ -277,6 +288,8 @@ struct zapi_route {
        u_int32_t mtu;
 
        vrf_id_t vrf_id;
+
+       struct ethaddr rmac;
 };
 
 /* Zebra IPv4 route message API. */
@@ -336,8 +349,8 @@ enum zapi_route_notify_owner {
 };
 
 /* Zebra MAC types */
-#define ZEBRA_MAC_TYPE_STICKY                0x01 /* Sticky MAC*/
-#define ZEBRA_MAC_TYPE_GW                    0x02 /* gateway (SVI) mac*/
+#define ZEBRA_MACIP_TYPE_STICKY                0x01 /* Sticky MAC*/
+#define ZEBRA_MACIP_TYPE_GW                    0x02 /* gateway (SVI) mac*/
 
 struct zclient_options {
        bool receive_notify;
@@ -370,6 +383,23 @@ extern u_short *redist_check_instance(struct redist_proto *, u_short);
 extern void redist_add_instance(struct redist_proto *, u_short);
 extern void redist_del_instance(struct redist_proto *, u_short);
 
+/*
+ * Send to zebra that the specified vrf is using label to resolve
+ * itself for L3VPN's.  Repeated calls of this function with
+ * different labels will cause an effective update of the
+ * label for lookup.  If you pass in MPLS_LABEL_NONE
+ * we will cause a delete action and remove this label pop
+ * operation.
+ *
+ * The underlying AF_MPLS doesn't care about afi's
+ * but we can make the zebra_vrf keep track of what
+ * we have installed and play some special games
+ * to get them both installed.
+ */
+extern void zclient_send_vrf_label(struct zclient *zclient, vrf_id_t vrf_id,
+                                  afi_t afi, mpls_label_t label,
+                                  enum lsp_types_t ltype);
+
 extern void zclient_send_reg_requests(struct zclient *, vrf_id_t);
 extern void zclient_send_dereg_requests(struct zclient *, vrf_id_t);
 
@@ -414,6 +444,11 @@ extern struct interface *zebra_interface_vrf_update_read(struct stream *s,
                                                         vrf_id_t *new_vrf_id);
 extern void zebra_interface_if_set_value(struct stream *, struct interface *);
 extern void zebra_router_id_update_read(struct stream *s, struct prefix *rid);
+
+#if CONFDATE > 20180823
+CPP_NOTICE("zapi_ipv4_route, zapi_ipv6_route, zapi_ipv4_route_ipv6_nexthop as well as the zapi_ipv4 and zapi_ipv6 data structures should be removed now");
+#endif
+
 extern int zapi_ipv4_route(u_char, struct zclient *, struct prefix_ipv4 *,
                           struct zapi_ipv4 *) __attribute__((deprecated));
 
@@ -472,16 +507,23 @@ extern int zapi_ipv4_route_ipv6_nexthop(u_char, struct zclient *,
                                        struct zapi_ipv6 *)
        __attribute__((deprecated));
 extern int zclient_route_send(u_char, struct zclient *, struct zapi_route *);
+extern int zclient_send_rnh(struct zclient *zclient, int command,
+                           struct prefix *p, bool exact_match,
+                           vrf_id_t vrf_id);
 extern int zapi_route_encode(u_char, struct stream *, struct zapi_route *);
 extern int zapi_route_decode(struct stream *, struct zapi_route *);
 bool zapi_route_notify_decode(struct stream *s, struct prefix *p,
                              enum zapi_route_notify_owner *note);
+extern struct nexthop *nexthop_from_zapi_nexthop(struct zapi_nexthop *znh);
+extern bool zapi_nexthop_update_decode(struct stream *s,
+                                      struct zapi_route *nhr);
 
 static inline void zapi_route_set_blackhole(struct zapi_route *api,
                                            enum blackhole_type bh_type)
 {
        api->nexthop_num = 1;
        api->nexthops[0].type = NEXTHOP_TYPE_BLACKHOLE;
+       api->nexthops[0].vrf_id = VRF_DEFAULT;
        api->nexthops[0].bh_type = bh_type;
        SET_FLAG(api->message, ZAPI_MESSAGE_NEXTHOP);
 };
index fa5fa89f776116c2b1aff76c9241017a63222a5e..b9a795d16099894beac1f9adb4c63cb60d0c87b5 100644 (file)
@@ -409,6 +409,7 @@ extern const char *zserv_command_string(unsigned int command);
 #define ZEBRA_FLAG_STATIC             0x40
 #define ZEBRA_FLAG_SCOPE_LINK         0x100
 #define ZEBRA_FLAG_FIB_OVERRIDE       0x200
+#define ZEBRA_FLAG_EVPN_ROUTE         0x400
 /* ZEBRA_FLAG_BLACKHOLE was 0x04 */
 /* ZEBRA_FLAG_REJECT was 0x80 */
 
@@ -485,7 +486,7 @@ typedef u_int16_t zebra_size_t;
 typedef u_int16_t zebra_command_t;
 
 /* VRF ID type. */
-typedef u_int16_t vrf_id_t;
+typedef uint32_t vrf_id_t;
 
 typedef uint32_t route_tag_t;
 #define ROUTE_TAG_MAX UINT32_MAX
index 2612d8e045bef673a016620ed484da2334d072a8..d43aa4929e10c492347789f85d58dd8eaa479453 100644 (file)
@@ -95,6 +95,7 @@ void nhrp_route_announce(int add, enum nhrp_cache_type type, const struct prefix
        memset(&api, 0, sizeof(api));
        api.type = ZEBRA_ROUTE_NHRP;
        api.safi = SAFI_UNICAST;
+       api.vrf_id = VRF_DEFAULT;
        api.prefix = *p;
 
        switch (type) {
@@ -118,6 +119,7 @@ void nhrp_route_announce(int add, enum nhrp_cache_type type, const struct prefix
        SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP);
        api.nexthop_num = 1;
        api_nh = &api.nexthops[0];
+       api_nh->vrf_id = VRF_DEFAULT;
 
        switch (api.prefix.family) {
        case AF_INET:
index d270b9547edc4360fc16cfe17cceaa787646f04c..8847611492b0333558122951af3930312df7025b 100644 (file)
@@ -901,6 +901,7 @@ void ospf6_abr_examin_summary(struct ospf6_lsa *lsa, struct ospf6_area *oa)
 
        ospf6_route_copy_nexthops(route, abr_entry);
 
+
        /* (7) If the routes are identical, copy the next hops over to existing
           route. ospf6's route table implementation will otherwise string both
           routes, but keep the older one as the best route since the routes
@@ -910,6 +911,12 @@ void ospf6_abr_examin_summary(struct ospf6_lsa *lsa, struct ospf6_area *oa)
 
        if (old && (ospf6_route_cmp(route, old) == 0)) {
                ospf6_route_merge_nexthops(old, route);
+
+               if (is_debug)
+                       zlog_debug("%s: Update route: %s nh count %u",
+                               __PRETTY_FUNCTION__,
+                               buf, listcount(route->nh_list));
+
                /* Update RIB/FIB */
                if (table->hook_add)
                        (*table->hook_add)(old);
@@ -918,7 +925,8 @@ void ospf6_abr_examin_summary(struct ospf6_lsa *lsa, struct ospf6_area *oa)
                ospf6_route_delete(route);
        } else {
                if (is_debug)
-                       zlog_debug("Install route: %s", buf);
+                       zlog_debug("Install route: %s nh count %u",
+                                  buf, listcount(route->nh_list));
                /* ospf6_ia_add_nw_route (table, &prefix, route); */
                ospf6_route_add(route, table);
        }
index bd5e2bd1d35740e1d6ff6ce0bdcaaa5f29907df1..ed624c6ae414a775fd35d2f8cc2192383c5bd278 100644 (file)
@@ -117,7 +117,9 @@ static void ospf6_area_lsdb_hook_remove(struct ospf6_lsa *lsa)
 
 static void ospf6_area_route_hook_add(struct ospf6_route *route)
 {
-       struct ospf6_route *copy = ospf6_route_copy(route);
+       struct ospf6_route *copy;
+
+       copy = ospf6_route_copy(route);
        ospf6_route_add(copy, ospf6->route_table);
 }
 
@@ -219,6 +221,7 @@ struct ospf6_area *ospf6_area_create(u_int32_t area_id, struct ospf6 *o, int df)
        oa->lsdb->hook_add = ospf6_area_lsdb_hook_add;
        oa->lsdb->hook_remove = ospf6_area_lsdb_hook_remove;
        oa->lsdb_self = ospf6_lsdb_create(oa);
+       oa->temp_router_lsa_lsdb = ospf6_lsdb_create(oa);
 
        oa->spf_table = OSPF6_ROUTE_TABLE_CREATE(AREA, SPF_RESULTS);
        oa->spf_table->scope = oa;
@@ -277,6 +280,7 @@ void ospf6_area_delete(struct ospf6_area *oa)
 
        ospf6_lsdb_delete(oa->lsdb);
        ospf6_lsdb_delete(oa->lsdb_self);
+       ospf6_lsdb_delete(oa->temp_router_lsa_lsdb);
 
        ospf6_spf_table_finish(oa->spf_table);
        ospf6_route_table_delete(oa->spf_table);
index d212d9238726971f2e5f2e533aa21aedd189d99a..e162d21cd25f27fbb2b9145f80ed2cce1c4e686e 100644 (file)
@@ -55,6 +55,7 @@ struct ospf6_area {
 
        struct ospf6_lsdb *lsdb;
        struct ospf6_lsdb *lsdb_self;
+       struct ospf6_lsdb *temp_router_lsa_lsdb;
 
        struct ospf6_route_table *spf_table;
        struct ospf6_route_table *route_table;
@@ -98,6 +99,8 @@ struct ospf6_area {
 
        /* Time stamps. */
        struct timeval ts_spf; /* SPF calculation time stamp. */
+
+       uint32_t full_nbrs; /* Fully adjacent neighbors. */
 };
 
 #define OSPF6_AREA_ENABLE     0x01
index c65578c11e34988c457d5283e23002bbb153661c..11f9e7c7b6e4dfc2dfcdde6268a4a96e1d596525 100644 (file)
@@ -148,6 +148,32 @@ static void ospf6_as_external_lsa_originate(struct ospf6_route *route)
        ospf6_lsa_originate_process(lsa, ospf6);
 }
 
+int ospf6_orig_as_external_lsa(struct thread *thread)
+{
+       struct ospf6_interface *oi;
+       struct ospf6_lsa *lsa;
+       uint32_t type, adv_router;
+
+       oi = (struct ospf6_interface *)THREAD_ARG(thread);
+       oi->thread_as_extern_lsa = NULL;
+
+       if (oi->state == OSPF6_INTERFACE_DOWN)
+               return 0;
+
+       type = htons(OSPF6_LSTYPE_AS_EXTERNAL);
+       adv_router = oi->area->ospf6->router_id;
+       for (ALL_LSDB_TYPED_ADVRTR(ospf6->lsdb, type, adv_router, lsa)) {
+               if (IS_OSPF6_DEBUG_ASBR)
+                       zlog_debug("%s: Send update of AS-External LSA %s seq 0x%x",
+                                  __PRETTY_FUNCTION__, lsa->name,
+                                  ntohl(lsa->header->seqnum));
+
+               ospf6_flood_interface(NULL, lsa, oi);
+       }
+
+       return 0;
+}
+
 static route_tag_t ospf6_as_external_lsa_get_tag(struct ospf6_lsa *lsa)
 {
        struct ospf6_as_external_lsa *external;
@@ -173,11 +199,136 @@ static route_tag_t ospf6_as_external_lsa_get_tag(struct ospf6_lsa *lsa)
        return ntohl(network_order);
 }
 
+void ospf6_asbr_update_route_ecmp_path(struct ospf6_route *old,
+                                      struct ospf6_route *route)
+{
+       struct ospf6_route *old_route;
+       struct ospf6_path *ecmp_path, *o_path = NULL;
+       struct listnode *anode;
+       struct listnode *nnode, *rnode, *rnext;
+       struct ospf6_nexthop *nh, *rnh;
+       char buf[PREFIX2STR_BUFFER];
+       bool route_found = false;
+
+       for (old_route = old; old_route; old_route = old_route->next) {
+               if (ospf6_route_is_same(old_route, route) &&
+                       (old_route->path.type == route->path.type) &&
+                       (old_route->path.cost == route->path.cost) &&
+                       (old_route->path.u.cost_e2 == route->path.u.cost_e2)) {
+
+                       if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
+                               prefix2str(&old_route->prefix, buf,
+                                          sizeof(buf));
+                               zlog_debug("%s: old route %s path  cost %u [%u]",
+                                          __PRETTY_FUNCTION__, buf,
+                                          old_route->path.cost,
+                                          ospf6_route_is_same(old_route,
+                                                              route));
+                       }
+                       route_found = true;
+                       /* check if this path exists already in
+                        * route->paths list, if so, replace nh_list
+                        * from asbr_entry.
+                        */
+                       for (ALL_LIST_ELEMENTS_RO(old_route->paths, anode,
+                                                 o_path)) {
+                               if ((o_path->origin.id == route->path.origin.id)
+                                       && (o_path->origin.adv_router ==
+                                               route->path.origin.adv_router))
+                                       break;
+                       }
+                       /* If path is not found in old_route paths's list,
+                        * add a new path to route paths list and merge
+                        * nexthops in route->path->nh_list.
+                        * Otherwise replace existing path's nh_list.
+                        */
+                       if (o_path == NULL) {
+                               ecmp_path = ospf6_path_dup(&route->path);
+
+                               /* Add a nh_list to new ecmp path */
+                               ospf6_copy_nexthops(ecmp_path->nh_list,
+                                                   route->nh_list);
+                               /* Merge nexthop to existing route's nh_list */
+                               ospf6_route_merge_nexthops(old_route, route);
+
+                               /* Update RIB/FIB */
+                               if (ospf6->route_table->hook_add)
+                                       (*ospf6->route_table->hook_add)
+                                               (old_route);
+
+                               /* Add the new path to route's path list */
+                               listnode_add_sort(old_route->paths, ecmp_path);
+
+                               if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
+                                       prefix2str(&route->prefix, buf,
+                                                  sizeof(buf));
+                                       zlog_debug("%s: route %s another path added with nh %u, Paths %u",
+                                               __PRETTY_FUNCTION__, buf,
+                                               listcount(ecmp_path->nh_list),
+                                               old_route->paths ?
+                                               listcount(old_route->paths)
+                                               : 0);
+                               }
+                       } else {
+                               for (ALL_LIST_ELEMENTS_RO(o_path->nh_list,
+                                                         nnode, nh)) {
+                                       for (ALL_LIST_ELEMENTS(
+                                                       old_route->nh_list,
+                                                       rnode, rnext, rnh)) {
+                                               if (!ospf6_nexthop_is_same(rnh,
+                                                                          nh))
+                                                       continue;
+
+                                               listnode_delete(
+                                                       old_route->nh_list,
+                                                       rnh);
+                                               ospf6_nexthop_delete(rnh);
+                                       }
+                               }
+                               list_delete_all_node(o_path->nh_list);
+                               ospf6_copy_nexthops(o_path->nh_list,
+                                           route->nh_list);
+
+                               /* Merge nexthop to existing route's nh_list */
+                               ospf6_route_merge_nexthops(old_route,
+                                                          route);
+
+                               if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
+                                       prefix2str(&route->prefix,
+                                                  buf, sizeof(buf));
+                                       zlog_debug("%s: existing route %s with effective nh count %u",
+                                                  __PRETTY_FUNCTION__, buf,
+                                                  old_route->nh_list ?
+                                                  listcount(old_route->nh_list)
+                                                  : 0);
+                               }
+
+                               /* Update RIB/FIB */
+                               if (ospf6->route_table->hook_add)
+                                       (*ospf6->route_table->hook_add)
+                                               (old_route);
+
+                       }
+                       /* Delete the new route its info added to existing
+                        * route.
+                        */
+                       ospf6_route_delete(route);
+                       break;
+               }
+       }
+
+       if (!route_found) {
+               /* Add new route to existing node in ospf6 route table. */
+               ospf6_route_add(route, ospf6->route_table);
+       }
+}
+
 void ospf6_asbr_lsa_add(struct ospf6_lsa *lsa)
 {
        struct ospf6_as_external_lsa *external;
        struct prefix asbr_id;
-       struct ospf6_route *asbr_entry, *route;
+       struct ospf6_route *asbr_entry, *route, *old;
+       struct ospf6_path *path;
        char buf[PREFIX2STR_BUFFER];
 
        external = (struct ospf6_as_external_lsa *)OSPF6_LSA_HEADER_END(
@@ -245,12 +396,34 @@ void ospf6_asbr_lsa_add(struct ospf6_lsa *lsa)
 
        ospf6_route_copy_nexthops(route, asbr_entry);
 
+       path = ospf6_path_dup(&route->path);
+       ospf6_copy_nexthops(path->nh_list, asbr_entry->nh_list);
+       listnode_add_sort(route->paths, path);
+
+
        if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
                prefix2str(&route->prefix, buf, sizeof(buf));
-               zlog_debug("AS-External route add: %s", buf);
+               zlog_debug("%s: AS-External %u route add %s cost %u(%u) nh %u",
+                          __PRETTY_FUNCTION__,
+                          (route->path.type == OSPF6_PATH_TYPE_EXTERNAL1)
+                          ? 1 : 2, buf, route->path.cost,
+                          route->path.u.cost_e2,
+                          listcount(route->nh_list));
+       }
+
+       old = ospf6_route_lookup(&route->prefix, ospf6->route_table);
+       if (!old) {
+               /* Add the new route to ospf6 instance route table. */
+               ospf6_route_add(route, ospf6->route_table);
+       } else {
+               /* RFC 2328 16.4 (6)
+                * ECMP: Keep new equal preference path in current
+                * route's path list, update zebra with new effective
+                * list along with addition of ECMP path.
+                */
+               ospf6_asbr_update_route_ecmp_path(old, route);
        }
 
-       ospf6_route_add(route, ospf6->route_table);
 }
 
 void ospf6_asbr_lsa_remove(struct ospf6_lsa *lsa)
@@ -291,16 +464,126 @@ void ospf6_asbr_lsa_remove(struct ospf6_lsa *lsa)
                nroute = ospf6_route_next(route);
                if (route->type != OSPF6_DEST_TYPE_NETWORK)
                        continue;
-               if (route->path.origin.type != lsa->header->type)
-                       continue;
-               if (route->path.origin.id != lsa->header->id)
-                       continue;
-               if (route->path.origin.adv_router != lsa->header->adv_router)
+
+               /* Route has multiple ECMP paths remove,
+                * matching path and update effective route's  nh list.
+                */
+               if (listcount(route->paths) > 1) {
+                       struct listnode *anode, *anext;
+                       struct listnode *nnode, *rnode, *rnext;
+                       struct ospf6_nexthop *nh, *rnh;
+                       struct ospf6_path *o_path;
+                       bool nh_updated = false;
+
+                       /* Iterate all paths of route to find maching with LSA
+                        * remove from route path list. If route->path is same,
+                        * replace from paths list.
+                        */
+                       for (ALL_LIST_ELEMENTS(route->paths, anode, anext,
+                                                 o_path)) {
+                               if (o_path->origin.type != lsa->header->type)
+                                       continue;
+                               if (o_path->origin.id != lsa->header->id)
+                                       continue;
+                               if (o_path->origin.adv_router !=
+                                       lsa->header->adv_router)
+                                       continue;
+
+                               if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL))  {
+                                       prefix2str(&prefix, buf, sizeof(buf));
+                                       zlog_debug(
+                                               "%s: route %s path found with nh %u",
+                                               __PRETTY_FUNCTION__, buf,
+                                               listcount(o_path->nh_list));
+                               }
+
+                               /* Remove found path's nh_list from
+                                * the route's nh_list.
+                                */
+                               for (ALL_LIST_ELEMENTS_RO(o_path->nh_list,
+                                                         nnode, nh)) {
+                                       for (ALL_LIST_ELEMENTS(route->nh_list,
+                                                       rnode, rnext, rnh)) {
+                                               if (!ospf6_nexthop_is_same(rnh,
+                                                               nh))
+                                                       continue;
+                                               listnode_delete(route->nh_list,
+                                                               rnh);
+                                               ospf6_nexthop_delete(rnh);
+                                       }
+                               }
+                               /* Delete the path from route's path list */
+                               listnode_delete(route->paths, o_path);
+                               ospf6_path_free(o_path);
+                               nh_updated = true;
+                       }
+
+                       if (nh_updated) {
+                               /* Iterate all paths and merge nexthop,
+                                * unlesss any of the nexthop similar to
+                                * ones deleted as part of path deletion.
+                                */
+
+                               for (ALL_LIST_ELEMENTS(route->paths, anode,
+                                                      anext, o_path)) {
+                                       ospf6_merge_nexthops(route->nh_list,
+                                                            o_path->nh_list);
+                               }
+
+                               if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
+                                       prefix2str(&route->prefix, buf,
+                                                  sizeof(buf));
+                                       zlog_debug("%s: AS-External %u route %s update paths %u nh %u"
+                                                  , __PRETTY_FUNCTION__,
+                                                  (route->path.type ==
+                                                  OSPF6_PATH_TYPE_EXTERNAL1)
+                                                  ? 1 : 2, buf,
+                                                  listcount(route->paths),
+                                                  listcount(route->nh_list));
+                               }
+
+                               /* Update RIB/FIB w/ effective nh_list */
+                               if (ospf6->route_table->hook_add)
+                                       (*ospf6->route_table->hook_add)(route);
+
+                               /* route's path is similar to lsa header,
+                                * replace route's path with route's
+                                * paths list head.
+                                */
+                               if (route->path.origin.id == lsa->header->id &&
+                                   route->path.origin.adv_router ==
+                                               lsa->header->adv_router) {
+                                       struct ospf6_path *h_path;
+
+                                       h_path = (struct ospf6_path *)
+                                       listgetdata(listhead(route->paths));
+                                       route->path.origin.type =
+                                               h_path->origin.type;
+                                       route->path.origin.id =
+                                               h_path->origin.id;
+                                       route->path.origin.adv_router =
+                                               h_path->origin.adv_router;
+                               }
+                       }
                        continue;
 
+               } else {
+                       if (route->path.origin.type != lsa->header->type)
+                               continue;
+                       if (route->path.origin.id != lsa->header->id)
+                               continue;
+                       if (route->path.origin.adv_router !=
+                                       lsa->header->adv_router)
+                               continue;
+               }
                if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
                        prefix2str(&route->prefix, buf, sizeof(buf));
-                       zlog_debug("AS-External route remove: %s", buf);
+                       zlog_debug("%s: AS-External %u route remove %s cost %u(%u) nh %u",
+                                  __PRETTY_FUNCTION__,
+                                  route->path.type == OSPF6_PATH_TYPE_EXTERNAL1
+                                  ? 1 : 2, buf, route->path.cost,
+                                  route->path.u.cost_e2,
+                                  listcount(route->nh_list));
                }
                ospf6_route_remove(route, ospf6->route_table);
        }
@@ -361,6 +644,56 @@ static void ospf6_asbr_routemap_unset(int type)
        ospf6->rmap[type].map = NULL;
 }
 
+static int ospf6_asbr_routemap_update_timer(struct thread *thread)
+{
+       void **arg;
+       int arg_type;
+
+       arg = THREAD_ARG(thread);
+       arg_type = (int)(intptr_t)arg[1];
+
+       ospf6->t_distribute_update = NULL;
+
+       if (ospf6->rmap[arg_type].name)
+               ospf6->rmap[arg_type].map = route_map_lookup_by_name(
+                                       ospf6->rmap[arg_type].name);
+       if (ospf6->rmap[arg_type].map) {
+               if (IS_OSPF6_DEBUG_ASBR)
+                       zlog_debug("%s: route-map %s update, reset redist %s",
+                                  __PRETTY_FUNCTION__,
+                                  ospf6->rmap[arg_type].name,
+                                  ZROUTE_NAME(arg_type));
+
+               ospf6_zebra_no_redistribute(arg_type);
+               ospf6_zebra_redistribute(arg_type);
+       }
+
+       XFREE(MTYPE_OSPF6_DIST_ARGS, arg);
+       return 0;
+}
+
+void ospf6_asbr_distribute_list_update(int type)
+{
+       void **args = NULL;
+
+       if (ospf6->t_distribute_update)
+               return;
+
+       args = XCALLOC(MTYPE_OSPF6_DIST_ARGS, sizeof(void *)*2);
+
+       args[0] = ospf6;
+       args[1] = (void *)((ptrdiff_t)type);
+
+       if (IS_OSPF6_DEBUG_ASBR)
+               zlog_debug("%s: trigger redistribute %s reset thread",
+                          __PRETTY_FUNCTION__, ZROUTE_NAME(type));
+
+       ospf6->t_distribute_update = NULL;
+       thread_add_timer_msec(master, ospf6_asbr_routemap_update_timer,
+                             (void **)args, OSPF_MIN_LS_INTERVAL,
+                             &ospf6->t_distribute_update);
+}
+
 static void ospf6_asbr_routemap_update(const char *mapname)
 {
        int type;
@@ -369,14 +702,37 @@ static void ospf6_asbr_routemap_update(const char *mapname)
                return;
 
        for (type = 0; type < ZEBRA_ROUTE_MAX; type++) {
-               if (ospf6->rmap[type].name)
+               if (ospf6->rmap[type].name) {
                        ospf6->rmap[type].map = route_map_lookup_by_name(
                                ospf6->rmap[type].name);
-               else
+
+                       if (mapname && ospf6->rmap[type].map &&
+                           (strcmp(ospf6->rmap[type].name, mapname) == 0)) {
+                               if (IS_OSPF6_DEBUG_ASBR)
+                                       zlog_debug("%s: route-map %s update, reset redist %s",
+                                                  __PRETTY_FUNCTION__, mapname,
+                                                  ZROUTE_NAME(type));
+                               ospf6_asbr_distribute_list_update(type);
+                       }
+               } else
                        ospf6->rmap[type].map = NULL;
        }
 }
 
+static void ospf6_asbr_routemap_event(route_map_event_t event, const char *name)
+{
+       int type;
+
+       if (ospf6 == NULL)
+               return;
+       for (type = 0; type < ZEBRA_ROUTE_MAX; type++) {
+               if ((ospf6->rmap[type].name) &&
+                   (strcmp(ospf6->rmap[type].name, name) == 0)) {
+                       ospf6_asbr_distribute_list_update(type);
+               }
+       }
+}
+
 int ospf6_asbr_is_asbr(struct ospf6 *o)
 {
        return o->external_table->count;
@@ -477,7 +833,6 @@ void ospf6_asbr_redistribute_add(int type, ifindex_t ifindex,
        match = ospf6_route_lookup(prefix, ospf6->external_table);
        if (match) {
                info = match->route_option;
-
                /* copy result of route-map */
                if (ospf6->rmap[type].map) {
                        if (troute.path.metric_type)
@@ -511,7 +866,9 @@ void ospf6_asbr_redistribute_add(int type, ifindex_t ifindex,
                if (IS_OSPF6_DEBUG_ASBR) {
                        inet_ntop(AF_INET, &prefix_id.u.prefix4, ibuf,
                                  sizeof(ibuf));
-                       zlog_debug("Advertise as AS-External Id:%s", ibuf);
+                       prefix2str(prefix, pbuf, sizeof(pbuf));
+                       zlog_debug("Advertise as AS-External Id:%s prefix %s metric %u",
+                                  ibuf, pbuf, match->path.metric_type);
                }
 
                match->path.origin.id = htonl(info->id);
@@ -562,7 +919,9 @@ void ospf6_asbr_redistribute_add(int type, ifindex_t ifindex,
 
        if (IS_OSPF6_DEBUG_ASBR) {
                inet_ntop(AF_INET, &prefix_id.u.prefix4, ibuf, sizeof(ibuf));
-               zlog_debug("Advertise as AS-External Id:%s", ibuf);
+               prefix2str(prefix, pbuf, sizeof(pbuf));
+               zlog_debug("Advertise as AS-External Id:%s prefix %s metric %u",
+                          ibuf, pbuf, route->path.metric_type);
        }
 
        route->path.origin.id = htonl(info->id);
@@ -1071,6 +1430,7 @@ static void ospf6_routemap_init(void)
 
        route_map_add_hook(ospf6_asbr_routemap_update);
        route_map_delete_hook(ospf6_asbr_routemap_update);
+       route_map_event_hook(ospf6_asbr_routemap_event);
 
        route_map_set_metric_hook(generic_set_add);
        route_map_no_set_metric_hook(generic_set_delete);
@@ -1270,6 +1630,10 @@ void ospf6_asbr_redistribute_reset(void)
 
 void ospf6_asbr_terminate(void)
 {
+       /* Cleanup route maps */
+       route_map_add_hook(NULL);
+       route_map_delete_hook(NULL);
+       route_map_event_hook(NULL);
        route_map_finish();
 }
 
index 73053452e6a22ac0e838d3dbd604af7e071875a1..cc4f0272aabbfc4d33c6710cb1253df341760af3 100644 (file)
@@ -93,5 +93,8 @@ extern void ospf6_asbr_send_externals_to_area(struct ospf6_area *);
 
 extern int config_write_ospf6_debug_asbr(struct vty *vty);
 extern void install_element_ospf6_debug_asbr(void);
+extern void ospf6_asbr_update_route_ecmp_path(struct ospf6_route *old,
+                                             struct ospf6_route *route);
+extern void ospf6_asbr_distribute_list_update(int type);
 
 #endif /* OSPF6_ASBR_H */
index 42716fbc7fda9a65617449007345be013677381b..17733d6099fc257e0a3effaf295b1f1df07b8616 100644 (file)
@@ -192,10 +192,6 @@ void ospf6_install_lsa(struct ospf6_lsa *lsa)
        struct timeval now;
        struct ospf6_lsa *old;
 
-       if (IS_OSPF6_DEBUG_LSA_TYPE(lsa->header->type)
-           || IS_OSPF6_DEBUG_EXAMIN_TYPE(lsa->header->type))
-               zlog_debug("Install LSA: %s", lsa->name);
-
        /* Remove the old instance from all neighbors' Link state
           retransmission list (RFC2328 13.2 last paragraph) */
        old = ospf6_lsdb_lookup(lsa->header->type, lsa->header->id,
@@ -237,6 +233,13 @@ void ospf6_install_lsa(struct ospf6_lsa *lsa)
                ospf6_lsa_checksum(lsa->header);
        }
 
+       if (IS_OSPF6_DEBUG_LSA_TYPE(lsa->header->type)
+           || IS_OSPF6_DEBUG_EXAMIN_TYPE(lsa->header->type))
+               zlog_debug("%s Install LSA: %s age %d seqnum %x in LSDB.",
+                          __PRETTY_FUNCTION__, lsa->name,
+                          ntohs(lsa->header->age),
+                          ntohl(lsa->header->seqnum));
+
        /* actually install */
        lsa->installed = now;
        ospf6_lsdb_add(lsa, lsa->lsdb);
@@ -246,7 +249,7 @@ void ospf6_install_lsa(struct ospf6_lsa *lsa)
 
 /* RFC2740 section 3.5.2. Sending Link State Update packets */
 /* RFC2328 section 13.3 Next step in the flooding procedure */
-static void ospf6_flood_interface(struct ospf6_neighbor *from,
+void ospf6_flood_interface(struct ospf6_neighbor *from,
                                  struct ospf6_lsa *lsa,
                                  struct ospf6_interface *oi)
 {
@@ -343,15 +346,24 @@ static void ospf6_flood_interface(struct ospf6_neighbor *from,
                        continue;
                }
 
-               /* (d) add retrans-list, schedule retransmission */
-               if (is_debug)
-                       zlog_debug("Add retrans-list of this neighbor");
-               ospf6_increment_retrans_count(lsa);
-               ospf6_lsdb_add(ospf6_lsa_copy(lsa), on->retrans_list);
-               thread_add_timer(master, ospf6_lsupdate_send_neighbor, on,
-                                on->ospf6_if->rxmt_interval,
-                                &on->thread_send_lsupdate);
-               retrans_added++;
+               if (ospf6->inst_shutdown) {
+                       if (is_debug)
+                               zlog_debug("%s: Send LSA %s (age %d) update now",
+                                          __PRETTY_FUNCTION__, lsa->name,
+                                          ntohs(lsa->header->age));
+                       ospf6_lsupdate_send_neighbor_now(on, lsa);
+                       continue;
+               } else {
+                       /* (d) add retrans-list, schedule retransmission */
+                       if (is_debug)
+                               zlog_debug("Add retrans-list of this neighbor");
+                       ospf6_increment_retrans_count(lsa);
+                       ospf6_lsdb_add(ospf6_lsa_copy(lsa), on->retrans_list);
+                       thread_add_timer(master, ospf6_lsupdate_send_neighbor,
+                                        on, on->ospf6_if->rxmt_interval,
+                                        &on->thread_send_lsupdate);
+                       retrans_added++;
+               }
        }
 
        /* (2) examin next interface if not added to retrans-list */
@@ -806,6 +818,17 @@ void ospf6_receive_lsa(struct ospf6_neighbor *from,
                                zlog_debug("Received is duplicated LSA");
                        SET_FLAG(new->flag, OSPF6_LSA_DUPLICATE);
                }
+               if (old->header->adv_router ==
+                   from->ospf6_if->area->ospf6->router_id
+                   && OSPF6_LSA_IS_MAXAGE(new)) {
+                       ospf6_acknowledge_lsa(new, ismore_recent, from);
+                       ospf6_lsa_delete(new);
+                       if (is_debug)
+                               zlog_debug("%s: Received is self orig MAXAGE LSA %s, discard (ismore_recent %d)",
+                                          __PRETTY_FUNCTION__, old->name,
+                                          ismore_recent);
+                       return;
+               }
        }
 
        /* if no database copy or received is more recent */
@@ -959,12 +982,34 @@ void ospf6_receive_lsa(struct ospf6_neighbor *from,
                                        "Send back directly and then discard");
                        }
 
+                       /* Neighbor router sent recent age for LSA,
+                        * Router could be restarted while current copy is
+                        * MAXAGEd and not removed.*/
+                       if (OSPF6_LSA_IS_MAXAGE(old) &&
+                           !OSPF6_LSA_IS_MAXAGE(new)) {
+
+                               if (is_debug)
+                                       zlog_debug("%s: Current copy of LSA %s is MAXAGE, but new has recent Age.",
+                                                  old->name,
+                                          __PRETTY_FUNCTION__);
+
+                               ospf6_lsa_purge(old);
+                               if (new->header->adv_router
+                                               != from->ospf6_if->area->
+                                                       ospf6->router_id)
+                                       ospf6_flood(from, new);
+
+                               ospf6_install_lsa(new);
+                               return;
+                       }
+
                        /* XXX, MinLSArrival check !? RFC 2328 13 (8) */
 
                        ospf6_lsdb_add(ospf6_lsa_copy(old),
                                       from->lsupdate_list);
                        thread_add_event(master, ospf6_lsupdate_send_neighbor,
                                         from, 0, &from->thread_send_lsupdate);
+
                        ospf6_lsa_delete(new);
                        return;
                }
@@ -972,7 +1017,6 @@ void ospf6_receive_lsa(struct ospf6_neighbor *from,
        }
 }
 
-
 DEFUN (debug_ospf6_flooding,
        debug_ospf6_flooding_cmd,
        "debug ospf6 flooding",
index 610eefc803b43047e1b21901692ff7bb3dc3b647..f5d33e2843aa3269a24e56c0fd6f20aab0ccb15b 100644 (file)
@@ -58,5 +58,10 @@ extern void ospf6_install_lsa(struct ospf6_lsa *lsa);
 
 extern int config_write_ospf6_debug_flood(struct vty *vty);
 extern void install_element_ospf6_debug_flood(void);
+extern void ospf6_flood_interface(struct ospf6_neighbor *from,
+                                 struct ospf6_lsa *lsa,
+                                 struct ospf6_interface *oi);
+extern int ospf6_lsupdate_send_neighbor_now(struct ospf6_neighbor *on,
+                                           struct ospf6_lsa *lsa);
 
 #endif /* OSPF6_FLOOD_H */
index 98f93b06e67431fc0b6e1865088324aa93b479df..5eaf6177025321e1928380b2d8dbdc6bd32dab8e 100644 (file)
@@ -301,6 +301,7 @@ void ospf6_interface_disable(struct ospf6_interface *oi)
        THREAD_OFF(oi->thread_network_lsa);
        THREAD_OFF(oi->thread_link_lsa);
        THREAD_OFF(oi->thread_intra_prefix_lsa);
+       THREAD_OFF(oi->thread_as_extern_lsa);
 }
 
 static struct in6_addr *
@@ -532,6 +533,7 @@ static void ospf6_interface_state_change(u_char next_state,
                OSPF6_NETWORK_LSA_EXECUTE(oi);
                OSPF6_INTRA_PREFIX_LSA_EXECUTE_TRANSIT(oi);
                OSPF6_INTRA_PREFIX_LSA_SCHEDULE_STUB(oi->area);
+               OSPF6_INTRA_PREFIX_LSA_EXECUTE_TRANSIT(oi);
        } else if (prev_state == OSPF6_INTERFACE_DR
                   || next_state == OSPF6_INTERFACE_DR) {
                OSPF6_NETWORK_LSA_SCHEDULE(oi);
@@ -1008,6 +1010,103 @@ DEFUN (show_ipv6_ospf6_interface,
        return CMD_SUCCESS;
 }
 
+static int ospf6_interface_show_traffic(struct vty *vty,
+                                       uint32_t vrf_id,
+                                       struct interface *intf_ifp,
+                                       int display_once)
+{
+       struct interface *ifp;
+       struct vrf *vrf = NULL;
+       struct ospf6_interface *oi = NULL;
+
+       vrf = vrf_lookup_by_id(vrf_id);
+
+       if (!display_once) {
+               vty_out(vty, "\n");
+               vty_out(vty, "%-12s%-17s%-17s%-17s%-17s%-17s\n",
+                       "Interface", "    HELLO", "    DB-Desc", "   LS-Req",
+                       "   LS-Update", "   LS-Ack");
+               vty_out(vty, "%-10s%-18s%-18s%-17s%-17s%-17s\n", "",
+                       "      Rx/Tx", "     Rx/Tx", "    Rx/Tx", "    Rx/Tx", "    Rx/Tx");
+               vty_out(vty,
+               "--------------------------------------------------------------------------------------------\n");
+       }
+
+       if (intf_ifp == NULL) {
+               FOR_ALL_INTERFACES (vrf, ifp) {
+                       if (ifp->info)
+                               oi = (struct ospf6_interface *)ifp->info;
+                       else
+                               continue;
+
+                       vty_out(vty,
+                       "%-10s %8u/%-8u %7u/%-7u %7u/%-7u %7u/%-7u %7u/%-7u\n",
+                               oi->interface->name, oi->hello_in,
+                               oi->hello_out,
+                               oi->db_desc_in, oi->db_desc_out,
+                               oi->ls_req_in, oi->ls_req_out,
+                               oi->ls_upd_in, oi->ls_upd_out,
+                               oi->ls_ack_in, oi->ls_ack_out);
+               }
+       } else {
+               oi = intf_ifp->info;
+               if (oi == NULL)
+                       return CMD_WARNING;
+
+               vty_out(vty,
+                       "%-10s %8u/%-8u %7u/%-7u %7u/%-7u %7u/%-7u %7u/%-7u\n",
+                       oi->interface->name, oi->hello_in,
+                       oi->hello_out,
+                       oi->db_desc_in, oi->db_desc_out,
+                       oi->ls_req_in, oi->ls_req_out,
+                       oi->ls_upd_in, oi->ls_upd_out,
+                       oi->ls_ack_in, oi->ls_ack_out);
+       }
+
+       return CMD_SUCCESS;
+}
+
+/* show interface */
+DEFUN (show_ipv6_ospf6_interface_traffic,
+       show_ipv6_ospf6_interface_traffic_cmd,
+       "show ipv6 ospf6 interface traffic [IFNAME]",
+       SHOW_STR
+       IP6_STR
+       OSPF6_STR
+       INTERFACE_STR
+       "Protocol Packet counters\n"
+       IFNAME_STR)
+{
+       int idx_ifname = 0;
+       int display_once = 0;
+       char *intf_name = NULL;
+       struct interface *ifp = NULL;
+
+       if (argv_find(argv, argc, "IFNAME", &idx_ifname)) {
+               intf_name = argv[idx_ifname]->arg;
+               ifp = if_lookup_by_name(intf_name, VRF_DEFAULT);
+               if (ifp == NULL) {
+                       vty_out(vty,
+                               "No such Interface: %s\n",
+                               intf_name);
+                       return CMD_WARNING;
+               }
+               if (ifp->info == NULL) {
+                       vty_out(vty,
+                               "   OSPF not enabled on this interface %s\n",
+                               intf_name);
+                       return 0;
+               }
+       }
+
+       ospf6_interface_show_traffic(vty, VRF_DEFAULT, ifp,
+                                    display_once);
+
+
+       return CMD_SUCCESS;
+}
+
+
 DEFUN (show_ipv6_ospf6_interface_ifname_prefix,
        show_ipv6_ospf6_interface_ifname_prefix_cmd,
        "show ipv6 ospf6 interface IFNAME prefix [<X:X::X:X|X:X::X:X/M>] [<match|detail>]",
@@ -1841,6 +1940,8 @@ void ospf6_interface_init(void)
        install_element(VIEW_NODE, &show_ipv6_ospf6_interface_ifname_cmd);
        install_element(VIEW_NODE,
                        &show_ipv6_ospf6_interface_ifname_prefix_cmd);
+       install_element(VIEW_NODE,
+                       &show_ipv6_ospf6_interface_traffic_cmd);
 
        install_element(INTERFACE_NODE, &ipv6_ospf6_cost_cmd);
        install_element(INTERFACE_NODE, &no_ipv6_ospf6_cost_cmd);
index 3844132366e6ebe131cc82e1adb77f6ec0c4f21b..9b9952beb68317f6215cd96d844bd60e632f089e 100644 (file)
@@ -108,6 +108,7 @@ struct ospf6_interface {
        struct thread *thread_network_lsa;
        struct thread *thread_link_lsa;
        struct thread *thread_intra_prefix_lsa;
+       struct thread *thread_as_extern_lsa;
 
        struct ospf6_route_table *route_connected;
 
@@ -117,6 +118,19 @@ struct ospf6_interface {
        /* BFD information */
        void *bfd_info;
 
+       /* Statistics Fields */
+       u_int32_t hello_in;
+       u_int32_t hello_out;
+       u_int32_t db_desc_in;
+       u_int32_t db_desc_out;
+       u_int32_t ls_req_in;
+       u_int32_t ls_req_out;
+       u_int32_t ls_upd_in;
+       u_int32_t ls_upd_out;
+       u_int32_t ls_ack_in;
+       u_int32_t ls_ack_out;
+       u_int32_t discarded;
+
        QOBJ_FIELDS
 };
 DECLARE_QOBJ_TYPE(ospf6_interface)
index b1d940952ca09019b8cffe6b69e2f214729e56dc..77653ea33fa80f9dc5f42ed0a08677eae209f3b5 100644 (file)
@@ -1404,7 +1404,8 @@ void ospf6_intra_prefix_lsa_add(struct ospf6_lsa *lsa)
 
                if (IS_OSPF6_DEBUG_EXAMIN(INTRA_PREFIX)) {
                        prefix2str(&route->prefix, buf, sizeof(buf));
-                       zlog_debug("  route %s add", buf);
+                       zlog_debug("  route %s add with nh count %u", buf,
+                                  listcount(route->nh_list));
                }
 
                ospf6_route_add(route, oa->route_table);
index b511a92005342e302a81ae646d1997825e101b24..2ae17f07004b58472a4b1d5c76fd0e54ef9b10a1 100644 (file)
@@ -185,11 +185,21 @@ struct ospf6_intra_prefix_lsa {
                                0, &(oi)->thread_intra_prefix_lsa);            \
        } while (0)
 
+#define OSPF6_AS_EXTERN_LSA_SCHEDULE(oi)                                      \
+       do {                                                                   \
+               if (!CHECK_FLAG((oi)->flag, OSPF6_INTERFACE_DISABLE))          \
+                       thread_add_event(                                      \
+                               master,                                        \
+                               ospf6_orig_as_external_lsa, oi,                \
+                               0, &(oi)->thread_as_extern_lsa);               \
+       } while (0)
+
 #define OSPF6_NETWORK_LSA_EXECUTE(oi)                                          \
        do {                                                                   \
                THREAD_OFF((oi)->thread_network_lsa);                          \
                thread_execute(master, ospf6_network_lsa_originate, oi, 0);    \
        } while (0)
+
 #define OSPF6_INTRA_PREFIX_LSA_EXECUTE_TRANSIT(oi)                             \
        do {                                                                   \
                THREAD_OFF((oi)->thread_intra_prefix_lsa);                     \
@@ -198,6 +208,11 @@ struct ospf6_intra_prefix_lsa {
                               0);                                             \
        } while (0)
 
+#define OSPF6_AS_EXTERN_LSA_EXECUTE(oi)                                        \
+       do {                                                                   \
+               THREAD_OFF((oi)->thread_as_extern_lsa);                        \
+               thread_execute(master, ospf6_orig_as_external_lsa, oi, 0);     \
+       } while (0)
 
 /* Function Prototypes */
 extern char *ospf6_router_lsdesc_lookup(u_char type, u_int32_t interface_id,
@@ -215,7 +230,7 @@ extern int ospf6_intra_prefix_lsa_originate_transit(struct thread *);
 extern int ospf6_intra_prefix_lsa_originate_stub(struct thread *);
 extern void ospf6_intra_prefix_lsa_add(struct ospf6_lsa *lsa);
 extern void ospf6_intra_prefix_lsa_remove(struct ospf6_lsa *lsa);
-
+extern int ospf6_orig_as_external_lsa(struct thread *thread);
 extern void ospf6_intra_route_calculation(struct ospf6_area *oa);
 extern void ospf6_intra_brouter_calculation(struct ospf6_area *oa);
 
index 82f75b153eb204882b30faace2bd1d3bd501f8a0..4a1ba992e3de38770ff0d7dd805389acfdcc492f 100644 (file)
@@ -191,7 +191,7 @@ int ospf6_lsa_is_changed(struct ospf6_lsa *lsa1, struct ospf6_lsa *lsa2)
 
 /* ospf6 age functions */
 /* calculate birth */
-static void ospf6_lsa_age_set(struct ospf6_lsa *lsa)
+void ospf6_lsa_age_set(struct ospf6_lsa *lsa)
 {
        struct timeval now;
 
@@ -706,6 +706,37 @@ int ospf6_lsa_refresh(struct thread *thread)
        return 0;
 }
 
+void ospf6_flush_self_originated_lsas_now(void)
+{
+       struct listnode *node;
+       struct ospf6_area *oa;
+       struct ospf6_lsa *lsa;
+       const struct route_node *end = NULL;
+       uint32_t type, adv_router;
+
+       ospf6->inst_shutdown = 1;
+
+       for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, node, oa)) {
+               end = ospf6_lsdb_head(oa->lsdb_self, 0, 0,
+                                     ospf6->router_id, &lsa);
+               while (lsa) {
+                       /* RFC 2328 (14.1):  Set MAXAGE */
+                       lsa->header->age = htons(OSPF_LSA_MAXAGE);
+                       /* Flood MAXAGE LSA*/
+                       ospf6_flood(NULL, lsa);
+
+                       lsa = ospf6_lsdb_next(end, lsa);
+               }
+       }
+
+       type = htons(OSPF6_LSTYPE_AS_EXTERNAL);
+       adv_router = ospf6->router_id;
+       for (ALL_LSDB_TYPED_ADVRTR(ospf6->lsdb, type, adv_router, lsa)) {
+               /* RFC 2328 (14.1):  Set MAXAGE */
+               lsa->header->age = htons(OSPF_LSA_MAXAGE);
+               ospf6_flood(NULL, lsa);
+       }
+}
 
 /* Fletcher Checksum -- Refer to RFC1008. */
 
index 3536d33d19ab74b1fc57027a38bf1a9f32a57506..369b381faaed5f131b35a1a641ac4952c36624d9 100644 (file)
@@ -252,5 +252,7 @@ extern void ospf6_lsa_terminate(void);
 
 extern int config_write_ospf6_debug_lsa(struct vty *vty);
 extern void install_element_ospf6_debug_lsa(void);
+extern void ospf6_lsa_age_set(struct ospf6_lsa *lsa);
+extern void ospf6_flush_self_originated_lsas_now(void);
 
 #endif /* OSPF6_LSA_H */
index 418f858a3256a6684b240248a00d404289864fd7..152702391b6a3891dc92cf3318da419829a2c15c 100644 (file)
@@ -334,6 +334,7 @@ int ospf6_lsdb_maxage_remover(struct ospf6_lsdb *lsdb)
                }
                if (IS_OSPF6_DEBUG_LSA_TYPE(lsa->header->type))
                        zlog_debug("Remove MaxAge %s", lsa->name);
+
                if (CHECK_FLAG(lsa->flag, OSPF6_LSA_SEQWRAPPED)) {
                        UNSET_FLAG(lsa->flag, OSPF6_LSA_SEQWRAPPED);
                        /*
index 9a6729ee2a6aee8f820c43b95f92fa428234511a..88f03d8f646ec1d0d49b0bdc07e8cd3815e1f280 100644 (file)
@@ -97,6 +97,14 @@ static void __attribute__((noreturn)) ospf6_exit(int status)
        ospf6_asbr_terminate();
        ospf6_lsa_terminate();
 
+       /* reverse access_list_init */
+       access_list_reset();
+
+       /* reverse prefix_list_init */
+       prefix_list_add_hook(NULL);
+       prefix_list_delete_hook(NULL);
+       prefix_list_reset();
+
        vrf_terminate();
 
        if (zclient) {
index 56c232d6da98bbb90c07f2cef085e5fec8e56ca6..c008b54ce7b765a3502f6b0da358f6fdfaa93df9 100644 (file)
@@ -41,4 +41,6 @@ DEFINE_MTYPE(OSPF6D, OSPF6_VERTEX, "OSPF6 vertex")
 DEFINE_MTYPE(OSPF6D, OSPF6_SPFTREE, "OSPF6 SPF tree")
 DEFINE_MTYPE(OSPF6D, OSPF6_NEXTHOP, "OSPF6 nexthop")
 DEFINE_MTYPE(OSPF6D, OSPF6_EXTERNAL_INFO, "OSPF6 ext. info")
+DEFINE_MTYPE(OSPF6D, OSPF6_PATH, "OSPF6 Path")
+DEFINE_MTYPE(OSPF6D, OSPF6_DIST_ARGS, "OSPF6 Distribute arguments")
 DEFINE_MTYPE(OSPF6D, OSPF6_OTHER, "OSPF6 other")
index fe72ee3669763e89cdd4fe490bdb446dc90864e8..a97d677543f3a189492e6e4b79d94ce89805410a 100644 (file)
@@ -40,6 +40,8 @@ DECLARE_MTYPE(OSPF6_VERTEX)
 DECLARE_MTYPE(OSPF6_SPFTREE)
 DECLARE_MTYPE(OSPF6_NEXTHOP)
 DECLARE_MTYPE(OSPF6_EXTERNAL_INFO)
+DECLARE_MTYPE(OSPF6_PATH)
+DECLARE_MTYPE(OSPF6_DIST_ARGS)
 DECLARE_MTYPE(OSPF6_OTHER)
 
 #endif /* _QUAGGA_OSPF6_MEMORY_H */
index 1307b374a511c9d1c7c3bb65ca99b8b40449af1d..fe74ddc982ec00eab1310f27411a8db299080325 100644 (file)
@@ -321,6 +321,8 @@ static void ospf6_hello_recv(struct in6_addr *src, struct in6_addr *dst,
                        backupseen++;
        }
 
+       oi->hello_in++;
+
        /* Execute neighbor events */
        thread_execute(master, hello_received, on, 0);
        if (twoway)
@@ -776,6 +778,8 @@ static void ospf6_dbdesc_recv(struct in6_addr *src, struct in6_addr *dst,
                dbdesc->reserved2 = 0;
        }
 
+       oi->db_desc_in++;
+
        if (ntohl(oh->router_id) < ntohl(ospf6->router_id))
                ospf6_dbdesc_recv_master(oh, on);
        else if (ntohl(ospf6->router_id) < ntohl(oh->router_id))
@@ -811,6 +815,8 @@ static void ospf6_lsreq_recv(struct in6_addr *src, struct in6_addr *dst,
                return;
        }
 
+       oi->ls_req_in++;
+
        /* Process each request */
        for (p = (char *)((caddr_t)oh + sizeof(struct ospf6_header));
             p + sizeof(struct ospf6_lsreq_entry) <= OSPF6_MESSAGE_END(oh);
@@ -1370,6 +1376,8 @@ static void ospf6_lsupdate_recv(struct in6_addr *src, struct in6_addr *dst,
        lsupdate = (struct ospf6_lsupdate *)((caddr_t)oh
                                             + sizeof(struct ospf6_header));
 
+       oi->ls_upd_in++;
+
        /* Process LSAs */
        for (p = (char *)((caddr_t)lsupdate + sizeof(struct ospf6_lsupdate));
             p < OSPF6_MESSAGE_END(oh)
@@ -1407,6 +1415,8 @@ static void ospf6_lsack_recv(struct in6_addr *src, struct in6_addr *dst,
                return;
        }
 
+       oi->ls_ack_in++;
+
        for (p = (char *)((caddr_t)oh + sizeof(struct ospf6_header));
             p + sizeof(struct ospf6_lsa_header) <= OSPF6_MESSAGE_END(oh);
             p += sizeof(struct ospf6_lsa_header)) {
@@ -1777,6 +1787,8 @@ int ospf6_hello_send(struct thread *thread)
        oh->type = OSPF6_MESSAGE_TYPE_HELLO;
        oh->length = htons(p - sendbuf);
 
+       oi->hello_out++;
+
        ospf6_send(oi->linklocal_addr, &allspfrouters6, oi, oh);
        return 0;
 }
@@ -1852,6 +1864,8 @@ int ospf6_dbdesc_send(struct thread *thread)
        else
                dst = &on->linklocal_addr;
 
+       on->ospf6_if->db_desc_out++;
+
        ospf6_send(on->ospf6_if->linklocal_addr, dst, on->ospf6_if, oh);
 
        return 0;
@@ -1955,6 +1969,8 @@ int ospf6_lsreq_send(struct thread *thread)
        oh->type = OSPF6_MESSAGE_TYPE_LSREQ;
        oh->length = htons(p - sendbuf);
 
+       on->ospf6_if->ls_req_out++;
+
        if (on->ospf6_if->state == OSPF6_INTERFACE_POINTTOPOINT)
                ospf6_send(on->ospf6_if->linklocal_addr, &allspfrouters6,
                           on->ospf6_if, oh);
@@ -1979,6 +1995,8 @@ static void ospf6_send_lsupdate(struct ospf6_neighbor *on,
 {
 
        if (on) {
+               on->ospf6_if->ls_upd_out++;
+
                if ((on->ospf6_if->state == OSPF6_INTERFACE_POINTTOPOINT) ||
                    (on->ospf6_if->state == OSPF6_INTERFACE_DR) ||
                    (on->ospf6_if->state == OSPF6_INTERFACE_BDR)) {
@@ -1989,6 +2007,9 @@ static void ospf6_send_lsupdate(struct ospf6_neighbor *on,
                                   &on->linklocal_addr, on->ospf6_if, oh);
                }
        } else if (oi) {
+
+               oi->ls_upd_out++;
+
                if ((oi->state == OSPF6_INTERFACE_POINTTOPOINT) ||
                    (oi->state == OSPF6_INTERFACE_DR) ||
                    (oi->state == OSPF6_INTERFACE_BDR)) {
@@ -2142,6 +2163,40 @@ int ospf6_lsupdate_send_neighbor(struct thread *thread)
        return 0;
 }
 
+int ospf6_lsupdate_send_neighbor_now(struct ospf6_neighbor *on,
+                                    struct ospf6_lsa *lsa)
+{
+       struct ospf6_header *oh;
+       struct ospf6_lsupdate *lsupdate;
+       u_char *p;
+       int lsa_cnt = 0;
+
+       memset(sendbuf, 0, iobuflen);
+       oh = (struct ospf6_header *)sendbuf;
+       lsupdate = (struct ospf6_lsupdate *)((caddr_t)oh
+                                            + sizeof(struct ospf6_header));
+
+       p = (u_char *)((caddr_t)lsupdate + sizeof(struct ospf6_lsupdate));
+       ospf6_lsa_age_update_to_send(lsa, on->ospf6_if->transdelay);
+       memcpy(p, lsa->header, OSPF6_LSA_SIZE(lsa->header));
+       p += OSPF6_LSA_SIZE(lsa->header);
+       lsa_cnt++;
+
+       oh->type = OSPF6_MESSAGE_TYPE_LSUPDATE;
+       oh->length = htons(p - sendbuf);
+       lsupdate->lsa_number = htonl(lsa_cnt);
+
+       if (IS_OSPF6_DEBUG_FLOODING ||
+           IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_LSUPDATE, SEND))
+               zlog_debug("%s: Send lsupdate with lsa %s (age %u)",
+                  __PRETTY_FUNCTION__, lsa->name,
+                  ntohs(lsa->header->age));
+
+       ospf6_send_lsupdate(on, NULL, oh);
+
+       return 0;
+}
+
 int ospf6_lsupdate_send_interface(struct thread *thread)
 {
        struct ospf6_interface *oi;
@@ -2185,8 +2240,11 @@ int ospf6_lsupdate_send_interface(struct thread *thread)
                                lsupdate->lsa_number = htonl(lsa_cnt);
 
                                ospf6_send_lsupdate(NULL, oi, oh);
-                               zlog_debug("%s: LSUpdate length %d",
-                                  __PRETTY_FUNCTION__, ntohs(oh->length));
+                               if (IS_OSPF6_DEBUG_MESSAGE(
+                                       OSPF6_MESSAGE_TYPE_LSUPDATE, SEND))
+                                       zlog_debug("%s: LSUpdate length %d",
+                                                  __PRETTY_FUNCTION__,
+                                                  ntohs(oh->length));
 
                                memset(sendbuf, 0, iobuflen);
                                oh = (struct ospf6_header *)sendbuf;
@@ -2263,6 +2321,8 @@ int ospf6_lsack_send_neighbor(struct thread *thread)
                                oh->type = OSPF6_MESSAGE_TYPE_LSACK;
                                oh->length = htons(p - sendbuf);
 
+                               on->ospf6_if->ls_ack_out++;
+
                                ospf6_send(on->ospf6_if->linklocal_addr,
                                           &on->linklocal_addr,
                                           on->ospf6_if, oh);
@@ -2288,6 +2348,8 @@ int ospf6_lsack_send_neighbor(struct thread *thread)
                oh->type = OSPF6_MESSAGE_TYPE_LSACK;
                oh->length = htons(p - sendbuf);
 
+               on->ospf6_if->ls_ack_out++;
+
                ospf6_send(on->ospf6_if->linklocal_addr, &on->linklocal_addr,
                           on->ospf6_if, oh);
        }
index bde89f54a604b1be465f297c4d6caefec7d75d80..05bc254951baee01d9ab9034beb762587033a2b9 100644 (file)
@@ -189,6 +189,15 @@ static void ospf6_neighbor_state_change(u_char next_state,
                        OSPF6_INTRA_PREFIX_LSA_SCHEDULE_TRANSIT(on->ospf6_if);
                }
                OSPF6_INTRA_PREFIX_LSA_SCHEDULE_STUB(on->ospf6_if->area);
+
+               if (prev_state == OSPF6_NEIGHBOR_LOADING &&
+                   next_state == OSPF6_NEIGHBOR_FULL) {
+                       OSPF6_AS_EXTERN_LSA_SCHEDULE(on->ospf6_if);
+                       on->ospf6_if->area->full_nbrs++;
+               }
+
+               if (prev_state == OSPF6_NEIGHBOR_FULL)
+                       on->ospf6_if->area->full_nbrs--;
        }
 
        if ((prev_state == OSPF6_NEIGHBOR_EXCHANGE
index 281757222dd1d1b595ef7083af19a4144ab84062..19eb9a3fe660fa3d32629bb5c1358cf31be8038c 100644 (file)
@@ -215,7 +215,7 @@ void ospf6_copy_nexthops(struct list *dst, struct list *src)
                        if (ospf6_nexthop_is_set(nh)) {
                                nh_new = ospf6_nexthop_create();
                                ospf6_nexthop_copy(nh_new, nh);
-                               listnode_add(dst, nh_new);
+                               listnode_add_sort(dst, nh_new);
                        }
                }
        }
@@ -231,7 +231,7 @@ void ospf6_merge_nexthops(struct list *dst, struct list *src)
                        if (!ospf6_route_find_nexthop(dst, nh)) {
                                nh_new = ospf6_nexthop_create();
                                ospf6_nexthop_copy(nh_new, nh);
-                               listnode_add(dst, nh_new);
+                               listnode_add_sort(dst, nh_new);
                        }
                }
        }
@@ -315,6 +315,7 @@ void ospf6_route_zebra_copy_nexthops(struct ospf6_route *route,
                        if (i >= entries)
                                return;
 
+                       nexthops[i].vrf_id = VRF_DEFAULT;
                        nexthops[i].ifindex = nh->ifindex;
                        if (!IN6_IS_ADDR_UNSPECIFIED(&nh->address)) {
                                nexthops[i].gate.ipv6 = nh->address;
@@ -338,7 +339,7 @@ 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)
+int ospf6_nexthop_cmp(struct ospf6_nexthop *a, struct ospf6_nexthop *b)
 {
        if (a->ifindex < b->ifindex)
                return -1;
@@ -351,6 +352,36 @@ static int ospf6_nexthop_cmp(struct ospf6_nexthop *a, struct ospf6_nexthop *b)
        return 0;
 }
 
+static int ospf6_path_cmp(struct ospf6_path *a, struct ospf6_path *b)
+{
+       if (a->origin.adv_router < b->origin.adv_router)
+               return -1;
+       else if (a->origin.adv_router > b->origin.adv_router)
+               return 1;
+       else
+               return 0;
+}
+
+void ospf6_path_free(struct ospf6_path *op)
+{
+       if (op->nh_list)
+               list_delete_and_null(&op->nh_list);
+       XFREE(MTYPE_OSPF6_PATH, op);
+}
+
+struct ospf6_path *ospf6_path_dup(struct ospf6_path *path)
+{
+       struct ospf6_path *new;
+
+       new = XCALLOC(MTYPE_OSPF6_PATH, sizeof(struct ospf6_path));
+       memcpy(new, path, sizeof(struct ospf6_path));
+       new->nh_list = list_new();
+       new->nh_list->cmp = (int (*)(void *, void *))ospf6_nexthop_cmp;
+       new->nh_list->del = (void (*) (void *))ospf6_nexthop_delete;
+
+       return new;
+}
+
 struct ospf6_route *ospf6_route_create(void)
 {
        struct ospf6_route *route;
@@ -358,6 +389,9 @@ struct ospf6_route *ospf6_route_create(void)
        route->nh_list = list_new();
        route->nh_list->cmp = (int (*)(void *, void *))ospf6_nexthop_cmp;
        route->nh_list->del = (void (*) (void *))ospf6_nexthop_delete;
+       route->paths = list_new();
+       route->paths->cmp = (int (*)(void *, void *))ospf6_path_cmp;
+       route->paths->del =  (void (*)(void *))ospf6_path_free;
        return route;
 }
 
@@ -366,6 +400,8 @@ void ospf6_route_delete(struct ospf6_route *route)
        if (route) {
                if (route->nh_list)
                        list_delete_and_null(&route->nh_list);
+               if (route->paths)
+                       list_delete_and_null(&route->paths);
                XFREE(MTYPE_OSPF6_ROUTE, route);
        }
 }
@@ -464,7 +500,13 @@ ospf6_route_lookup_identical(struct ospf6_route *route,
 
        for (target = ospf6_route_lookup(&route->prefix, table); target;
             target = target->next) {
-               if (ospf6_route_is_identical(target, route))
+               if (target->type == route->type &&
+                   (memcmp(&target->prefix, &route->prefix,
+                          sizeof(struct prefix)) == 0) &&
+                   target->path.type == route->path.type &&
+                   target->path.cost == route->path.cost &&
+                   target->path.u.cost_e2 == route->path.u.cost_e2 &&
+                   ospf6_route_cmp_nexthops(target, route) == 0)
                        return target;
        }
        return NULL;
@@ -1083,6 +1125,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, "Paths count: %u\n", route->paths->count);
        vty_out(vty, "Nexthop count: %u\n", route->nh_list->count);
        /* Nexthops */
        vty_out(vty, "Nexthop:\n");
index 9eacadbdb7dee68e0254b84230965d369beb1b72..b759828c39a81371cf82621a0563d7926a65389a 100644 (file)
@@ -96,6 +96,9 @@ struct ospf6_path {
                u_int32_t cost_config;
        } u;
        u_int32_t tag;
+
+       /* nh list for this path */
+       struct list *nh_list;
 };
 
 #define OSPF6_PATH_TYPE_NONE         0
@@ -149,6 +152,9 @@ struct ospf6_route {
        /* path */
        struct ospf6_path path;
 
+       /* List of Paths. */
+       struct list *paths;
+
        /* nexthop */
        struct list *nh_list;
 };
@@ -256,6 +262,7 @@ extern void ospf6_linkstate_prefix2str(struct prefix *prefix, char *buf,
                                       int size);
 
 extern struct ospf6_nexthop *ospf6_nexthop_create(void);
+extern int ospf6_nexthop_cmp(struct ospf6_nexthop *a, struct ospf6_nexthop *b);
 extern void ospf6_nexthop_delete(struct ospf6_nexthop *nh);
 extern void ospf6_clear_nexthops(struct list *nh_list);
 extern int ospf6_num_nexthops(struct list *nh_list);
@@ -331,5 +338,7 @@ extern int config_write_ospf6_debug_route(struct vty *vty);
 extern void install_element_ospf6_debug_route(void);
 extern void ospf6_route_init(void);
 extern void ospf6_clean(void);
+extern void ospf6_path_free(struct ospf6_path *op);
+extern struct ospf6_path *ospf6_path_dup(struct ospf6_path *path);
 
 #endif /* OSPF6_ROUTE_H */
index 340d90159ff8d2d539a0d154d507c1b3ae5aba85..29ba1bcec7c396540fe569b4b560cc24d0b87850 100644 (file)
@@ -145,6 +145,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->cmp = (int (*)(void *, void *))ospf6_nexthop_cmp;
        v->nh_list->del = (void (*) (void *))ospf6_nexthop_delete;
 
        v->parent = NULL;
@@ -162,21 +163,20 @@ static void ospf6_vertex_delete(struct ospf6_vertex *v)
 }
 
 static struct ospf6_lsa *ospf6_lsdesc_lsa(caddr_t lsdesc,
-                                         struct ospf6_vertex *v,
-                                         uint32_t link_id)
+                                         struct ospf6_vertex *v)
 {
-       struct ospf6_lsa *lsa;
+       struct ospf6_lsa *lsa = NULL;
        u_int16_t type = 0;
        u_int32_t id = 0, adv_router = 0;
 
        if (VERTEX_IS_TYPE(NETWORK, v)) {
                type = htons(OSPF6_LSTYPE_ROUTER);
-               id = link_id;
+               id = htonl(0);
                adv_router = NETWORK_LSDESC_GET_NBR_ROUTERID(lsdesc);
        } else {
                if (ROUTER_LSDESC_IS_TYPE(POINTTOPOINT, lsdesc)) {
                        type = htons(OSPF6_LSTYPE_ROUTER);
-                       id = link_id;
+                       id = htonl(0);
                        adv_router = ROUTER_LSDESC_GET_NBR_ROUTERID(lsdesc);
                } else if (ROUTER_LSDESC_IS_TYPE(TRANSIT_NETWORK, lsdesc)) {
                        type = htons(OSPF6_LSTYPE_NETWORK);
@@ -185,19 +185,22 @@ static struct ospf6_lsa *ospf6_lsdesc_lsa(caddr_t lsdesc,
                }
        }
 
-       lsa = ospf6_lsdb_lookup(type, id, adv_router, v->area->lsdb);
-
+       if (type == htons(OSPF6_LSTYPE_NETWORK))
+               lsa = ospf6_lsdb_lookup(type, id, adv_router, v->area->lsdb);
+       else
+               lsa = ospf6_create_single_router_lsa(v->area, v->area->lsdb,
+                                                    adv_router);
        if (IS_OSPF6_DEBUG_SPF(PROCESS)) {
                char ibuf[16], abuf[16];
                inet_ntop(AF_INET, &id, ibuf, sizeof(ibuf));
                inet_ntop(AF_INET, &adv_router, abuf, sizeof(abuf));
                if (lsa)
-                       zlog_debug("  Link to: %s , V %s id %u", lsa->name,
-                                  v->name, link_id);
+                       zlog_debug("  Link to: %s len %u, V %s", lsa->name,
+                                  ntohs(lsa->header->length), v->name);
                else
-                       zlog_debug("  Link to: [%s Id:%s Adv:%s] No LSA , V %s id %u",
+                       zlog_debug("  Link to: [%s Id:%s Adv:%s] No LSA , V %s",
                                   ospf6_lstype_name(type), ibuf, abuf,
-                                  v->name, link_id);
+                                  v->name);
        }
 
        return lsa;
@@ -460,17 +463,14 @@ void ospf6_spf_calculation(u_int32_t router_id,
        struct ospf6_vertex *root, *v, *w;
        int size;
        caddr_t lsdesc;
-       struct ospf6_lsa *lsa, *self_rtr_lsa = NULL, *rtr_lsa = NULL;
-       const struct route_node *end = NULL;
+       struct ospf6_lsa *lsa;
        struct in6_addr address;
-       struct ospf6_lsdb *lsdb = NULL;
 
        ospf6_spf_table_finish(result_table);
 
        /* Install the calculating router itself as the root of the SPF tree */
        /* construct root vertex */
-       lsa = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_ROUTER), htonl(0), router_id,
-                               oa->lsdb_self);
+       lsa = ospf6_create_single_router_lsa(oa, oa->lsdb_self, router_id);
        if (lsa == NULL) {
                if (IS_OSPF6_DEBUG_SPF(PROCESS))
                        zlog_debug("%s: No router LSA for area %s\n", __func__,
@@ -478,8 +478,6 @@ void ospf6_spf_calculation(u_int32_t router_id,
                return;
        }
 
-       self_rtr_lsa = lsa;
-
        /* initialize */
        candidate_list = pqueue_create();
        candidate_list->cmp = ospf6_vertex_cmp;
@@ -509,139 +507,63 @@ void ospf6_spf_calculation(u_int32_t router_id,
                     && ospf6_router_is_stub_router(v->lsa)))
                        continue;
 
-               if (VERTEX_IS_TYPE(ROUTER, v)) {
-                       /* First fetch root Router LSAs from lsdb_self */
-                       if (v->lsa == self_rtr_lsa)
-                               lsdb = oa->lsdb_self;
-                       else
-                               lsdb = v->area->lsdb;
-
-                       /* Iterating multiple ROUTER LSAs from same adv router
-                        * with different Link State ID */
-                       end = ospf6_lsdb_head(lsdb, 2,
-                                       htons(OSPF6_LSTYPE_ROUTER),
-                                       v->lsa->header->adv_router,
-                                       &rtr_lsa);
-                       while (rtr_lsa) {
-                               if (IS_OSPF6_DEBUG_SPF(PROCESS))
-                                       zlog_debug("%s: Next LSA %s to process"
-                                                  ,__PRETTY_FUNCTION__,
-                                                 rtr_lsa->name);
-                               size = sizeof(struct ospf6_router_lsdesc);
-                               /* For each LS description in the just-added vertex V's LSA */
-                               for (lsdesc = OSPF6_LSA_HEADER_END(
-                                                       rtr_lsa->header) + 4;
-                                    lsdesc + size <= OSPF6_LSA_END(
-                                                       rtr_lsa->header);
-                                    lsdesc += size) {
-                                       lsa = ospf6_lsdesc_lsa(lsdesc, v,
-                                               rtr_lsa->header->id);
-                                       if (lsa == NULL)
-                                               continue;
-
-                                       if (OSPF6_LSA_IS_MAXAGE(lsa))
-                                               continue;
-
-                                       if (!ospf6_lsdesc_backlink(lsa,
-                                                                  lsdesc, v))
-                                               continue;
-
-                                       w = ospf6_vertex_create(lsa);
-                                       w->area = oa;
-                                       w->parent = v;
-                                       w->link_id = rtr_lsa->header->id;
-
-                                       if (VERTEX_IS_TYPE(ROUTER, v)) {
-                                               w->cost = v->cost
-                                               + ROUTER_LSDESC_GET_METRIC(lsdesc);
-                                               w->hops =
-                                                       v->hops
-                                                       + (VERTEX_IS_TYPE(NETWORK, w)
-                                                          ? 0 : 1);
-                                       } else /* NETWORK */ {
-                                               w->cost = v->cost;
-                                               w->hops = v->hops + 1;
-                                       }
-
-                                       /* nexthop calculation */
-                                       if (w->hops == 0)
-                                               ospf6_add_nexthop(w->nh_list,
-                                                       ROUTER_LSDESC_GET_IFID(lsdesc)
-                                                       , NULL);
-                                       else if (w->hops == 1 && v->hops == 0)
-                                               ospf6_nexthop_calc(w, v, lsdesc);
-                                       else {
-                                               ospf6_copy_nexthops(w->nh_list,
-                                                                   v->nh_list);
-                                       }
-
-                                       /* add new candidate to the candidate_list */
-                                       if (IS_OSPF6_DEBUG_SPF(PROCESS))
-                                               zlog_debug(
-                                                       "  New candidate: %s hops %d cost %d",
-                                                       w->name, w->hops,
-                                                       w->cost);
-                                       pqueue_enqueue(w, candidate_list);
-                               }
-                               /* Fetch next Link state ID Router LSA */
-                               rtr_lsa = ospf6_lsdb_next(end, rtr_lsa);
-                       }
-               } else {
-                       /* For each LS description in the just-added vertex V's LSA */
-                       size = (VERTEX_IS_TYPE(ROUTER, v)
-                                       ? sizeof(struct ospf6_router_lsdesc)
-                                       : sizeof(struct ospf6_network_lsdesc));
-                       for (lsdesc = OSPF6_LSA_HEADER_END(v->lsa->header) + 4;
-                            lsdesc + size <= OSPF6_LSA_END(v->lsa->header);
-                            lsdesc += size) {
-                               lsa = ospf6_lsdesc_lsa(lsdesc, v, v->link_id);
-                               if (lsa == NULL)
-                                       continue;
-
-                               if (OSPF6_LSA_IS_MAXAGE(lsa))
-                                       continue;
-
-                               if (!ospf6_lsdesc_backlink(lsa, lsdesc, v))
-                                       continue;
-
-                               w = ospf6_vertex_create(lsa);
-                               w->area = oa;
-                               w->parent = v;
-                               if (VERTEX_IS_TYPE(ROUTER, v)) {
-                                       w->cost = v->cost
+               /* For each LS description in the just-added vertex V's LSA */
+               size = (VERTEX_IS_TYPE(ROUTER, v)
+                               ? sizeof(struct ospf6_router_lsdesc)
+                               : sizeof(struct ospf6_network_lsdesc));
+               for (lsdesc = OSPF6_LSA_HEADER_END(v->lsa->header) + 4;
+                    lsdesc + size <= OSPF6_LSA_END(v->lsa->header);
+                    lsdesc += size) {
+                       lsa = ospf6_lsdesc_lsa(lsdesc, v);
+                       if (lsa == NULL)
+                               continue;
+
+                       if (OSPF6_LSA_IS_MAXAGE(lsa))
+                               continue;
+
+                       if (!ospf6_lsdesc_backlink(lsa, lsdesc, v))
+                               continue;
+
+                       w = ospf6_vertex_create(lsa);
+                       w->area = oa;
+                       w->parent = v;
+                       if (VERTEX_IS_TYPE(ROUTER, v)) {
+                               w->cost = v->cost
                                          + ROUTER_LSDESC_GET_METRIC(lsdesc);
-                                       w->hops =
-                                               v->hops
-                                               + (VERTEX_IS_TYPE(NETWORK, w) ?
-                                                  0 : 1);
-                               } else /* NETWORK */ {
-                                       w->cost = v->cost;
-                                       w->hops = v->hops + 1;
-                               }
-
-                               /* nexthop calculation */
-                               if (w->hops == 0)
-                                       ospf6_add_nexthop(w->nh_list,
+                               w->hops =
+                                       v->hops
+                                       + (VERTEX_IS_TYPE(NETWORK, w) ? 0 : 1);
+                       } else {
+                               /* NETWORK */
+                               w->cost = v->cost;
+                               w->hops = v->hops + 1;
+                       }
+
+                       /* nexthop calculation */
+                       if (w->hops == 0)
+                               ospf6_add_nexthop(
+                                       w->nh_list,
                                        ROUTER_LSDESC_GET_IFID(lsdesc), NULL);
-                               else if (w->hops == 1 && v->hops == 0)
-                                       ospf6_nexthop_calc(w, v, lsdesc);
-                               else {
-                                       ospf6_copy_nexthops(w->nh_list,
-                                                           v->nh_list);
-                               }
-
-                               /* add new candidate to the candidate_list */
-                               if (IS_OSPF6_DEBUG_SPF(PROCESS))
-                                       zlog_debug(
+                       else if (w->hops == 1 && v->hops == 0)
+                               ospf6_nexthop_calc(w, v, lsdesc);
+                       else
+                               ospf6_copy_nexthops(w->nh_list, v->nh_list);
+
+
+                       /* add new candidate to the candidate_list */
+                       if (IS_OSPF6_DEBUG_SPF(PROCESS))
+                               zlog_debug(
                                        "  New candidate: %s hops %d cost %d",
                                                w->name, w->hops, w->cost);
-                               pqueue_enqueue(w, candidate_list);
-                       }
+                       pqueue_enqueue(w, candidate_list);
                }
        }
 
+
        pqueue_delete(candidate_list);
 
+       ospf6_remove_temp_router_lsa(oa);
+
        oa->spf_calculation++;
 }
 
@@ -1028,3 +950,156 @@ void ospf6_spf_init(void)
        install_element(OSPF6_NODE, &ospf6_timers_throttle_spf_cmd);
        install_element(OSPF6_NODE, &no_ospf6_timers_throttle_spf_cmd);
 }
+
+/* Create Aggregated Large Router-LSA from multiple Link-State IDs
+ * RFC 5340 A 4.3:
+ * When more than one router-LSA is received from a single router,
+ * the links are processed as if concatenated into a single LSA.*/
+struct ospf6_lsa *ospf6_create_single_router_lsa(struct ospf6_area *area,
+                                                struct ospf6_lsdb *lsdb,
+                                                uint32_t adv_router)
+{
+       struct ospf6_lsa *lsa = NULL;
+       struct ospf6_lsa *rtr_lsa = NULL;
+       struct ospf6_lsa_header *lsa_header = NULL;
+       uint8_t *new_header = NULL;
+       const struct route_node *end = NULL;
+       uint16_t lsa_length, total_lsa_length = 0, num_lsa = 0;
+       u_int16_t type = 0;
+       char ifbuf[16];
+       uint32_t interface_id;
+       caddr_t lsd;
+
+       lsa_length = sizeof(struct ospf6_lsa_header) +
+                               sizeof(struct ospf6_router_lsa);
+       total_lsa_length = lsa_length;
+       type = htons(OSPF6_LSTYPE_ROUTER);
+
+       /* First check Aggregated LSA formed earlier in Cache */
+       lsa = ospf6_lsdb_lookup(type, htonl(0), adv_router,
+                               area->temp_router_lsa_lsdb);
+       if (lsa)
+               return lsa;
+
+       inet_ntop(AF_INET, &adv_router, ifbuf, sizeof(ifbuf));
+
+       /* Determine total LSA length from all link state ids */
+       end = ospf6_lsdb_head(lsdb, 2, type, adv_router, &rtr_lsa);
+       while (rtr_lsa) {
+               lsa = rtr_lsa;
+               if (OSPF6_LSA_IS_MAXAGE(rtr_lsa)) {
+                       rtr_lsa = ospf6_lsdb_next(end, rtr_lsa);
+                       continue;
+               }
+               lsa_header = (struct ospf6_lsa_header *) rtr_lsa->header;
+               total_lsa_length += (ntohs(lsa_header->length)
+                                    - lsa_length);
+               num_lsa++;
+               rtr_lsa = ospf6_lsdb_next(end, rtr_lsa);
+       }
+       if (IS_OSPF6_DEBUG_SPF(PROCESS))
+               zlog_debug("%s: adv_router %s num_lsa %u to convert.",
+                       __PRETTY_FUNCTION__, ifbuf, num_lsa);
+       if (num_lsa == 1)
+               return lsa;
+
+       if (num_lsa == 0) {
+               if (IS_OSPF6_DEBUG_SPF(PROCESS))
+                       zlog_debug("%s: adv_router %s not found in LSDB.",
+                                  __PRETTY_FUNCTION__, ifbuf);
+               return NULL;
+       }
+
+       /* Allocate memory for this LSA */
+       new_header = XMALLOC(MTYPE_OSPF6_LSA_HEADER, total_lsa_length);
+       if (!new_header)
+               return NULL;
+
+       /* LSA information structure */
+       lsa = (struct ospf6_lsa *)XCALLOC(MTYPE_OSPF6_LSA,
+                                         sizeof(struct ospf6_lsa));
+       if (!lsa) {
+               free(new_header);
+               return NULL;
+       }
+
+       lsa->header = (struct ospf6_lsa_header *)new_header;
+
+       lsa->lsdb = area->temp_router_lsa_lsdb;
+
+       /* Fill Larger LSA Payload */
+       end = ospf6_lsdb_head(lsdb, 2, type, adv_router, &rtr_lsa);
+
+       /*
+        * We assume at this point in time that rtr_lsa is
+        * a valid pointer.
+        */
+       assert(rtr_lsa);
+       if (!OSPF6_LSA_IS_MAXAGE(rtr_lsa)) {
+               /* Append first Link State ID LSA */
+               lsa_header = (struct ospf6_lsa_header *)rtr_lsa->header;
+               memcpy(new_header, lsa_header, ntohs(lsa_header->length));
+               /* Assign new lsa length as aggregated length. */
+               ((struct ospf6_lsa_header *)new_header)->length =
+                       htons(total_lsa_length);
+               new_header += ntohs(lsa_header->length);
+               num_lsa--;
+       }
+
+       /* Print LSA Name */
+       ospf6_lsa_printbuf(lsa, lsa->name, sizeof(lsa->name));
+
+       rtr_lsa = ospf6_lsdb_next(end, rtr_lsa);
+       while (rtr_lsa) {
+               if (OSPF6_LSA_IS_MAXAGE(rtr_lsa)) {
+                       rtr_lsa = ospf6_lsdb_next(end, rtr_lsa);
+                       continue;
+               }
+
+               if (IS_OSPF6_DEBUG_SPF(PROCESS)) {
+                       lsd = OSPF6_LSA_HEADER_END(rtr_lsa->header) + 4;
+                       interface_id = ROUTER_LSDESC_GET_IFID(lsd);
+                       inet_ntop(AF_INET, &interface_id, ifbuf, sizeof(ifbuf));
+                       zlog_debug("%s: Next Router LSA %s to aggreat with len %u interface_id %s",
+                                  __PRETTY_FUNCTION__, rtr_lsa->name,
+                                  ntohs(lsa_header->length), ifbuf);
+               }
+
+               /* Append Next Link State ID LSA */
+               lsa_header = (struct ospf6_lsa_header *) rtr_lsa->header;
+               memcpy(new_header, (OSPF6_LSA_HEADER_END(rtr_lsa->header) + 4),
+                      (ntohs(lsa_header->length) - lsa_length));
+               new_header += (ntohs(lsa_header->length) - lsa_length);
+               num_lsa--;
+
+               rtr_lsa = ospf6_lsdb_next(end, rtr_lsa);
+       }
+
+       /* Calculate birth of this lsa */
+       ospf6_lsa_age_set(lsa);
+
+       /* Store Aggregated LSA into area temp lsdb */
+       ospf6_lsdb_add(lsa, area->temp_router_lsa_lsdb);
+
+       if (IS_OSPF6_DEBUG_SPF(PROCESS))
+               zlog_debug("%s: LSA %s id %u type 0%x len %u num_lsa %u",
+                          __PRETTY_FUNCTION__, lsa->name,
+                          ntohl(lsa->header->id), ntohs(lsa->header->type),
+                          ntohs(lsa->header->length), num_lsa);
+
+       return lsa;
+}
+
+void ospf6_remove_temp_router_lsa(struct ospf6_area *area)
+{
+       struct ospf6_lsa *lsa = NULL;
+
+       for (ALL_LSDB(area->temp_router_lsa_lsdb, lsa)) {
+               if (IS_OSPF6_DEBUG_SPF(PROCESS))
+                       zlog_debug("%s Remove LSA %s lsa->lock %u lsdb count %u",
+                                  __PRETTY_FUNCTION__,
+                                  lsa->name, lsa->lock,
+                                  area->temp_router_lsa_lsdb->count);
+               ospf6_lsdb_remove(lsa, area->temp_router_lsa_lsdb);
+       }
+}
index dbb88d12ba0089525e7dda04f8ad9066b774af79..f294b8d34f33d9b747c2f77d7d66d7c964dfc39d 100644 (file)
@@ -149,5 +149,9 @@ extern int config_write_ospf6_debug_spf(struct vty *vty);
 extern void install_element_ospf6_debug_spf(void);
 extern void ospf6_spf_init(void);
 extern void ospf6_spf_reason_string(unsigned int reason, char *buf, int size);
+extern struct ospf6_lsa *ospf6_create_single_router_lsa(struct ospf6_area *area,
+                                                       struct ospf6_lsdb *lsdb,
+                                                       uint32_t adv_router);
+extern void ospf6_remove_temp_router_lsa(struct ospf6_area *area);
 
 #endif /* OSPF6_SPF_H */
index e0844765d3e423d83cd1184b47bd38aa9c74a703..25d968fb689e575dc3c5ada7240769ea6f2a2710 100644 (file)
@@ -95,6 +95,13 @@ static void ospf6_top_route_hook_remove(struct ospf6_route *route)
 
 static void ospf6_top_brouter_hook_add(struct ospf6_route *route)
 {
+       if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
+               char buf[PREFIX2STR_BUFFER];
+
+               prefix2str(&route->prefix, buf, sizeof(buf));
+               zlog_debug("%s: brouter %s add with nh count %u",
+                          __PRETTY_FUNCTION__, buf, listcount(route->nh_list));
+       }
        ospf6_abr_examin_brouter(ADV_ROUTER_IN_PREFIX(&route->prefix));
        ospf6_asbr_lsentry_add(route);
        ospf6_abr_originate_summary(route);
@@ -102,6 +109,13 @@ static void ospf6_top_brouter_hook_add(struct ospf6_route *route)
 
 static void ospf6_top_brouter_hook_remove(struct ospf6_route *route)
 {
+       if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
+               char buf[PREFIX2STR_BUFFER];
+
+               prefix2str(&route->prefix, buf, sizeof(buf));
+               zlog_debug("%s: brouter %s del with nh count %u",
+                          __PRETTY_FUNCTION__, buf, listcount(route->nh_list));
+       }
        route->flag |= OSPF6_ROUTE_REMOVE;
        ospf6_abr_examin_brouter(ADV_ROUTER_IN_PREFIX(&route->prefix));
        ospf6_asbr_lsentry_remove(route);
@@ -166,6 +180,8 @@ void ospf6_delete(struct ospf6 *o)
        struct ospf6_area *oa;
 
        QOBJ_UNREG(o);
+
+       ospf6_flush_self_originated_lsas_now();
        ospf6_disable(ospf6);
 
        for (ALL_LIST_ELEMENTS(o->area_list, node, nnode, oa))
@@ -210,6 +226,7 @@ static void ospf6_disable(struct ospf6 *o)
                THREAD_OFF(o->maxage_remover);
                THREAD_OFF(o->t_spf_calc);
                THREAD_OFF(o->t_ase_calc);
+               THREAD_OFF(o->t_distribute_update);
        }
 }
 
@@ -318,6 +335,8 @@ DEFUN(ospf6_router_id,
        int ret;
        const char *router_id_str;
        u_int32_t router_id;
+       struct ospf6_area *oa;
+       struct listnode *node;
 
        argv_find(argv, argc, "A.B.C.D", &idx);
        router_id_str = argv[idx]->arg;
@@ -329,8 +348,17 @@ DEFUN(ospf6_router_id,
        }
 
        o->router_id_static = router_id;
-       if (o->router_id == 0)
-               o->router_id = router_id;
+
+       for (ALL_LIST_ELEMENTS_RO(o->area_list, node, oa)) {
+               if (oa->full_nbrs) {
+                       vty_out(vty,
+                               "For this router-id change to take effect,"
+                               " save config and restart ospf6d\n");
+                       return CMD_SUCCESS;
+               }
+       }
+
+       o->router_id = router_id;
 
        return CMD_SUCCESS;
 }
@@ -343,8 +371,22 @@ DEFUN(no_ospf6_router_id,
       V4NOTATION_STR)
 {
        VTY_DECLVAR_CONTEXT(ospf6, o);
+       struct ospf6_area *oa;
+       struct listnode *node;
+
        o->router_id_static = 0;
+
+       for (ALL_LIST_ELEMENTS_RO(o->area_list, node, oa)) {
+               if (oa->full_nbrs) {
+                       vty_out(vty,
+                               "For this router-id change to take effect,"
+                               " save config and restart ospf6d\n");
+                       return CMD_SUCCESS;
+               }
+       }
        o->router_id = 0;
+       if (o->router_id_zebra.s_addr)
+               o->router_id = (uint32_t)o->router_id_zebra.s_addr;
 
        return CMD_SUCCESS;
 }
@@ -506,6 +548,10 @@ DEFUN (ospf6_distance_ospf6,
        VTY_DECLVAR_CONTEXT(ospf6, o);
        int idx = 0;
 
+       o->distance_intra = 0;
+       o->distance_inter = 0;
+       o->distance_external = 0;
+
        if (argv_find(argv, argc, "intra-area", &idx))
                o->distance_intra = atoi(argv[idx + 1]->arg);
        idx = 0;
index d8d34d0f3c7ff993a528511818e9e3f987fd8f7c..d7a3766b80498676b255c183f66c2d9473a0d16c 100644 (file)
@@ -32,6 +32,8 @@ struct ospf6 {
        /* static router id */
        u_int32_t router_id_static;
 
+       struct in_addr router_id_zebra;
+
        /* start time */
        struct timeval starttime;
 
@@ -82,6 +84,7 @@ struct ospf6 {
        struct thread *t_spf_calc; /* SPF calculation timer. */
        struct thread *t_ase_calc; /* ASE calculation timer. */
        struct thread *maxage_remover;
+       struct thread *t_distribute_update; /* Distirbute update timer. */
 
        u_int32_t ref_bandwidth;
 
@@ -93,6 +96,10 @@ struct ospf6 {
 
        struct route_table *distance_table;
 
+       /* Used during ospf instance going down send LSDB
+        * update to neighbors immediatly */
+       uint8_t inst_shutdown;
+
        QOBJ_FIELDS
 };
 DECLARE_QOBJ_TYPE(ospf6)
index cc87c499ee50af6e502bf382aa7907365adae65e..4fb959b952e63dbf64c0741878e9a7c1058e8587 100644 (file)
@@ -46,8 +46,6 @@ unsigned char conf_debug_ospf6_zebra = 0;
 /* information about zebra. */
 struct zclient *zclient = NULL;
 
-struct in_addr router_id_zebra;
-
 /* Router-id update message from zebra. */
 static int ospf6_router_id_update_zebra(int command, struct zclient *zclient,
                                        zebra_size_t length, vrf_id_t vrf_id)
@@ -56,13 +54,14 @@ static int ospf6_router_id_update_zebra(int command, struct zclient *zclient,
        struct ospf6 *o = ospf6;
 
        zebra_router_id_update_read(zclient->ibuf, &router_id);
-       router_id_zebra = router_id.u.prefix4;
 
        if (o == NULL)
                return 0;
 
+       o->router_id_zebra = router_id.u.prefix4;
+
        if (o->router_id == 0)
-               o->router_id = (u_int32_t)router_id_zebra.s_addr;
+               o->router_id = (uint32_t)o->router_id_zebra.s_addr;
 
        return 0;
 }
index d28d9dd06417010f54e60b9add8fe9d543f7cdfe..bbc1cc18f6ddac69e710075a1dbfc7b385c1ad09 100644 (file)
@@ -360,6 +360,49 @@ DEFUN (show_ipv6_ospf6_database_router,
        return CMD_SUCCESS;
 }
 
+DEFUN_HIDDEN (show_ipv6_ospf6_database_aggr_router,
+       show_ipv6_ospf6_database_aggr_router_cmd,
+       "show ipv6 ospf6 database aggr adv-router A.B.C.D",
+       SHOW_STR
+       IPV6_STR
+       OSPF6_STR
+       "Display Link state database\n"
+       "Aggregated Router LSA\n"
+       "Search by Advertising Router\n"
+       "Specify Advertising Router as IPv4 address notation\n")
+{
+       int level = OSPF6_LSDB_SHOW_LEVEL_DETAIL;
+       uint16_t type = htons(OSPF6_LSTYPE_ROUTER);
+       int idx_ipv4 = 6;
+       struct listnode *i;
+       struct ospf6 *o = ospf6;
+       struct ospf6_area *oa;
+       struct ospf6_lsdb *lsdb;
+       uint32_t adv_router = 0;
+
+       inet_pton(AF_INET, argv[idx_ipv4]->arg, &adv_router);
+
+       for (ALL_LIST_ELEMENTS_RO(o->area_list, i, oa)) {
+               if (adv_router == o->router_id)
+                       lsdb = oa->lsdb_self;
+               else
+                       lsdb = oa->lsdb;
+               if (ospf6_create_single_router_lsa(oa, lsdb,
+                                                  adv_router) == NULL) {
+                       vty_out(vty, "Adv router is not found in LSDB.");
+                       return CMD_SUCCESS;
+               }
+               ospf6_lsdb_show(vty, level, &type, NULL, NULL,
+                               oa->temp_router_lsa_lsdb);
+               /* Remove the temp cache */
+               ospf6_remove_temp_router_lsa(oa);
+       }
+
+       vty_out(vty, "\n");
+
+       return CMD_SUCCESS;
+}
+
 DEFUN (show_ipv6_ospf6_database_type_id,
        show_ipv6_ospf6_database_type_id_cmd,
        "show ipv6 ospf6 database <router|network|inter-prefix|inter-router|as-external|group-membership|type-7|link|intra-prefix> linkstate-id A.B.C.D [<detail|dump|internal>]",
@@ -1219,6 +1262,7 @@ void ospf6_init(void)
        install_element(
                VIEW_NODE,
                &show_ipv6_ospf6_database_type_self_originated_linkstate_id_cmd);
+       install_element(VIEW_NODE, &show_ipv6_ospf6_database_aggr_router_cmd);
 
        /* Make ospf protocol socket. */
        ospf6_serv_sock();
index dac6182fdeabca809ee7e50488b7d035ea851c08..905bd228b169692575331bc2f79228483ad996fd 100644 (file)
@@ -1,5 +1,3 @@
-$Id: OSPF-ALIGNMENT.txt,v 1.1 2004/11/17 17:59:52 gdt Exp $
-
 Greg Troxel <gdt@ir.bbn.com>
 2004-11-17
 
index f7aa94ad188c2f5042a98dec7f3f6a593dc982dd..ea94bab6b3b20ddeb11bae4ba9fa288f1155cc24 100644 (file)
@@ -327,8 +327,7 @@ static int ospf_abr_nssa_am_elected(struct ospf_area *area)
        struct router_lsa *rlsa;
        struct in_addr *best = NULL;
 
-       LSDB_LOOP(ROUTER_LSDB(area), rn, lsa)
-       {
+       LSDB_LOOP (ROUTER_LSDB(area), rn, lsa) {
                /* sanity checks */
                if (!lsa || (lsa->data->type != OSPF_ROUTER_LSA)
                    || IS_LSA_SELF(lsa))
@@ -978,7 +977,7 @@ static void ospf_abr_process_nssa_translates(struct ospf *ospf)
                                inet_ntoa(area->area_id));
 
                LSDB_LOOP(NSSA_LSDB(area), rn, lsa)
-               ospf_abr_translate_nssa(area, lsa);
+                       ospf_abr_translate_nssa(area, lsa);
        }
 
        if (IS_DEBUG_OSPF_NSSA)
@@ -1325,14 +1324,14 @@ ospf_abr_unapprove_translates(struct ospf *ospf) /* For NSSA Translations */
          and we would want to flush any residuals anyway */
 
        LSDB_LOOP(EXTERNAL_LSDB(ospf), rn, lsa)
-       if (CHECK_FLAG(lsa->flags, OSPF_LSA_LOCAL_XLT)) {
-               UNSET_FLAG(lsa->flags, OSPF_LSA_APPROVED);
-               if (IS_DEBUG_OSPF_NSSA)
-                       zlog_debug(
-                               "ospf_abr_unapprove_translates(): "
-                               "approved unset on link id %s",
-                               inet_ntoa(lsa->data->id));
-       }
+               if (CHECK_FLAG(lsa->flags, OSPF_LSA_LOCAL_XLT)) {
+                       UNSET_FLAG(lsa->flags, OSPF_LSA_APPROVED);
+                       if (IS_DEBUG_OSPF_NSSA)
+                               zlog_debug(
+                                       "ospf_abr_unapprove_translates(): "
+                                       "approved unset on link id %s",
+                                       inet_ntoa(lsa->data->id));
+               }
 
        if (IS_DEBUG_OSPF_NSSA)
                zlog_debug("ospf_abr_unapprove_translates(): Stop");
@@ -1355,24 +1354,24 @@ static void ospf_abr_unapprove_summaries(struct ospf *ospf)
                                "considering area %s",
                                inet_ntoa(area->area_id));
                LSDB_LOOP(SUMMARY_LSDB(area), rn, lsa)
-               if (ospf_lsa_is_self_originated(ospf, lsa)) {
-                       if (IS_DEBUG_OSPF_EVENT)
-                               zlog_debug(
-                                       "ospf_abr_unapprove_summaries(): "
-                                       "approved unset on summary link id %s",
-                                       inet_ntoa(lsa->data->id));
-                       UNSET_FLAG(lsa->flags, OSPF_LSA_APPROVED);
-               }
+                       if (ospf_lsa_is_self_originated(ospf, lsa)) {
+                               if (IS_DEBUG_OSPF_EVENT)
+                                       zlog_debug(
+                                               "ospf_abr_unapprove_summaries(): "
+                                               "approved unset on summary link id %s",
+                                               inet_ntoa(lsa->data->id));
+                               UNSET_FLAG(lsa->flags, OSPF_LSA_APPROVED);
+                       }
 
                LSDB_LOOP(ASBR_SUMMARY_LSDB(area), rn, lsa)
-               if (ospf_lsa_is_self_originated(ospf, lsa)) {
-                       if (IS_DEBUG_OSPF_EVENT)
-                               zlog_debug(
-                                       "ospf_abr_unapprove_summaries(): "
-                                       "approved unset on asbr-summary link id %s",
-                                       inet_ntoa(lsa->data->id));
-                       UNSET_FLAG(lsa->flags, OSPF_LSA_APPROVED);
-               }
+                       if (ospf_lsa_is_self_originated(ospf, lsa)) {
+                               if (IS_DEBUG_OSPF_EVENT)
+                                       zlog_debug(
+                                               "ospf_abr_unapprove_summaries(): "
+                                               "approved unset on asbr-summary link id %s",
+                                               inet_ntoa(lsa->data->id));
+                               UNSET_FLAG(lsa->flags, OSPF_LSA_APPROVED);
+                       }
        }
 
        if (IS_DEBUG_OSPF_EVENT)
@@ -1633,7 +1632,7 @@ static void ospf_abr_remove_unapproved_translates(struct ospf *ospf)
                zlog_debug("ospf_abr_remove_unapproved_translates(): Start");
 
        LSDB_LOOP(EXTERNAL_LSDB(ospf), rn, lsa)
-       ospf_abr_remove_unapproved_translates_apply(ospf, lsa);
+               ospf_abr_remove_unapproved_translates_apply(ospf, lsa);
 
        if (IS_DEBUG_OSPF_NSSA)
                zlog_debug("ospf_abr_remove_unapproved_translates(): Stop");
@@ -1657,14 +1656,14 @@ static void ospf_abr_remove_unapproved_summaries(struct ospf *ospf)
                                inet_ntoa(area->area_id));
 
                LSDB_LOOP(SUMMARY_LSDB(area), rn, lsa)
-               if (ospf_lsa_is_self_originated(ospf, lsa))
-                       if (!CHECK_FLAG(lsa->flags, OSPF_LSA_APPROVED))
-                               ospf_lsa_flush_area(lsa, area);
+                       if (ospf_lsa_is_self_originated(ospf, lsa))
+                               if (!CHECK_FLAG(lsa->flags, OSPF_LSA_APPROVED))
+                                       ospf_lsa_flush_area(lsa, area);
 
                LSDB_LOOP(ASBR_SUMMARY_LSDB(area), rn, lsa)
-               if (ospf_lsa_is_self_originated(ospf, lsa))
-                       if (!CHECK_FLAG(lsa->flags, OSPF_LSA_APPROVED))
-                               ospf_lsa_flush_area(lsa, area);
+                       if (ospf_lsa_is_self_originated(ospf, lsa))
+                               if (!CHECK_FLAG(lsa->flags, OSPF_LSA_APPROVED))
+                                       ospf_lsa_flush_area(lsa, area);
        }
 
        if (IS_DEBUG_OSPF_EVENT)
index 8c1ad5ff0caa471012b0345867654fe205d86481..9ebaeffa69d62720b69366c114f09be082e49cb2 100644 (file)
@@ -1313,22 +1313,28 @@ int ospf_apiserver_handle_sync_lsdb(struct ospf_apiserver *apiserv,
                        /* Check msg type. */
                        if (mask & Power2[OSPF_ROUTER_LSA])
                                LSDB_LOOP(ROUTER_LSDB(area), rn, lsa)
-                       apiserver_sync_callback(lsa, (void *)&param, seqnum);
+                                       apiserver_sync_callback(
+                                               lsa, (void *)&param, seqnum);
                        if (mask & Power2[OSPF_NETWORK_LSA])
                                LSDB_LOOP(NETWORK_LSDB(area), rn, lsa)
-                       apiserver_sync_callback(lsa, (void *)&param, seqnum);
+                                       apiserver_sync_callback(
+                                               lsa, (void *)&param, seqnum);
                        if (mask & Power2[OSPF_SUMMARY_LSA])
                                LSDB_LOOP(SUMMARY_LSDB(area), rn, lsa)
-                       apiserver_sync_callback(lsa, (void *)&param, seqnum);
+                                       apiserver_sync_callback(
+                                               lsa, (void *)&param, seqnum);
                        if (mask & Power2[OSPF_ASBR_SUMMARY_LSA])
                                LSDB_LOOP(ASBR_SUMMARY_LSDB(area), rn, lsa)
-                       apiserver_sync_callback(lsa, (void *)&param, seqnum);
+                                       apiserver_sync_callback(
+                                               lsa, (void *)&param, seqnum);
                        if (mask & Power2[OSPF_OPAQUE_LINK_LSA])
                                LSDB_LOOP(OPAQUE_LINK_LSDB(area), rn, lsa)
-                       apiserver_sync_callback(lsa, (void *)&param, seqnum);
+                                       apiserver_sync_callback(
+                                               lsa, (void *)&param, seqnum);
                        if (mask & Power2[OSPF_OPAQUE_AREA_LSA])
                                LSDB_LOOP(OPAQUE_AREA_LSDB(area), rn, lsa)
-                       apiserver_sync_callback(lsa, (void *)&param, seqnum);
+                                       apiserver_sync_callback(
+                                               lsa, (void *)&param, seqnum);
                }
        }
 
@@ -1336,14 +1342,16 @@ int ospf_apiserver_handle_sync_lsdb(struct ospf_apiserver *apiserv,
        if (ospf->lsdb) {
                if (mask & Power2[OSPF_AS_EXTERNAL_LSA])
                        LSDB_LOOP(EXTERNAL_LSDB(ospf), rn, lsa)
-               apiserver_sync_callback(lsa, (void *)&param, seqnum);
+                               apiserver_sync_callback(lsa, (void *)&param,
+                                                       seqnum);
        }
 
        /* For AS-external opaque LSAs */
        if (ospf->lsdb) {
                if (mask & Power2[OSPF_OPAQUE_AS_LSA])
                        LSDB_LOOP(OPAQUE_AS_LSDB(ospf), rn, lsa)
-               apiserver_sync_callback(lsa, (void *)&param, seqnum);
+                               apiserver_sync_callback(lsa, (void *)&param,
+                                                       seqnum);
        }
 
        /* Send a reply back to client with return code */
@@ -1945,16 +1953,19 @@ void ospf_apiserver_flush_opaque_lsa(struct ospf_apiserver *apiserv,
        case OSPF_OPAQUE_LINK_LSA:
                for (ALL_LIST_ELEMENTS(ospf->areas, node, nnode, area))
                        LSDB_LOOP(OPAQUE_LINK_LSDB(area), rn, lsa)
-               apiserver_flush_opaque_type_callback(lsa, (void *)&param, 0);
+                               apiserver_flush_opaque_type_callback(
+                                       lsa, (void *)&param, 0);
                break;
        case OSPF_OPAQUE_AREA_LSA:
                for (ALL_LIST_ELEMENTS(ospf->areas, node, nnode, area))
                        LSDB_LOOP(OPAQUE_AREA_LSDB(area), rn, lsa)
-               apiserver_flush_opaque_type_callback(lsa, (void *)&param, 0);
+                               apiserver_flush_opaque_type_callback(
+                                       lsa, (void *)&param, 0);
                break;
        case OSPF_OPAQUE_AS_LSA:
                LSDB_LOOP(OPAQUE_LINK_LSDB(ospf), rn, lsa)
-               apiserver_flush_opaque_type_callback(lsa, (void *)&param, 0);
+                       apiserver_flush_opaque_type_callback(lsa,
+                                                            (void *)&param, 0);
                break;
        default:
                break;
index 2f1b27f0f1966e0a1e85e07af59d9939b178b56e..d2af974833f490c21229943c937b79f9bde775ba 100644 (file)
@@ -649,7 +649,7 @@ static int ospf_ase_calculate_timer(struct thread *t)
 
                /* Calculate external route for each AS-external-LSA */
                LSDB_LOOP(EXTERNAL_LSDB(ospf), rn, lsa)
-               ospf_ase_calculate_route(ospf, lsa);
+                       ospf_ase_calculate_route(ospf, lsa);
 
                /*  This version simple adds to the table all NSSA areas  */
                if (ospf->anyNSSA)
@@ -661,11 +661,12 @@ static int ospf_ase_calculate_timer(struct thread *t)
 
                                if (area->external_routing == OSPF_AREA_NSSA)
                                        LSDB_LOOP(NSSA_LSDB(area), rn, lsa)
-                               ospf_ase_calculate_route(ospf, lsa);
+                                               ospf_ase_calculate_route(ospf,
+                                                                        lsa);
                        }
                /* kevinm: And add the NSSA routes in ospf_top */
                LSDB_LOOP(NSSA_LSDB(ospf), rn, lsa)
-               ospf_ase_calculate_route(ospf, lsa);
+                       ospf_ase_calculate_route(ospf, lsa);
 
                /* Compare old and new external routing table and install the
                   difference info zebra/kernel */
@@ -679,8 +680,9 @@ static int ospf_ase_calculate_timer(struct thread *t)
 
                monotime(&stop_time);
 
-               zlog_info("SPF Processing Time(usecs): External Routes: %lld\n",
-                         (stop_time.tv_sec - start_time.tv_sec) * 1000000LL
+               if (IS_DEBUG_OSPF_EVENT)
+                       zlog_info("SPF Processing Time(usecs): External Routes: %lld\n",
+                                 (stop_time.tv_sec - start_time.tv_sec) * 1000000LL
                                  + (stop_time.tv_usec - start_time.tv_usec));
        }
        return 0;
index 6a410f4ed3fd4d831a37754587f5bdd5096a210d..66ab59b816e494601d85dc9371fa8dc24297d396 100644 (file)
@@ -51,6 +51,8 @@ unsigned long conf_debug_ospf_lsa = 0;
 unsigned long conf_debug_ospf_zebra = 0;
 unsigned long conf_debug_ospf_nssa = 0;
 unsigned long conf_debug_ospf_te = 0;
+unsigned long conf_debug_ospf_ext = 0;
+unsigned long conf_debug_ospf_sr = 0;
 
 /* Enable debug option variables -- valid only session. */
 unsigned long term_debug_ospf_packet[5] = {0, 0, 0, 0, 0};
@@ -61,7 +63,8 @@ unsigned long term_debug_ospf_lsa = 0;
 unsigned long term_debug_ospf_zebra = 0;
 unsigned long term_debug_ospf_nssa = 0;
 unsigned long term_debug_ospf_te = 0;
-
+unsigned long term_debug_ospf_ext = 0;
+unsigned long term_debug_ospf_sr = 0;
 
 const char *ospf_redist_string(u_int route_type)
 {
@@ -1441,6 +1444,33 @@ DEFUN (no_debug_ospf_te,
        return CMD_SUCCESS;
 }
 
+DEFUN (debug_ospf_sr,
+       debug_ospf_sr_cmd,
+       "debug ospf sr",
+       DEBUG_STR
+       OSPF_STR
+       "OSPF-SR information\n")
+{
+       if (vty->node == CONFIG_NODE)
+               CONF_DEBUG_ON(sr, SR);
+       TERM_DEBUG_ON(sr, SR);
+       return CMD_SUCCESS;
+}
+
+DEFUN (no_debug_ospf_sr,
+       no_debug_ospf_sr_cmd,
+       "no debug ospf sr",
+       NO_STR
+       DEBUG_STR
+       OSPF_STR
+       "OSPF-SR information\n")
+{
+       if (vty->node == CONFIG_NODE)
+               CONF_DEBUG_OFF(sr, SR);
+       TERM_DEBUG_OFF(sr, SR);
+       return CMD_SUCCESS;
+}
+
 DEFUN (no_debug_ospf,
        no_debug_ospf_cmd,
        "no debug ospf",
@@ -1758,6 +1788,18 @@ static int config_write_debug(struct vty *vty)
                write = 1;
        }
 
+       /* debug ospf te */
+       if (IS_CONF_DEBUG_OSPF(te, TE) == OSPF_DEBUG_TE) {
+               vty_out(vty, "debug ospf%s te\n", str);
+               write = 1;
+       }
+
+       /* debug ospf sr */
+       if (IS_CONF_DEBUG_OSPF(sr, SR) == OSPF_DEBUG_SR) {
+               vty_out(vty, "debug ospf%s sr\n", str);
+               write = 1;
+       }
+
        return write;
 }
 
@@ -1774,6 +1816,7 @@ void debug_init()
        install_element(ENABLE_NODE, &debug_ospf_event_cmd);
        install_element(ENABLE_NODE, &debug_ospf_nssa_cmd);
        install_element(ENABLE_NODE, &debug_ospf_te_cmd);
+       install_element(ENABLE_NODE, &debug_ospf_sr_cmd);
        install_element(ENABLE_NODE, &no_debug_ospf_ism_cmd);
        install_element(ENABLE_NODE, &no_debug_ospf_nsm_cmd);
        install_element(ENABLE_NODE, &no_debug_ospf_lsa_cmd);
@@ -1781,6 +1824,7 @@ void debug_init()
        install_element(ENABLE_NODE, &no_debug_ospf_event_cmd);
        install_element(ENABLE_NODE, &no_debug_ospf_nssa_cmd);
        install_element(ENABLE_NODE, &no_debug_ospf_te_cmd);
+       install_element(ENABLE_NODE, &no_debug_ospf_sr_cmd);
 
        install_element(ENABLE_NODE, &show_debugging_ospf_instance_cmd);
        install_element(ENABLE_NODE, &debug_ospf_packet_cmd);
@@ -1809,12 +1853,14 @@ void debug_init()
        install_element(CONFIG_NODE, &debug_ospf_event_cmd);
        install_element(CONFIG_NODE, &debug_ospf_nssa_cmd);
        install_element(CONFIG_NODE, &debug_ospf_te_cmd);
+       install_element(CONFIG_NODE, &debug_ospf_sr_cmd);
        install_element(CONFIG_NODE, &no_debug_ospf_nsm_cmd);
        install_element(CONFIG_NODE, &no_debug_ospf_lsa_cmd);
        install_element(CONFIG_NODE, &no_debug_ospf_zebra_cmd);
        install_element(CONFIG_NODE, &no_debug_ospf_event_cmd);
        install_element(CONFIG_NODE, &no_debug_ospf_nssa_cmd);
        install_element(CONFIG_NODE, &no_debug_ospf_te_cmd);
+       install_element(CONFIG_NODE, &no_debug_ospf_sr_cmd);
 
        install_element(CONFIG_NODE, &debug_ospf_instance_nsm_cmd);
        install_element(CONFIG_NODE, &debug_ospf_instance_lsa_cmd);
index ead2f526ba0ee5de0eee1a6017c7ed12376875d9..99d7512f16f19c30a44d6171d43085d230eb4930 100644 (file)
@@ -57,6 +57,8 @@
 #define OSPF_DEBUG_EVENT        0x01
 #define OSPF_DEBUG_NSSA                0x02
 #define OSPF_DEBUG_TE          0x04
+#define OSPF_DEBUG_EXT         0x08
+#define OSPF_DEBUG_SR          0x10
 
 /* Macro for setting debug option. */
 #define CONF_DEBUG_PACKET_ON(a, b)         conf_debug_ospf_packet[a] |= (b)
 /* Macro for checking debug option. */
 #define IS_DEBUG_OSPF_PACKET(a, b) (term_debug_ospf_packet[a] & OSPF_DEBUG_##b)
 #define IS_DEBUG_OSPF(a, b) (term_debug_ospf_##a & OSPF_DEBUG_##b)
-#define IS_DEBUG_OSPF_EVENT IS_DEBUG_OSPF(event,EVENT)
+#define IS_DEBUG_OSPF_EVENT IS_DEBUG_OSPF(event, EVENT)
 
-#define IS_DEBUG_OSPF_NSSA  IS_DEBUG_OSPF(nssa,NSSA)
+#define IS_DEBUG_OSPF_NSSA  IS_DEBUG_OSPF(nssa, NSSA)
 
-#define IS_DEBUG_OSPF_TE  IS_DEBUG_OSPF(te,TE)
+#define IS_DEBUG_OSPF_TE  IS_DEBUG_OSPF(te, TE)
+
+#define IS_DEBUG_OSPF_EXT  IS_DEBUG_OSPF(ext, EXT)
+
+#define IS_DEBUG_OSPF_SR  IS_DEBUG_OSPF(sr, SR)
 
 #define IS_CONF_DEBUG_OSPF_PACKET(a, b)                                        \
        (conf_debug_ospf_packet[a] & OSPF_DEBUG_##b)
@@ -119,6 +125,8 @@ extern unsigned long term_debug_ospf_lsa;
 extern unsigned long term_debug_ospf_zebra;
 extern unsigned long term_debug_ospf_nssa;
 extern unsigned long term_debug_ospf_te;
+extern unsigned long term_debug_ospf_ext;
+extern unsigned long term_debug_ospf_sr;
 
 /* Message Strings. */
 extern char *ospf_lsa_type_str[];
diff --git a/ospfd/ospf_ext.c b/ospfd/ospf_ext.c
new file mode 100644 (file)
index 0000000..d7faf4b
--- /dev/null
@@ -0,0 +1,1827 @@
+/*
+ * This is an implementation of RFC7684 OSPFv2 Prefix/Link Attribute
+ * Advertisement
+ *
+ * Module name: Extended Prefix/Link Opaque LSA
+ *
+ * Author: Olivier Dugeon <olivier.dugeon@orange.com>
+ * Author: Anselme Sawadogo <anselmesawadogo@gmail.com>
+ *
+ * Copyright (C) 2016 - 2018 Orange Labs http://www.orange.com
+ *
+ * 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 <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "linklist.h"
+#include "prefix.h"
+#include "if.h"
+#include "table.h"
+#include "memory.h"
+#include "command.h"
+#include "vty.h"
+#include "stream.h"
+#include "log.h"
+#include "thread.h"
+#include "hash.h"
+#include "sockunion.h" /* for inet_aton() */
+#include "network.h"
+#include "if.h"
+#include "libospf.h" /* for ospf interface types */
+
+#include "ospfd/ospfd.h"
+#include "ospfd/ospf_interface.h"
+#include "ospfd/ospf_ism.h"
+#include "ospfd/ospf_asbr.h"
+#include "ospfd/ospf_lsa.h"
+#include "ospfd/ospf_lsdb.h"
+#include "ospfd/ospf_neighbor.h"
+#include "ospfd/ospf_nsm.h"
+#include "ospfd/ospf_flood.h"
+#include "ospfd/ospf_packet.h"
+#include "ospfd/ospf_spf.h"
+#include "ospfd/ospf_dump.h"
+#include "ospfd/ospf_route.h"
+#include "ospfd/ospf_ase.h"
+#include "ospfd/ospf_zebra.h"
+#include "ospfd/ospf_sr.h"
+#include "ospfd/ospf_ext.h"
+
+/* Following structure are internal use only. */
+
+/*
+ * Global variable to manage Extended Prefix/Link Opaque LSA on this node.
+ * Note that all parameter values are stored in network byte order.
+ */
+static struct ospf_ext_lp OspfEXT;
+
+/*
+ * -----------------------------------------------------------------------
+ * Followings are initialize/terminate functions for Extended Prefix/Link
+ * Opaque LSA handling.
+ * -----------------------------------------------------------------------
+ */
+
+/* Extended Prefix Opaque LSA related callback functions */
+static void ospf_ext_pref_ism_change(struct ospf_interface *oi, int old_status);
+static void ospf_ext_pref_show_info(struct vty *vty, struct ospf_lsa *lsa);
+static int ospf_ext_pref_lsa_originate(void *arg);
+static struct ospf_lsa *ospf_ext_pref_lsa_refresh(struct ospf_lsa *lsa);
+static void ospf_ext_pref_lsa_schedule(struct ext_itf *exti,
+                                      enum lsa_opcode opcode);
+/* Extended Link Opaque LSA related callback functions */
+static int ospf_ext_link_new_if(struct interface *ifp);
+static int ospf_ext_link_del_if(struct interface *ifp);
+static void ospf_ext_link_ism_change(struct ospf_interface *oi, int old_status);
+static void ospf_ext_link_nsm_change(struct ospf_neighbor *nbr, int old_status);
+static void ospf_ext_link_show_info(struct vty *vty, struct ospf_lsa *lsa);
+static int ospf_ext_link_lsa_originate(void *arg);
+static struct ospf_lsa *ospf_ext_link_lsa_refresh(struct ospf_lsa *lsa);
+static void ospf_ext_link_lsa_schedule(struct ext_itf *exti,
+                                      enum lsa_opcode opcode);
+static void ospf_ext_lsa_schedule(struct ext_itf *exti, enum lsa_opcode op);
+static int ospf_ext_link_lsa_update(struct ospf_lsa *lsa);
+static int ospf_ext_pref_lsa_update(struct ospf_lsa *lsa);
+static void del_ext_info(void *val);
+
+/*
+ * Extended Link/Prefix initialization
+ *
+ * @param - none
+ *
+ * @return - 0 if OK, <> 0 otherwise
+ */
+int ospf_ext_init(void)
+{
+       int rc = 0;
+
+       memset(&OspfEXT, 0, sizeof(struct ospf_ext_lp));
+       OspfEXT.enabled = false;
+       /* Only Area flooding is supported yet */
+       OspfEXT.scope = OSPF_OPAQUE_AREA_LSA;
+       /* Initialize interface list */
+       OspfEXT.iflist = list_new();
+       OspfEXT.iflist->del = del_ext_info;
+
+       zlog_info("EXT (%s): Register Extended Link Opaque LSA", __func__);
+       rc = ospf_register_opaque_functab(
+               OSPF_OPAQUE_AREA_LSA, OPAQUE_TYPE_EXTENDED_LINK_LSA,
+               ospf_ext_link_new_if,        /* new if */
+               ospf_ext_link_del_if,        /* del if */
+               ospf_ext_link_ism_change,    /* ism change */
+               ospf_ext_link_nsm_change,    /* nsm change */
+               NULL,                        /* Write router config. */
+               NULL,                        /* Write interface conf. */
+               NULL,                        /* Write debug config. */
+               ospf_ext_link_show_info,     /* Show LSA info */
+               ospf_ext_link_lsa_originate, /* Originate LSA */
+               ospf_ext_link_lsa_refresh,   /* Refresh LSA */
+               ospf_ext_link_lsa_update,    /* new_lsa_hook */
+               NULL);                       /* del_lsa_hook */
+
+       if (rc != 0) {
+               zlog_warn("EXT (%s): Failed to register Extended Link LSA",
+                         __func__);
+               return rc;
+       }
+
+       zlog_info("EXT (%s): Register Extended Prefix Opaque LSA", __func__);
+       rc = ospf_register_opaque_functab(
+               OspfEXT.scope, OPAQUE_TYPE_EXTENDED_PREFIX_LSA,
+               NULL,                        /* new if handle by link */
+               NULL,                        /* del if handle by link */
+               ospf_ext_pref_ism_change,    /* ism change */
+               NULL,                        /* nsm change */
+               ospf_sr_config_write_router, /* Write router config. */
+               NULL,                        /* Write interface conf. */
+               NULL,                        /* Write debug config. */
+               ospf_ext_pref_show_info,     /* Show LSA info */
+               ospf_ext_pref_lsa_originate, /* Originate LSA */
+               ospf_ext_pref_lsa_refresh,   /* Refresh LSA */
+               ospf_ext_pref_lsa_update,    /* new_lsa_hook */
+               NULL);                       /* del_lsa_hook */
+       if (rc != 0) {
+               zlog_warn("EXT (%s): Failed to register Extended Prefix LSA",
+                         __func__);
+               return rc;
+       }
+
+       return rc;
+}
+
+/*
+ * Extended Link/Prefix termination function
+ *
+ * @param - none
+ * @return - none
+ */
+void ospf_ext_term(void)
+{
+
+       if ((OspfEXT.scope != OSPF_OPAQUE_AREA_LSA)
+           && (OspfEXT.scope != OSPF_OPAQUE_AS_LSA))
+               zlog_warn(
+                       "EXT: Unable to unregister Extended Prefix "
+                       "Opaque LSA functions: Wrong scope!");
+       else
+               ospf_delete_opaque_functab(OspfEXT.scope,
+                                          OPAQUE_TYPE_EXTENDED_PREFIX_LSA);
+
+       ospf_delete_opaque_functab(OSPF_OPAQUE_AREA_LSA,
+                                  OPAQUE_TYPE_EXTENDED_LINK_LSA);
+
+       list_delete_and_null(&OspfEXT.iflist);
+       OspfEXT.scope = 0;
+       OspfEXT.enabled = false;
+
+       return;
+}
+
+/*
+ * Extended Link/Prefix finish function
+ *
+ * @param - none
+ * @return - none
+ */
+void ospf_ext_finish(void)
+{
+       // list_delete_all_node(OspfEXT.iflist);
+       OspfEXT.enabled = false;
+}
+
+/*
+ * ---------------------------------------------------------------------
+ * Followings are control functions for Extended Prefix/Link Opaque LSA
+ * parameters management.
+ * ---------------------------------------------------------------------
+ */
+
+/* Functions to free memory space */
+static void del_ext_info(void *val)
+{
+       XFREE(MTYPE_OSPF_EXT_PARAMS, val);
+}
+
+/* Increment instance value for Extended Prefix Opaque LSAs Opaque ID field */
+static uint32_t get_ext_pref_instance_value(void)
+{
+       static uint32_t seqno = 0;
+
+       if (seqno < MAX_LEGAL_EXT_INSTANCE_NUM)
+               seqno += 1;
+       else
+               seqno = 1; /* Avoid zero. */
+
+       return seqno;
+}
+
+/* Increment instance value for Extended Link Opaque LSAs Opaque ID field */
+static uint32_t get_ext_link_instance_value(void)
+{
+       static uint32_t seqno = 0;
+
+       if (seqno < MAX_LEGAL_EXT_INSTANCE_NUM)
+               seqno += 1;
+       else
+               seqno = 1; /* Avoid zero. */
+
+       return seqno;
+}
+
+/* Lookup Extended Prefix/Links by ifp from OspfEXT struct iflist */
+static struct ext_itf *lookup_ext_by_ifp(struct interface *ifp)
+{
+       struct listnode *node, *nnode;
+       struct ext_itf *exti;
+
+       for (ALL_LIST_ELEMENTS(OspfEXT.iflist, node, nnode, exti))
+               if (exti->ifp == ifp)
+                       return exti;
+
+       return NULL;
+}
+
+/* Lookup Extended Prefix/Links by LSA ID from OspfEXT struct iflist */
+static struct ext_itf *lookup_ext_by_instance(struct ospf_lsa *lsa)
+{
+       struct listnode *node;
+       struct ext_itf *exti;
+       uint32_t key = GET_OPAQUE_ID(ntohl(lsa->data->id.s_addr));
+       uint8_t type = GET_OPAQUE_TYPE(ntohl(lsa->data->id.s_addr));
+
+
+       for (ALL_LIST_ELEMENTS_RO(OspfEXT.iflist, node, exti))
+               if ((exti->instance == key) && (exti->type == type))
+                       return exti;
+
+       return NULL;
+}
+
+/*
+ * ----------------------------------------------------------------------
+ * The underlying subsection defines setters and unsetters to create and
+ * delete tlvs and subtlvs
+ * ----------------------------------------------------------------------
+ */
+
+/* Extended Prefix TLV - RFC7684 section 2.1 */
+static void set_ext_prefix(struct ext_itf *exti, uint8_t route_type,
+                          uint8_t flags, struct prefix_ipv4 p)
+{
+
+       TLV_TYPE(exti->prefix) = htons(EXT_TLV_PREFIX);
+       /* Warning: Size must be adjust depending of subTLV's */
+       TLV_LEN(exti->prefix) = htons(EXT_TLV_PREFIX_SIZE);
+       exti->prefix.route_type = route_type;
+       exti->prefix.flags = flags;
+       /* Only Address Family Ipv4 (0) is defined in RFC 7684 */
+       exti->prefix.af = 0;
+       exti->prefix.pref_length = p.prefixlen;
+       exti->prefix.address = p.prefix;
+}
+
+/* Extended Link TLV - RFC7684 section 3.1 */
+static void set_ext_link(struct ext_itf *exti, uint8_t type, struct in_addr id,
+                        struct in_addr data)
+{
+
+       TLV_TYPE(exti->link) = htons(EXT_TLV_LINK);
+       /* Warning: Size must be adjust depending of subTLV's */
+       TLV_LEN(exti->link) = htons(EXT_TLV_LINK_SIZE);
+       exti->link.link_type = type;
+       exti->link.link_id = id;
+       exti->link.link_data = data;
+}
+
+/* Prefix SID SubTLV - section 5 */
+static void set_prefix_sid(struct ext_itf *exti, uint8_t algorithm,
+                          uint32_t value, int value_type, uint8_t flags)
+{
+
+       if ((algorithm != SR_ALGORITHM_SPF)
+           && (algorithm != SR_ALGORITHM_STRICT_SPF)) {
+               zlog_warn(
+                       "EXT (%s): unrecognized algorithm, not SPF or S-SPF",
+                       __func__);
+               return;
+       }
+
+       /* Update flags according to the type of value field: label or index */
+       if (value_type == SID_LABEL)
+               SET_FLAG(flags, EXT_SUBTLV_PREFIX_SID_VFLG);
+
+       /* set prefix sid subtlv for an extended prefix tlv */
+       TLV_TYPE(exti->node_sid) = htons(EXT_SUBTLV_PREFIX_SID);
+       exti->node_sid.algorithm = algorithm;
+       exti->node_sid.flags = flags;
+       exti->node_sid.mtid = 0; /* Multi-Topology is not supported */
+
+       /* Set Label or Index value */
+       if (value_type == SID_LABEL) {
+               TLV_LEN(exti->node_sid) = htons(SID_LABEL_SIZE);
+               exti->node_sid.value = htonl(SET_LABEL(value));
+       } else {
+               TLV_LEN(exti->node_sid) = htons(SID_INDEX_SIZE);
+               exti->node_sid.value = htonl(value);
+       }
+
+}
+
+/* Adjacency SID SubTLV - section 6.1 */
+static void set_adj_sid(struct ext_itf *exti, bool backup, uint32_t value,
+                       int value_type)
+{
+       int index;
+       uint8_t flags;
+
+       /* Determine which ADJ_SID must be set: nominal or backup */
+       if (backup) {
+               flags = EXT_SUBTLV_LINK_ADJ_SID_BFLG;
+               index = 1;
+       } else {
+               index = 0;
+               flags = 0;
+       }
+
+       /* Set Header */
+       TLV_TYPE(exti->adj_sid[index]) = htons(EXT_SUBTLV_ADJ_SID);
+
+       /* Only Local ADJ-SID is supported for the moment */
+       SET_FLAG(flags, EXT_SUBTLV_LINK_ADJ_SID_LFLG);
+
+       exti->adj_sid[index].mtid = 0; /* Multi-Topology is not supported */
+
+       /* Adjust Length, Flags and Value depending on the type of Label */
+       if (value_type == SID_LABEL) {
+               SET_FLAG(flags, EXT_SUBTLV_LINK_ADJ_SID_VFLG);
+               TLV_LEN(exti->adj_sid[index]) = htons(SID_LABEL_SIZE);
+               exti->adj_sid[index].value = htonl(SET_LABEL(value));
+       } else {
+               UNSET_FLAG(flags, EXT_SUBTLV_LINK_ADJ_SID_VFLG);
+               TLV_LEN(exti->adj_sid[index]) = htons(SID_INDEX_SIZE);
+               exti->adj_sid[index].value = htonl(value);
+       }
+
+       exti->adj_sid[index].flags = flags; /* Set computed flags */
+       exti->adj_sid[index].mtid = 0;   /* Multi-Topology is not supported */
+       exti->adj_sid[index].weight = 0; /* Load-Balancing is not supported */
+
+}
+
+/* LAN Adjacency SID SubTLV - section 6.2 */
+static void set_lan_adj_sid(struct ext_itf *exti, bool backup, uint32_t value,
+                           int value_type, struct in_addr neighbor_id)
+{
+
+       int index;
+       uint8_t flags;
+
+       /* Determine which ADJ_SID must be set: nominal or backup */
+       if (backup) {
+               flags = EXT_SUBTLV_LINK_ADJ_SID_BFLG;
+               index = 1;
+       } else {
+               index = 0;
+               flags = 0;
+       }
+
+       /* Set Header */
+       TLV_TYPE(exti->lan_sid[index]) = htons(EXT_SUBTLV_ADJ_SID);
+
+       /* Only Local ADJ-SID is supported for the moment */
+       SET_FLAG(flags, EXT_SUBTLV_LINK_ADJ_SID_LFLG);
+
+       /* Adjust Length, Flags and Value depending on the type of Label */
+       if (value_type == SID_LABEL) {
+               SET_FLAG(flags, EXT_SUBTLV_LINK_ADJ_SID_VFLG);
+               TLV_LEN(exti->lan_sid[index]) = htons(SID_LABEL_SIZE);
+               exti->lan_sid[index].value = htonl(SET_LABEL(value));
+       } else {
+               UNSET_FLAG(flags, EXT_SUBTLV_LINK_ADJ_SID_VFLG);
+               TLV_LEN(exti->lan_sid[index]) = htons(SID_INDEX_SIZE);
+               exti->lan_sid[index].value = htonl(value);
+       }
+
+       exti->lan_sid[index].flags = flags; /* Set computed flags */
+       exti->lan_sid[index].mtid = 0;   /* Multi-Topology is not supported */
+       exti->lan_sid[index].weight = 0; /* Load-Balancing is not supported */
+       exti->lan_sid[index].neighbor_id = neighbor_id;
+
+}
+
+/* Experimental SubTLV from Cisco */
+static void set_rmt_itf_addr(struct ext_itf *exti, struct in_addr rmtif)
+{
+
+       TLV_TYPE(exti->rmt_itf_addr) = htons(EXT_SUBTLV_RMT_ITF_ADDR);
+       TLV_LEN(exti->rmt_itf_addr) = htons(sizeof(struct in_addr));
+       exti->rmt_itf_addr.value = rmtif;
+
+}
+
+/*
+ * Update Extended prefix SID index for Loopback interface type
+ *
+ * @param ifname - Loopback interface name
+ * @param index - new value for the prefix SID of this interface
+ * @param p - prefix for this interface or NULL if Extended Prefix
+ * should be remove
+ *
+ * @return instance number if update is OK, 0 otherwise
+ */
+uint32_t ospf_ext_schedule_prefix_index(struct interface *ifp, uint32_t index,
+                                       struct prefix_ipv4 *p, uint8_t flags)
+{
+       int rc = 0;
+       struct ext_itf *exti;
+
+       /* Find Extended Prefix interface */
+       exti = lookup_ext_by_ifp(ifp);
+       if (exti == NULL)
+               return rc;
+
+       if (p != NULL) {
+               if (IS_DEBUG_OSPF_SR)
+                       zlog_debug(
+                               "EXT (%s): Schedule new prefix %s/%u with "
+                               "index %u on interface %s",
+                               __func__, inet_ntoa(p->prefix), p->prefixlen,
+                               index, ifp->name);
+
+               /* Set first Extended Prefix then the Prefix SID information */
+               set_ext_prefix(exti, OSPF_PATH_INTRA_AREA, EXT_TLV_PREF_NFLG,
+                              *p);
+               set_prefix_sid(exti, SR_ALGORITHM_SPF, index, SID_INDEX, flags);
+
+               /* Try to Schedule LSA */
+               SET_FLAG(exti->flags, EXT_LPFLG_LSA_ACTIVE);
+               if (CHECK_FLAG(exti->flags, EXT_LPFLG_LSA_ENGAGED))
+                       ospf_ext_pref_lsa_schedule(exti, REFRESH_THIS_LSA);
+               else
+                       ospf_ext_pref_lsa_schedule(exti, REORIGINATE_THIS_LSA);
+       } else {
+               if (IS_DEBUG_OSPF_SR)
+                       zlog_debug(
+                               "EXT (%s): Remove prefix for interface %s",
+                               __func__, ifp->name);
+
+               if (CHECK_FLAG(exti->flags, EXT_LPFLG_LSA_ENGAGED)) {
+                       ospf_ext_pref_lsa_schedule(exti, FLUSH_THIS_LSA);
+                       UNSET_FLAG(exti->flags, EXT_LPFLG_LSA_ENGAGED);
+                       UNSET_FLAG(exti->flags, EXT_LPFLG_LSA_ACTIVE);
+               }
+       }
+
+       return SET_OPAQUE_LSID(exti->type, exti->instance);
+}
+
+/*
+ * Used by Segment Routing to activate/deactivate Extended Link/Prefix flooding
+ *
+ * @param enable To activate or not Segment Routing Extended LSA flooding
+ *
+ * @return none
+ */
+void ospf_ext_update_sr(bool enable)
+{
+       struct listnode *node;
+       struct ext_itf *exti;
+
+       if (IS_DEBUG_OSPF_SR)
+               zlog_debug(
+                       "EXT (%s): %s Extended LSAs for Segment Routing ",
+                       __func__, enable ? "Enable" : "Disable");
+
+       if (enable) {
+               OspfEXT.enabled = true;
+               /* Refresh LSAs if already engaged or originate */
+               for (ALL_LIST_ELEMENTS_RO(OspfEXT.iflist, node, exti))
+                       if (CHECK_FLAG(exti->flags, EXT_LPFLG_LSA_ENGAGED))
+                               ospf_ext_lsa_schedule(exti, REFRESH_THIS_LSA);
+                       else
+                               ospf_ext_lsa_schedule(exti,
+                                                     REORIGINATE_THIS_LSA);
+       } else {
+               /* Start by Flushing engaged LSAs */
+               for (ALL_LIST_ELEMENTS_RO(OspfEXT.iflist, node, exti))
+                       if (CHECK_FLAG(exti->flags, EXT_LPFLG_LSA_ENGAGED))
+                               ospf_ext_lsa_schedule(exti, FLUSH_THIS_LSA);
+               /* And then disable Extended Link/Prefix */
+               OspfEXT.enabled = false;
+       }
+}
+/*
+ * -----------------------------------------------------------------------
+ * Followings are callback functions against generic Opaque-LSAs handling
+ * -----------------------------------------------------------------------
+ */
+
+/* Add new Interface in Extended Interface List */
+static int ospf_ext_link_new_if(struct interface *ifp)
+{
+       struct ext_itf *new;
+       int rc = -1;
+
+       if (lookup_ext_by_ifp(ifp) != NULL) {
+               zlog_warn(
+                       "EXT (%s): interface %s is already in use",
+                       __func__, ifp ? ifp->name : "-");
+               rc = 0; /* Do nothing here. */
+               return rc;
+       }
+
+       new = XCALLOC(MTYPE_OSPF_EXT_PARAMS, sizeof(struct ext_itf));
+       if (new == NULL) {
+               zlog_warn("EXT (%s): XCALLOC: %s", __func__,
+                         safe_strerror(errno));
+               return rc;
+       }
+
+       /* initialize new information and link back the interface */
+       new->ifp = ifp;
+       new->flags = EXT_LPFLG_LSA_INACTIVE;
+
+       listnode_add(OspfEXT.iflist, new);
+
+       rc = 0;
+       return rc;
+}
+
+/* Remove existing Interface from Extended Interface List */
+static int ospf_ext_link_del_if(struct interface *ifp)
+{
+       struct ext_itf *exti;
+       int rc = -1;
+
+       exti = lookup_ext_by_ifp(ifp);
+       if (exti != NULL) {
+               struct list *iflist = OspfEXT.iflist;
+
+               /* Dequeue listnode entry from the list. */
+               listnode_delete(iflist, exti);
+
+               XFREE(MTYPE_OSPF_EXT_PARAMS, exti);
+
+               rc = 0;
+       } else {
+               zlog_warn(
+                       "EXT (%s): interface %s is not found",
+                       __func__, ifp ? ifp->name : "-");
+       }
+
+       return rc;
+}
+
+/*
+ * Determine if an Interface belongs to an Extended Link Adjacency or LAN Adj.
+ * type and allocate new instance value accordingly
+ */
+static void ospf_ext_link_ism_change(struct ospf_interface *oi, int old_status)
+{
+       struct ext_itf *exti;
+
+       /* Get interface information for Segment Routing */
+       exti = lookup_ext_by_ifp(oi->ifp);
+       if (exti == NULL) {
+               zlog_warn(
+                       "EXT (%s): Cannot get Extended info. from OI(%s)",
+                       __func__, IF_NAME(oi));
+               return;
+       }
+
+       /* Determine if interface is related to Adjacency or LAN Adj. SID */
+       if (oi->type != OSPF_IFTYPE_LOOPBACK) {
+               if (oi->state == ISM_DR)
+                       exti->stype = LAN_ADJ_SID;
+               else
+                       exti->stype = ADJ_SID;
+
+               exti->instance = get_ext_link_instance_value();
+               exti->type = OPAQUE_TYPE_EXTENDED_LINK_LSA;
+
+               zlog_debug(
+                       "EXT (%s): Set %s SID to interface %s ", __func__,
+                       exti->stype == ADJ_SID ? "Adj." : "LAN Adj.",
+                       oi->ifp->name);
+       }
+}
+
+/*
+ * Determine if an Interface belongs to an Extended Prefix and
+ * allocate new instance value accordingly
+ */
+static void ospf_ext_pref_ism_change(struct ospf_interface *oi, int old_status)
+{
+       struct ext_itf *exti;
+
+       /* Get interface information for Segment Routing */
+       exti = lookup_ext_by_ifp(oi->ifp);
+       if (exti == NULL) {
+               zlog_warn(
+                       "EXT (%s): Cannot get Extended info. from OI(%s)",
+                       __func__, IF_NAME(oi));
+               return;
+       }
+
+       /* Determine if interface is related to a Node SID */
+       if (oi->type == OSPF_IFTYPE_LOOPBACK) {
+               exti->stype = PREF_SID;
+               exti->instance = get_ext_pref_instance_value();
+               exti->type = OPAQUE_TYPE_EXTENDED_PREFIX_LSA;
+
+               zlog_debug(
+                       "EXT (%s): Set Node SID to interface %s ", __func__,
+                       oi->ifp->name);
+
+               /* Complete SRDB if the interface belongs to a Prefix */
+               if (OspfEXT.enabled)
+                       ospf_sr_update_prefix(oi->ifp, oi->address);
+       }
+}
+
+/*
+ * Finish Extended Link configuration and flood corresponding LSA
+ * when OSPF adjacency on this link fire up
+ */
+static void ospf_ext_link_nsm_change(struct ospf_neighbor *nbr, int old_status)
+{
+       struct ospf_interface *oi = nbr->oi;
+       struct ext_itf *exti;
+       uint32_t label;
+
+       /* Process Neighbor only when its state is NSM Full */
+       if (nbr->state != NSM_Full)
+               return;
+
+       /* Get interface information for Segment Routing */
+       exti = lookup_ext_by_ifp(oi->ifp);
+       if (exti == NULL) {
+               zlog_warn(
+                       "EXT (%s): Cannot get Extended info. from OI(%s)",
+                       __func__, IF_NAME(oi));
+               return;
+       }
+
+       if (oi->area == NULL || oi->area->ospf == NULL) {
+               zlog_warn(
+                       "EXT (%s): Cannot refer to OSPF from OI(%s)",
+                       __func__, IF_NAME(oi));
+               return;
+       }
+
+       /* Keep Area information in combination with SR info. */
+       exti->area = oi->area;
+       OspfEXT.area = oi->area;
+
+       /* Process only Adjacency/LAN SID */
+       if (exti->stype == PREF_SID)
+               return;
+
+       switch (oi->state) {
+       case ISM_PointToPoint:
+               /* Segment ID is an Adjacency one */
+               exti->stype = ADJ_SID;
+
+               /* Set Extended Link TLV with link_id == Nbr Router ID */
+               set_ext_link(exti, OSPF_IFTYPE_POINTOPOINT, nbr->router_id,
+                            oi->address->u.prefix4);
+
+               /* Set Extended Link Adjacency SubTLVs, backup first */
+               label = get_ext_link_label_value();
+               set_adj_sid(exti, true, label, SID_LABEL);
+               label = get_ext_link_label_value();
+               set_adj_sid(exti, false, label, SID_LABEL);
+               /* And Remote Interface address */
+               set_rmt_itf_addr(exti, nbr->address.u.prefix4);
+
+               break;
+
+       case ISM_DR:
+               /* Segment ID is a LAN Adjacency for the DR only */
+               exti->stype = LAN_ADJ_SID;
+
+               /* Set Extended Link TLV with link_id == DR */
+               set_ext_link(exti, OSPF_IFTYPE_BROADCAST, DR(oi),
+                            oi->address->u.prefix4);
+
+               /* Set Extended Link Adjacency SubTLVs, backup first */
+               label = get_ext_link_label_value();
+               set_lan_adj_sid(exti, true, label, SID_LABEL, nbr->router_id);
+               label = get_ext_link_label_value();
+               set_lan_adj_sid(exti, false, label, SID_LABEL, nbr->router_id);
+
+               break;
+
+       case ISM_DROther:
+       case ISM_Backup:
+               /* Segment ID is an Adjacency if not the DR */
+               exti->stype = ADJ_SID;
+
+               /* Set Extended Link TLV with link_id == DR */
+               set_ext_link(exti, OSPF_IFTYPE_BROADCAST, DR(oi),
+                            oi->address->u.prefix4);
+
+               /* Set Extended Link Adjacency SubTLVs, backup first */
+               label = get_ext_link_label_value();
+               set_adj_sid(exti, true, label, SID_LABEL);
+               label = get_ext_link_label_value();
+               set_adj_sid(exti, false, label, SID_LABEL);
+
+               break;
+
+       default:
+               if (CHECK_FLAG(exti->flags, EXT_LPFLG_LSA_ENGAGED)) {
+                       ospf_ext_link_lsa_schedule(exti, FLUSH_THIS_LSA);
+                       UNSET_FLAG(exti->flags, EXT_LPFLG_LSA_ENGAGED);
+                       UNSET_FLAG(exti->flags, EXT_LPFLG_LSA_ACTIVE);
+               }
+               return;
+       }
+
+       if (IS_DEBUG_OSPF_SR)
+               zlog_debug(
+                       "EXT (%s): Complete %s SID to interface %s ", __func__,
+                       exti->stype == ADJ_SID ? "Adj." : "LAN Adj.",
+                       oi->ifp->name);
+
+       /* flood this links params if everything is ok */
+       SET_FLAG(exti->flags, EXT_LPFLG_LSA_ACTIVE);
+       if (OspfEXT.enabled) {
+               if (CHECK_FLAG(exti->flags, EXT_LPFLG_LSA_ENGAGED))
+                       ospf_ext_link_lsa_schedule(exti, REFRESH_THIS_LSA);
+               else
+                       ospf_ext_link_lsa_schedule(exti, REORIGINATE_THIS_LSA);
+       }
+
+}
+
+/* Callbacks to handle Extended Link Segment Routing LSA information */
+static int ospf_ext_link_lsa_update(struct ospf_lsa *lsa)
+{
+       /* Sanity Check */
+       if (lsa == NULL) {
+               zlog_warn("EXT (%s): Abort! LSA is NULL", __func__);
+               return -1;
+       }
+
+       /* Process only Opaque LSA */
+       if ((lsa->data->type != OSPF_OPAQUE_AREA_LSA)
+           && (lsa->data->type != OSPF_OPAQUE_AS_LSA))
+               return 0;
+
+       /* Process only Extended Link LSA */
+       if (GET_OPAQUE_TYPE(ntohl(lsa->data->id.s_addr))
+           != OPAQUE_TYPE_EXTENDED_LINK_LSA)
+               return 0;
+
+       /* Check if Extended is enable */
+       if (!OspfEXT.enabled)
+               return 0;
+
+       /* Call Segment Routing LSA update or deletion */
+       if (!IS_LSA_MAXAGE(lsa))
+               ospf_sr_ext_link_lsa_update(lsa);
+       else
+               ospf_sr_ext_link_lsa_delete(lsa);
+
+       return 0;
+}
+
+/* Callbacks to handle Extended Prefix Segment Routing LSA information */
+static int ospf_ext_pref_lsa_update(struct ospf_lsa *lsa)
+{
+
+       /* Sanity Check */
+       if (lsa == NULL) {
+               zlog_warn("EXT (%s): Abort! LSA is NULL", __func__);
+               return -1;
+       }
+
+       /* Process only Opaque LSA */
+       if ((lsa->data->type != OSPF_OPAQUE_AREA_LSA)
+           && (lsa->data->type != OSPF_OPAQUE_AS_LSA))
+               return 0;
+
+       /* Process only Extended Prefix LSA */
+       if (GET_OPAQUE_TYPE(ntohl(lsa->data->id.s_addr))
+           != OPAQUE_TYPE_EXTENDED_PREFIX_LSA)
+               return 0;
+
+       /* Check if it is not my LSA */
+       if (IS_LSA_SELF(lsa))
+               return 0;
+
+       /* Check if Extended is enable */
+       if (!OspfEXT.enabled)
+               return 0;
+
+       /* Call Segment Routing LSA update or deletion */
+       if (!IS_LSA_MAXAGE(lsa))
+               ospf_sr_ext_prefix_lsa_update(lsa);
+       else
+               ospf_sr_ext_prefix_lsa_delete(lsa);
+
+       return 0;
+}
+
+/*
+ * -------------------------------------------------------
+ * Followings are OSPF protocol processing functions for
+ * Extended Prefix/Link Opaque LSA
+ * -------------------------------------------------------
+ */
+
+static void build_tlv_header(struct stream *s, struct tlv_header *tlvh)
+{
+       stream_put(s, tlvh, sizeof(struct tlv_header));
+
+}
+
+static void build_tlv(struct stream *s, struct tlv_header *tlvh)
+{
+
+       if ((tlvh != NULL) && (ntohs(tlvh->type) != 0)) {
+               build_tlv_header(s, tlvh);
+               stream_put(s, TLV_DATA(tlvh), TLV_BODY_SIZE(tlvh));
+       }
+
+}
+
+/* Build an Extended Prefix Opaque LSA body for extended prefix TLV */
+static void ospf_ext_pref_lsa_body_set(struct stream *s, struct ext_itf *exti)
+{
+
+       /* Sanity check */
+       if ((exti == NULL) || (exti->stype != PREF_SID))
+               return;
+
+       /* Adjust Extended Prefix TLV size */
+       TLV_LEN(exti->prefix) =
+               htons(ntohs(TLV_LEN(exti->node_sid)) + EXT_TLV_PREFIX_SIZE
+                           + TLV_HDR_SIZE);
+
+       /* Build LSA body for an Extended Prefix TLV */
+       build_tlv_header(s, &exti->prefix.header);
+       stream_put(s, TLV_DATA(&exti->prefix.header), EXT_TLV_PREFIX_SIZE);
+       /* Then add Prefix SID SubTLV */
+       build_tlv(s, &exti->node_sid.header);
+
+}
+
+/* Build an Extended Link Opaque LSA body for extended link TLV */
+static void ospf_ext_link_lsa_body_set(struct stream *s, struct ext_itf *exti)
+{
+       size_t size;
+
+       /* Sanity check */
+       if ((exti == NULL)
+           || ((exti->stype != ADJ_SID) && (exti->stype != LAN_ADJ_SID)))
+               return;
+
+       if (exti->stype == ADJ_SID) {
+               /* Adjust Extended Link TLV size for Adj. SID */
+               size = EXT_TLV_LINK_SIZE + 2 * EXT_SUBTLV_ADJ_SID_SIZE
+                       + 2 * TLV_HDR_SIZE;
+               if (ntohs(TLV_TYPE(exti->rmt_itf_addr)) != 0)
+                       size = size + EXT_SUBTLV_RMT_ITF_ADDR_SIZE
+                                   + TLV_HDR_SIZE;
+               TLV_LEN(exti->link) = htons(size);
+
+               /* Build LSA body for an Extended Link TLV with Adj. SID */
+               build_tlv_header(s, &exti->link.header);
+               stream_put(s, TLV_DATA(&exti->link.header), EXT_TLV_LINK_SIZE);
+               /* then add Ajacency SubTLVs */
+               build_tlv(s, &exti->adj_sid[1].header);
+               build_tlv(s, &exti->adj_sid[0].header);
+
+               /* Add Cisco experimental SubTLV if interface is PtoP */
+               if (ntohs(TLV_TYPE(exti->rmt_itf_addr)) != 0)
+                       build_tlv(s, &exti->rmt_itf_addr.header);
+       } else {
+               /* Adjust Extended Link TLV size for LAN SID */
+               size = EXT_TLV_LINK_SIZE
+                       + 2 * (EXT_SUBTLV_LAN_ADJ_SID_SIZE + TLV_HDR_SIZE);
+               TLV_LEN(exti->link) = htons(size);
+
+               /* Build LSA body for an Extended Link TLV with LAN SID */
+               build_tlv_header(s, &exti->link.header);
+               stream_put(s, &exti->link.header, EXT_TLV_LINK_SIZE);
+               /* then add LAN-Ajacency SubTLVs */
+               build_tlv(s, &exti->lan_sid[1].header);
+               build_tlv(s, &exti->lan_sid[0].header);
+       }
+
+}
+
+/* Create new Extended Prefix opaque-LSA for every extended prefix */
+static struct ospf_lsa *ospf_ext_pref_lsa_new(struct ospf_area *area,
+                                             struct ext_itf *exti)
+{
+       struct stream *s;
+       struct lsa_header *lsah;
+       struct ospf_lsa *new = NULL;
+       struct ospf *top;
+       u_char options, lsa_type;
+       struct in_addr lsa_id;
+       struct in_addr router_id;
+       uint32_t tmp;
+       uint16_t length;
+
+       /* Sanity Check */
+       if (exti == NULL)
+               return NULL;
+
+       /* Create a stream for LSA. */
+       s = stream_new(OSPF_MAX_LSA_SIZE);
+       if (s == NULL) {
+               zlog_warn("EXT (%s): stream_new() error", __func__);
+               return NULL;
+       }
+
+       /* Prepare LSA Header */
+       lsah = (struct lsa_header *)STREAM_DATA(s);
+
+       lsa_type = OspfEXT.scope;
+
+       /*
+        * LSA ID is a variable number identifying different instances of
+        * Extended Prefix Opaque LSA from the same router see RFC 7684
+        */
+       tmp = SET_OPAQUE_LSID(OPAQUE_TYPE_EXTENDED_PREFIX_LSA, exti->instance);
+       lsa_id.s_addr = htonl(tmp);
+
+       options = OSPF_OPTION_O; /* Don't forget this :-) */
+
+       /* Fix Options and Router ID depending of the flooding scope */
+       if ((OspfEXT.scope == OSPF_OPAQUE_AS_LSA) || (area == NULL)) {
+               options = OSPF_OPTION_E;
+               top = ospf_lookup_by_vrf_id(VRF_DEFAULT);
+               router_id.s_addr = top ? top->router_id.s_addr : 0;
+       } else {
+               options |= LSA_OPTIONS_GET(area); /* Get area default option */
+               options |= LSA_OPTIONS_NSSA_GET(area);
+               router_id = area->ospf->router_id;
+       }
+
+       /* Set opaque-LSA header fields. */
+       lsa_header_set(s, options, lsa_type, lsa_id, router_id);
+
+       if (IS_DEBUG_OSPF(lsa, LSA_GENERATE))
+               zlog_debug(
+                       "EXT (%s): LSA[Type%u:%s]: Create an Opaque-LSA "
+                       "Extended Prefix Opaque LSA instance",
+                       __func__, lsa_type, inet_ntoa(lsa_id));
+
+
+       /* Set opaque-LSA body fields. */
+       ospf_ext_pref_lsa_body_set(s, exti);
+
+       /* Set length. */
+       length = stream_get_endp(s);
+       lsah->length = htons(length);
+
+       /* Now, create an OSPF LSA instance. */
+       new = ospf_lsa_new();
+       if (new == NULL) {
+               zlog_warn("EXT (%s): ospf_lsa_new() error", __func__);
+               stream_free(s);
+               return NULL;
+       }
+       new->data = ospf_lsa_data_new(length);
+       if (new->data == NULL) {
+               zlog_warn("EXT (%s): ospf_lsa_data_new() error", __func__);
+               ospf_lsa_unlock(&new);
+               new = NULL;
+               stream_free(s);
+               return NULL;
+       }
+
+       /* Segment Routing belongs only to default VRF */
+       new->vrf_id = VRF_DEFAULT;
+       new->area = area;
+       SET_FLAG(new->flags, OSPF_LSA_SELF);
+       memcpy(new->data, lsah, length);
+       stream_free(s);
+
+       return new;
+}
+
+/* Create new Extended Link opaque-LSA for every extended link TLV */
+static struct ospf_lsa *ospf_ext_link_lsa_new(struct ospf_area *area,
+                                             struct ext_itf *exti)
+{
+       struct stream *s;
+       struct lsa_header *lsah;
+       struct ospf_lsa *new = NULL;
+       u_char options, lsa_type;
+       struct in_addr lsa_id;
+       uint32_t tmp;
+       uint16_t length;
+
+       /* Sanity Check */
+       if (exti == NULL)
+               return NULL;
+
+       /* Create a stream for LSA. */
+       s = stream_new(OSPF_MAX_LSA_SIZE);
+       if (s == NULL) {
+               zlog_warn("EXT (%s): stream_new() error", __func__);
+               return NULL;
+       }
+       lsah = (struct lsa_header *)STREAM_DATA(s);
+
+       options = OSPF_OPTION_O;          /* Don't forget this :-) */
+       options |= LSA_OPTIONS_GET(area); /* Get area default option */
+       options |= LSA_OPTIONS_NSSA_GET(area);
+       /* Extended Link Opaque LSA are only flooded within an area */
+       lsa_type = OSPF_OPAQUE_AREA_LSA;
+
+       /*
+        * LSA ID is a variable number identifying different instances of
+        * Extended Link Opaque LSA from the same router see RFC 7684
+        */
+       tmp = SET_OPAQUE_LSID(OPAQUE_TYPE_EXTENDED_LINK_LSA, exti->instance);
+       lsa_id.s_addr = htonl(tmp);
+
+       if (IS_DEBUG_OSPF(lsa, LSA_GENERATE))
+               zlog_debug(
+                       "EXT (%s) LSA[Type%u:%s]: Create an Opaque-LSA "
+                       "Extended Link Opaque LSA instance",
+                       __func__, lsa_type, inet_ntoa(lsa_id));
+
+       /* Set opaque-LSA header fields. */
+       lsa_header_set(s, options, lsa_type, lsa_id, area->ospf->router_id);
+
+       /* Set opaque-LSA body fields. */
+       ospf_ext_link_lsa_body_set(s, exti);
+
+       /* Set length. */
+       length = stream_get_endp(s);
+       lsah->length = htons(length);
+
+       /* Now, create an OSPF LSA instance. */
+       new = ospf_lsa_new();
+       if (new == NULL) {
+               zlog_warn("EXT (%s): ospf_lsa_new() error", __func__);
+               stream_free(s);
+               return NULL;
+       }
+       new->data = ospf_lsa_data_new(length);
+       if (new->data == NULL) {
+               zlog_warn("EXT (%s): ospf_lsa_data_new() error", __func__);
+               ospf_lsa_unlock(&new);
+               new = NULL;
+               stream_free(s);
+               return NULL;
+       }
+
+       /* Segment Routing belongs only to default VRF */
+       new->vrf_id = VRF_DEFAULT;
+       new->area = area;
+       SET_FLAG(new->flags, OSPF_LSA_SELF);
+       memcpy(new->data, lsah, length);
+       stream_free(s);
+
+       return new;
+}
+
+/*
+ * Process the origination of an Extended Prefix Opaque LSA
+ * for every extended prefix TLV
+ */
+static int ospf_ext_pref_lsa_originate1(struct ospf_area *area,
+                                       struct ext_itf *exti)
+{
+       struct ospf_lsa *new;
+       int rc = -1;
+
+
+       /* Create new Opaque-LSA/Extended Prefix Opaque LSA instance. */
+       new = ospf_ext_pref_lsa_new(area, exti);
+       if (new == NULL) {
+               zlog_warn("EXT (%s): ospf_ext_pref_lsa_new() error", __func__);
+               return rc;
+       }
+
+       /* Install this LSA into LSDB. */
+       if (ospf_lsa_install(area->ospf, NULL /*oi */, new) == NULL) {
+               zlog_warn("EXT (%s): ospf_lsa_install() error", __func__);
+               ospf_lsa_unlock(&new);
+               return rc;
+       }
+
+       /* Now this Extended Prefix Opaque LSA info parameter entry has
+        * associated LSA.
+        */
+       SET_FLAG(exti->flags, EXT_LPFLG_LSA_ENGAGED);
+
+       /* Update new LSA origination count. */
+       area->ospf->lsa_originate_count++;
+
+       /* Flood new LSA through area. */
+       ospf_flood_through_area(area, NULL /*nbr */, new);
+
+       if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) {
+               char area_id[INET_ADDRSTRLEN];
+
+               strncpy(area_id, inet_ntoa(area->area_id), INET_ADDRSTRLEN);
+               zlog_debug(
+                       "EXT (%s): LSA[Type%u:%s]: Originate Opaque-LSA "
+                       "Extended Prefix Opaque LSA: Area(%s), Link(%s)",
+                       __func__, new->data->type, inet_ntoa(new->data->id),
+                       area_id, exti->ifp->name);
+               ospf_lsa_header_dump(new->data);
+       }
+
+       rc = 0;
+
+       return rc;
+}
+
+/*
+ * Process the origination of an Extended Link Opaque LSA
+ * for every extended link TLV
+ */
+static int ospf_ext_link_lsa_originate1(struct ospf_area *area,
+                                       struct ext_itf *exti)
+{
+       struct ospf_lsa *new;
+       int rc = -1;
+
+       /* Create new Opaque-LSA/Extended Link Opaque LSA instance. */
+       new = ospf_ext_link_lsa_new(area, exti);
+       if (new == NULL) {
+               zlog_warn("EXT (%s): ospf_ext_link_lsa_new() error", __func__);
+               return rc;
+       }
+
+       /* Install this LSA into LSDB. */
+       if (ospf_lsa_install(area->ospf, NULL /*oi */, new) == NULL) {
+               zlog_warn("EXT (%s): ospf_lsa_install() error", __func__);
+               ospf_lsa_unlock(&new);
+               return rc;
+       }
+
+       /* Now this link-parameter entry has associated LSA. */
+       SET_FLAG(exti->flags, EXT_LPFLG_LSA_ENGAGED);
+
+       /* Update new LSA origination count. */
+       area->ospf->lsa_originate_count++;
+
+       /* Flood new LSA through area. */
+       ospf_flood_through_area(area, NULL /*nbr */, new);
+
+       if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) {
+               char area_id[INET_ADDRSTRLEN];
+
+               strncpy(area_id, inet_ntoa(area->area_id), INET_ADDRSTRLEN);
+               zlog_debug(
+                       "EXT (%s): LSA[Type%u:%s]: Originate Opaque-LSA "
+                       "Extended Link Opaque LSA: Area(%s), Link(%s)",
+                        __func__, new->data->type, inet_ntoa(new->data->id),
+                        area_id, exti->ifp->name);
+               ospf_lsa_header_dump(new->data);
+       }
+
+       rc = 0;
+
+       return rc;
+}
+
+/* Trigger the origination of Extended Prefix Opaque LSAs */
+static int ospf_ext_pref_lsa_originate(void *arg)
+{
+       struct ospf_area *area = (struct ospf_area *)arg;
+       struct listnode *node;
+       struct ext_itf *exti;
+       int rc = -1;
+
+       if (!OspfEXT.enabled) {
+               zlog_info(
+                       "EXT (%s): Segment Routing "
+                       "functionality is Disabled now", __func__);
+               rc = 0; /* This is not an error case. */
+               return rc;
+       }
+       if (IS_DEBUG_OSPF_SR)
+               zlog_debug(
+                       "EXT (%s): Start Originate Prefix LSA for area %s",
+                       __func__, inet_ntoa(area->area_id));
+
+       /* Check if Extended Prefix Opaque LSA is already engaged */
+       for (ALL_LIST_ELEMENTS_RO(OspfEXT.iflist, node, exti)) {
+
+               /* Process only Prefix SID */
+               if (exti->stype != PREF_SID)
+                       continue;
+
+               /* Process only Extended Prefix with valid Area ID */
+               if ((exti->area == NULL)
+                   || (!IPV4_ADDR_SAME(&exti->area->area_id, &area->area_id)))
+                       continue;
+
+               if (CHECK_FLAG(exti->flags, EXT_LPFLG_LSA_ENGAGED)) {
+                       if (CHECK_FLAG(exti->flags,
+                                      EXT_LPFLG_LSA_FORCED_REFRESH)) {
+                               zlog_warn(
+                                       "EXT (%s): Refresh instead of "
+                                       "Originate", __func__);
+                               UNSET_FLAG(exti->flags,
+                                          EXT_LPFLG_LSA_FORCED_REFRESH);
+                               ospf_ext_pref_lsa_schedule(exti,
+                                                          REFRESH_THIS_LSA);
+                       }
+                       continue;
+               }
+
+               /* Ok, let's try to originate an LSA */
+               if (IS_DEBUG_OSPF_SR)
+                       zlog_debug(
+                               "EXT (%s): Let's finally reoriginate the "
+                               "LSA 7.0.0.%u for Itf %s",
+                               __func__, exti->instance,
+                               exti->ifp ? exti->ifp->name : "");
+               ospf_ext_pref_lsa_originate1(area, exti);
+       }
+
+       rc = 0;
+       return rc;
+}
+
+/* Trigger the origination of Extended Link Opaque LSAs */
+static int ospf_ext_link_lsa_originate(void *arg)
+{
+       struct ospf_area *area = (struct ospf_area *)arg;
+       struct listnode *node;
+       struct ext_itf *exti;
+       int rc = -1;
+
+       if (!OspfEXT.enabled) {
+               zlog_info(
+                       "EXT (%s): Segment Routing "
+                       "functionality is Disabled now", __func__);
+               rc = 0; /* This is not an error case. */
+               return rc;
+       }
+
+       /* Check if Extended Prefix Opaque LSA is already engaged */
+       for (ALL_LIST_ELEMENTS_RO(OspfEXT.iflist, node, exti)) {
+               /* Process only Adjacency or LAN SID */
+               if (exti->stype == PREF_SID)
+                       continue;
+
+               /* Process only Extended Link with valid Area ID */
+               if ((exti->area == NULL)
+                   || (!IPV4_ADDR_SAME(&exti->area->area_id, &area->area_id)))
+                       continue;
+
+               /* Check if LSA not already engaged */
+               if (CHECK_FLAG(exti->flags, EXT_LPFLG_LSA_ENGAGED)) {
+                       if (CHECK_FLAG(exti->flags,
+                                      EXT_LPFLG_LSA_FORCED_REFRESH)) {
+                               zlog_warn(
+                                       "EXT (%s): Refresh instead of "
+                                       "Originate", __func__);
+                               UNSET_FLAG(exti->flags,
+                                          EXT_LPFLG_LSA_FORCED_REFRESH);
+                               ospf_ext_link_lsa_schedule(exti,
+                                                          REFRESH_THIS_LSA);
+                       }
+                       continue;
+               }
+
+               /* Ok, let's try to originate an LSA */
+               if (IS_DEBUG_OSPF_SR)
+                       zlog_debug(
+                               "EXT (%s): Let's finally reoriginate the "
+                               "LSA 8.0.0.%u for Itf %s through the Area %s",
+                               __func__, exti->instance,
+                               exti->ifp ? exti->ifp->name : "-",
+                               inet_ntoa(area->area_id));
+               ospf_ext_link_lsa_originate1(area, exti);
+       }
+
+       rc = 0;
+       return rc;
+}
+
+/* Refresh an Extended Prefix Opaque LSA */
+static struct ospf_lsa *ospf_ext_pref_lsa_refresh(struct ospf_lsa *lsa)
+{
+       struct ospf_lsa *new = NULL;
+       struct ospf_area *area = lsa->area;
+       struct ospf *top;
+       struct ext_itf *exti;
+
+       if (!OspfEXT.enabled) {
+               /*
+                * This LSA must have flushed before due to Extended Prefix
+                * Opaque LSA status change.
+                * It seems a slip among routers in the routing domain.
+                */
+               zlog_info(
+                       "EXT (%s): Segment Routing functionality is "
+                       "Disabled", __func__);
+               /* Flush it anyway. */
+               lsa->data->ls_age = htons(OSPF_LSA_MAXAGE);
+       }
+
+       /* Lookup this lsa corresponding Extended parameters */
+       exti = lookup_ext_by_instance(lsa);
+       if (exti == NULL) {
+               zlog_warn("EXT (%s): Invalid parameter LSA ID", __func__);
+               /* Flush it anyway. */
+               lsa->data->ls_age = htons(OSPF_LSA_MAXAGE);
+       }
+
+       /* Check if Interface was not disable in the interval */
+       if ((exti != NULL) && !CHECK_FLAG(exti->flags, EXT_LPFLG_LSA_ACTIVE)) {
+               zlog_warn("EXT (%s): Interface was Disabled: Flush it!",
+                       __func__);
+               /* Flush it anyway. */
+               lsa->data->ls_age = htons(OSPF_LSA_MAXAGE);
+       }
+
+       /* If the lsa's age reached to MaxAge, start flushing procedure. */
+       if (IS_LSA_MAXAGE(lsa)) {
+               if (exti)
+                       UNSET_FLAG(exti->flags, EXT_LPFLG_LSA_ENGAGED);
+               ospf_opaque_lsa_flush_schedule(lsa);
+               return NULL;
+       }
+
+       /* Create new Opaque-LSA/Extended Prefix Opaque LSA instance. */
+       new = ospf_ext_pref_lsa_new(area, exti);
+
+       if (new == NULL) {
+               zlog_warn("EXT (%s): ospf_ext_pref_lsa_new() error", __func__);
+               return NULL;
+       }
+       new->data->ls_seqnum = lsa_seqnum_increment(lsa);
+
+       /*
+        * Install this LSA into LSDB
+        * Given "lsa" will be freed in the next function
+        * As area could be NULL i.e. when using OPAQUE_LSA_AS, we prefer to use
+        * ospf_lookup() to get ospf instance
+        */
+       if (area)
+               top = area->ospf;
+       else
+               top = ospf_lookup_by_vrf_id(VRF_DEFAULT);
+
+       if (ospf_lsa_install(top, NULL /*oi */, new) == NULL) {
+               zlog_warn("EXT (%s): ospf_lsa_install() error", __func__);
+               ospf_lsa_unlock(&new);
+               return NULL;
+       }
+
+       /* Flood updated LSA through the Prefix Area according to the RFC7684 */
+       ospf_flood_through_area(area, NULL /*nbr */, new);
+
+       /* Debug logging. */
+       if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) {
+               zlog_debug(
+                       "EXT (%s): LSA[Type%u:%s] Refresh Extended Prefix LSA",
+                       __func__, new->data->type, inet_ntoa(new->data->id));
+               ospf_lsa_header_dump(new->data);
+       }
+
+       return new;
+}
+
+/* Refresh an Extended Link Opaque LSA */
+static struct ospf_lsa *ospf_ext_link_lsa_refresh(struct ospf_lsa *lsa)
+{
+       struct ext_itf *exti;
+       struct ospf_area *area = lsa->area;
+       struct ospf *top = area->ospf;
+       struct ospf_lsa *new = NULL;
+
+       if (!OspfEXT.enabled) {
+               /*
+                * This LSA must have flushed before due to OSPF-SR status
+                * change. It seems a slip among routers in the routing domain.
+                */
+               zlog_info(
+                       "EXT (%s): Segment Routing functionality is Disabled",
+                       __func__);
+               /* Flush it anyway. */
+               lsa->data->ls_age = htons(OSPF_LSA_MAXAGE);
+       }
+
+       /* Lookup this LSA corresponding Extended parameters */
+       exti = lookup_ext_by_instance(lsa);
+       if (exti == NULL) {
+               zlog_warn("EXT (%s): Invalid parameter LSA ID", __func__);
+               /* Flush it anyway. */
+               lsa->data->ls_age = htons(OSPF_LSA_MAXAGE);
+       }
+
+       /* Check if Interface was not disable in the interval */
+       if ((exti != NULL) && !CHECK_FLAG(exti->flags, EXT_LPFLG_LSA_ACTIVE)) {
+               zlog_warn(
+                       "EXT (%s): Interface was Disabled: Flush it!",
+                       __func__);
+               lsa->data->ls_age = htons(OSPF_LSA_MAXAGE);
+       }
+
+       /* If the lsa's age reached to MaxAge, start flushing procedure */
+       if (IS_LSA_MAXAGE(lsa)) {
+               if (exti)
+                       UNSET_FLAG(exti->flags, EXT_LPFLG_LSA_ENGAGED);
+               ospf_opaque_lsa_flush_schedule(lsa);
+               return NULL;
+       }
+
+       /* Create new Opaque-LSA/Extended Link instance */
+       new = ospf_ext_link_lsa_new(area, exti);
+       if (new == NULL) {
+               zlog_warn("EXT (%s): Error creating new LSA", __func__);
+               return NULL;
+       }
+       new->data->ls_seqnum = lsa_seqnum_increment(lsa);
+
+       /* Install this LSA into LSDB. */
+       /* Given "lsa" will be freed in the next function */
+       if (ospf_lsa_install(top, NULL /*oi */, new) == NULL) {
+               zlog_warn("EXT (%s): Error installing new LSA", __func__);
+               ospf_lsa_unlock(&new);
+               return NULL;
+       }
+
+       /* Flood updated LSA through the link Area according to the RFC7684 */
+       ospf_flood_through_area(area, NULL /*nbr */, new);
+
+       /* Debug logging. */
+       if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) {
+               zlog_debug(
+                       "EXT (%s): LSA[Type%u:%s]: Refresh Extended Link LSA",
+                       __func__, new->data->type, inet_ntoa(new->data->id));
+               ospf_lsa_header_dump(new->data);
+       }
+
+       return new;
+}
+
+/* Schedule Extended Prefix Opaque LSA origination/refreshment/flushing */
+static void ospf_ext_pref_lsa_schedule(struct ext_itf *exti,
+                                      enum lsa_opcode opcode)
+{
+       struct ospf_lsa lsa;
+       struct lsa_header lsah;
+       struct ospf *top;
+       uint32_t tmp;
+
+       memset(&lsa, 0, sizeof(lsa));
+       memset(&lsah, 0, sizeof(lsah));
+
+       /* Sanity Check */
+       if (exti == NULL)
+               return;
+
+       /* Check if the corresponding link is ready to be flooded */
+       if (!(CHECK_FLAG(exti->flags, EXT_LPFLG_LSA_ACTIVE)))
+               return;
+
+       zlog_debug(
+               "EXT (%s): Schedule %s%s%s LSA for interface %s", __func__,
+               opcode == REORIGINATE_THIS_LSA ? "Re-Originate" : "",
+               opcode == REFRESH_THIS_LSA ? "Refresh" : "",
+               opcode == FLUSH_THIS_LSA ? "Flush" : "",
+               exti->ifp ? exti->ifp->name : "-");
+
+       /* Set LSA header information */
+       if (exti->area == NULL) {
+               zlog_warn(
+                       "EXT (%s): Flooding is Area scope but area is not yet "
+                       "set", __func__);
+               if (OspfEXT.area == NULL) {
+                       top = ospf_lookup_by_vrf_id(VRF_DEFAULT);
+                       OspfEXT.area = ospf_area_lookup_by_area_id(
+                               top, OspfEXT.area_id);
+               }
+               exti->area = OspfEXT.area;
+       }
+       lsa.area = exti->area;
+       lsa.data = &lsah;
+       lsah.type = OSPF_OPAQUE_AREA_LSA;
+       tmp = SET_OPAQUE_LSID(OPAQUE_TYPE_EXTENDED_PREFIX_LSA, exti->instance);
+       lsah.id.s_addr = htonl(tmp);
+
+       switch (opcode) {
+       case REORIGINATE_THIS_LSA:
+               ospf_opaque_lsa_reoriginate_schedule(
+                       (void *)exti->area, OSPF_OPAQUE_AREA_LSA,
+                       OPAQUE_TYPE_EXTENDED_PREFIX_LSA);
+               break;
+       case REFRESH_THIS_LSA:
+               ospf_opaque_lsa_refresh_schedule(&lsa);
+               break;
+       case FLUSH_THIS_LSA:
+               UNSET_FLAG(exti->flags, EXT_LPFLG_LSA_ENGAGED);
+               ospf_opaque_lsa_flush_schedule(&lsa);
+               break;
+       default:
+               zlog_warn("EXT (%s): Unknown opcode", __func__);
+               break;
+       }
+
+}
+
+/* Schedule Extended Link Opaque LSA origination/refreshment/flushing */
+static void ospf_ext_link_lsa_schedule(struct ext_itf *exti,
+                                      enum lsa_opcode opcode)
+{
+       struct ospf_lsa lsa;
+       struct lsa_header lsah;
+       struct ospf *top;
+       uint32_t tmp;
+
+       memset(&lsa, 0, sizeof(lsa));
+       memset(&lsah, 0, sizeof(lsah));
+
+       /* Sanity Check */
+       if (exti == NULL)
+               return;
+
+       /* Check if the corresponding link is ready to be flooded */
+       if (!(CHECK_FLAG(exti->flags, EXT_LPFLG_LSA_ACTIVE)))
+               return;
+
+       zlog_debug(
+               "EXT (%s): Schedule %s%s%s LSA for interface %s", __func__,
+               opcode == REORIGINATE_THIS_LSA ? "Re-Originate" : "",
+               opcode == REFRESH_THIS_LSA ? "Refresh" : "",
+               opcode == FLUSH_THIS_LSA ? "Flush" : "",
+               exti->ifp ? exti->ifp->name : "-");
+
+       /* Set LSA header information */
+       if (exti->area == NULL) {
+               zlog_warn(
+                       "EXT (%s): Flooding is Area scope but area is not "
+                       "yet set", __func__);
+               if (OspfEXT.area == NULL) {
+                       top = ospf_lookup_by_vrf_id(VRF_DEFAULT);
+                       OspfEXT.area = ospf_area_lookup_by_area_id(
+                               top, OspfEXT.area_id);
+               }
+               exti->area = OspfEXT.area;
+       }
+       lsa.area = exti->area;
+       lsa.data = &lsah;
+       lsah.type = OSPF_OPAQUE_AREA_LSA;
+       tmp = SET_OPAQUE_LSID(OPAQUE_TYPE_EXTENDED_LINK_LSA, exti->instance);
+       lsah.id.s_addr = htonl(tmp);
+
+       switch (opcode) {
+       case REORIGINATE_THIS_LSA:
+               ospf_opaque_lsa_reoriginate_schedule(
+                       (void *)exti->area, OSPF_OPAQUE_AREA_LSA,
+                       OPAQUE_TYPE_EXTENDED_LINK_LSA);
+               break;
+       case REFRESH_THIS_LSA:
+               ospf_opaque_lsa_refresh_schedule(&lsa);
+               break;
+       case FLUSH_THIS_LSA:
+               UNSET_FLAG(exti->flags, EXT_LPFLG_LSA_ENGAGED);
+               ospf_opaque_lsa_flush_schedule(&lsa);
+               break;
+       default:
+               zlog_warn("EXT (%s): Unknown opcode", __func__);
+               break;
+       }
+
+}
+
+/* Schedule Extended Link or Prefix depending of the Type of LSA */
+static void ospf_ext_lsa_schedule(struct ext_itf *exti, enum lsa_opcode op)
+{
+
+       if (exti->stype == PREF_SID)
+               ospf_ext_pref_lsa_schedule(exti, op);
+       else
+               ospf_ext_link_lsa_schedule(exti, op);
+}
+
+/*
+ * ------------------------------------
+ * Followings are vty show functions.
+ * ------------------------------------
+ */
+
+/* Cisco experimental SubTLV */
+static uint16_t show_vty_ext_link_rmt_itf_addr(struct vty *vty,
+                                               struct tlv_header *tlvh)
+{
+       struct ext_subtlv_rmt_itf_addr *top;
+
+       top = (struct ext_subtlv_rmt_itf_addr *)tlvh;
+
+       vty_out(vty,
+               "  Remote Interface Address Sub-TLV: Length %u\n        "
+               "Address: %s\n",
+               ntohs(top->header.length), inet_ntoa(top->value));
+
+       return TLV_SIZE(tlvh);
+}
+
+/* Adjacency SID SubTLV */
+static uint16_t show_vty_ext_link_adj_sid(struct vty *vty,
+                                          struct tlv_header *tlvh)
+{
+       struct ext_subtlv_adj_sid *top = (struct ext_subtlv_adj_sid *)tlvh;
+
+       vty_out(vty,
+               "  Adj-SID Sub-TLV: Length %u\n\tFlags: "
+               "0x%x\n\tMT-ID:0x%x\n\tWeight: 0x%x\n\t%s: %u\n",
+               ntohs(top->header.length), top->flags, top->mtid, top->weight,
+               CHECK_FLAG(top->flags, EXT_SUBTLV_LINK_ADJ_SID_VFLG) ? "Label"
+                                                                    : "Index",
+               CHECK_FLAG(top->flags, EXT_SUBTLV_LINK_ADJ_SID_VFLG)
+                       ? GET_LABEL(ntohl(top->value))
+                       : ntohl(top->value));
+
+       return TLV_SIZE(tlvh);
+}
+
+/* LAN Adjacency SubTLV */
+static uint16_t show_vty_ext_link_lan_adj_sid(struct vty *vty,
+                                              struct tlv_header *tlvh)
+{
+       struct ext_subtlv_lan_adj_sid *top =
+               (struct ext_subtlv_lan_adj_sid *)tlvh;
+
+       vty_out(vty,
+               "  LAN-Adj-SID Sub-TLV: Length %u\n\tFlags: "
+               "0x%x\n\tMT-ID:0x%x\n\tWeight: 0x%x\n\tNeighbor ID: "
+               "%s\n\tLabel: %u\n",
+               ntohs(top->header.length), top->flags, top->mtid, top->weight,
+               CHECK_FLAG(top->flags, EXT_SUBTLV_LINK_ADJ_SID_VFLG) ? "Label"
+                                                                    : "Index",
+               CHECK_FLAG(top->flags, EXT_SUBTLV_LINK_ADJ_SID_VFLG)
+                       ? GET_LABEL(ntohl(top->value))
+                       : ntohl(top->value));
+
+       return TLV_SIZE(tlvh);
+}
+
+static uint16_t show_vty_unknown_tlv(struct vty *vty, struct tlv_header *tlvh)
+{
+       vty_out(vty, "    Unknown TLV: [type(0x%x), length(0x%x)]\n",
+               ntohs(tlvh->type), ntohs(tlvh->length));
+
+       return TLV_SIZE(tlvh);
+}
+
+/* Extended Link Sub TLVs */
+static uint16_t show_vty_link_info(struct vty *vty, struct tlv_header *ext)
+{
+       struct ext_tlv_link *top = (struct ext_tlv_link *)ext;
+       struct tlv_header *tlvh;
+       uint16_t length = ntohs(top->header.length) - 3 * sizeof(uint32_t);
+       uint16_t sum = 0;
+
+       vty_out(vty,
+               "  Extended Link TLV: Length %u\n       Link Type: 0x%x\n"
+               "       Link ID: %s\n",
+               ntohs(top->header.length), top->link_type,
+               inet_ntoa(top->link_id));
+       vty_out(vty, "  Link data: %s\n", inet_ntoa(top->link_data));
+
+       tlvh = (struct tlv_header *)((char *)(ext) + TLV_HDR_SIZE
+                                    + EXT_TLV_LINK_SIZE);
+       for (; sum < length; tlvh = TLV_HDR_NEXT(tlvh)) {
+               switch (ntohs(tlvh->type)) {
+               case EXT_SUBTLV_ADJ_SID:
+                       sum += show_vty_ext_link_adj_sid(vty, tlvh);
+                       break;
+               case EXT_SUBTLV_LAN_ADJ_SID:
+                       sum += show_vty_ext_link_lan_adj_sid(vty, tlvh);
+                       break;
+               case EXT_SUBTLV_RMT_ITF_ADDR:
+                       sum += show_vty_ext_link_rmt_itf_addr(vty, tlvh);
+                       break;
+               default:
+                       sum += show_vty_unknown_tlv(vty, tlvh);
+                       break;
+               }
+       }
+
+       return sum + sizeof(struct ext_tlv_link);
+}
+
+/* Extended Link TLVs */
+static void ospf_ext_link_show_info(struct vty *vty, struct ospf_lsa *lsa)
+{
+       struct lsa_header *lsah = (struct lsa_header *)lsa->data;
+       struct tlv_header *tlvh;
+       uint16_t length = 0, sum = 0;
+
+       /* Initialize TLV browsing */
+       length = ntohs(lsah->length) - OSPF_LSA_HEADER_SIZE;
+
+       for (tlvh = TLV_HDR_TOP(lsah); sum < length;
+            tlvh = TLV_HDR_NEXT(tlvh)) {
+               switch (ntohs(tlvh->type)) {
+               case EXT_TLV_LINK:
+                       sum += show_vty_link_info(vty, tlvh);
+                       break;
+               default:
+                       sum += show_vty_unknown_tlv(vty, tlvh);
+                       break;
+               }
+       }
+
+}
+
+/* Prefix SID SubTLV */
+static uint16_t show_vty_ext_pref_pref_sid(struct vty *vty,
+                                           struct tlv_header *tlvh)
+{
+       struct ext_subtlv_prefix_sid *top =
+               (struct ext_subtlv_prefix_sid *)tlvh;
+
+       vty_out(vty,
+               "  Prefix SID Sub-TLV: Length %u\n\tAlgorithm: "
+               "%u\n\tFlags: 0x%x\n\tMT-ID:0x%x\n\t%s: %u\n",
+               ntohs(top->header.length), top->algorithm, top->flags,
+               top->mtid,
+               CHECK_FLAG(top->flags, EXT_SUBTLV_PREFIX_SID_VFLG) ? "Label"
+                                                                  : "Index",
+               CHECK_FLAG(top->flags, EXT_SUBTLV_PREFIX_SID_VFLG)
+                       ? GET_LABEL(ntohl(top->value))
+                       : ntohl(top->value));
+
+       return TLV_SIZE(tlvh);
+}
+
+/* Extended Prefix SubTLVs */
+static uint16_t show_vty_pref_info(struct vty *vty, struct tlv_header *ext)
+{
+       struct ext_tlv_prefix *top = (struct ext_tlv_prefix *)ext;
+       struct tlv_header *tlvh;
+       uint16_t length = ntohs(top->header.length) - 2 * sizeof(uint32_t);
+       uint16_t sum = 0;
+
+       vty_out(vty,
+               "  Extended Prefix TLV: Length %u\n\tRoute Type: %u\n"
+               "\tAddress Family: 0x%x\n\tFlags: 0x%x\n\tAddress: %s/%u\n",
+               ntohs(top->header.length), top->route_type, top->af, top->flags,
+               inet_ntoa(top->address), top->pref_length);
+
+       tlvh = (struct tlv_header *)((char *)(ext) + TLV_HDR_SIZE
+                                    + EXT_TLV_PREFIX_SIZE);
+       for (; sum < length; tlvh = TLV_HDR_NEXT(tlvh)) {
+               switch (ntohs(tlvh->type)) {
+               case EXT_SUBTLV_PREFIX_SID:
+                       sum += show_vty_ext_pref_pref_sid(vty, tlvh);
+                       break;
+               default:
+                       sum += show_vty_unknown_tlv(vty, tlvh);
+                       break;
+               }
+       }
+
+       return sum + sizeof(struct ext_tlv_prefix);
+}
+
+/* Extended Prefix TLVs */
+static void ospf_ext_pref_show_info(struct vty *vty, struct ospf_lsa *lsa)
+{
+       struct lsa_header *lsah = (struct lsa_header *)lsa->data;
+       struct tlv_header *tlvh;
+       uint16_t length = 0, sum = 0;
+
+       /* Initialize TLV browsing */
+       length = ntohs(lsah->length) - OSPF_LSA_HEADER_SIZE;
+
+       for (tlvh = TLV_HDR_TOP(lsah); sum < length;
+            tlvh = TLV_HDR_NEXT(tlvh)) {
+               switch (ntohs(tlvh->type)) {
+               case EXT_TLV_PREFIX:
+                       sum += show_vty_pref_info(vty, tlvh);
+                       break;
+               default:
+                       sum += show_vty_unknown_tlv(vty, tlvh);
+                       break;
+               }
+       }
+
+}
diff --git a/ospfd/ospf_ext.h b/ospfd/ospf_ext.h
new file mode 100644 (file)
index 0000000..6728075
--- /dev/null
@@ -0,0 +1,200 @@
+/*
+ * This is an implementation of RFC7684 OSPFv2 Prefix/Link Attribute
+ * Advertisement
+ *
+ * Module name: Extended Prefix/Link Opaque LSA header definition
+ *
+ * Author: Olivier Dugeon <olivier.dugeon@orange.com>
+ * Author: Anselme Sawadogo <anselmesawadogo@gmail.com>
+ *
+ * Copyright (C) 2016 - 2018 Orange Labs http://www.orange.com
+ *
+ * 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_OSPF_EXT_PREF_H_
+#define _FRR_OSPF_EXT_PREF_H_
+
+/*
+ * Opaque LSA's link state ID for Extended Prefix/Link is
+ * structured as follows.
+ *
+ *        24       16        8        0
+ * +--------+--------+--------+--------+
+ * |  7/8   |........|........|........|
+ * +--------+--------+--------+--------+
+ * |<-Type->|<------- Instance ------->|
+ *
+ *
+ * Type:      IANA has assigned '7' for Extended Prefix Opaque LSA
+ *            and '8' for Extended Link Opaque LSA
+ * Instance:  User may select arbitrary 24-bit values to identify
+ *            different instances of Extended Prefix/Link Opaque LSA
+ *
+ */
+
+/*
+ *        24       16        8        0
+ * +--------+--------+--------+--------+ ---
+ * |   LS age        |Options |  10,11 |  A
+ * +--------+--------+--------+--------+  |  Standard (Opaque) LSA header;
+ * |   7/8  |        Instance          |  |
+ * +--------+--------+--------+--------+  |  Type 10 or 11 are used for Extended
+ * |        Advertising router         |  |  Prefix Opaque LSA
+ * +--------+--------+--------+--------+  |
+ * |        LS sequence number         |  |  Type 10 only is used for Extended
+ * +--------+--------+--------+--------+  |  Link Opaque LSA
+ * |   LS checksum   |     Length      |  V
+ * +--------+--------+--------+--------+ ---
+ * |      Type       |     Length      |  A
+ * +--------+--------+--------+--------+  |  TLV part for Extended Prefix/Link
+ * |                                   |  |  Opaque LSA;
+ * ~              Values ...           ~  |  Values might be structured as a set
+ * |                                   |  V  of sub-TLVs.
+ * +--------+--------+--------+--------+ ---
+ */
+
+/* Global use constant numbers */
+
+#define MAX_LEGAL_EXT_INSTANCE_NUM     (0xffff)
+#define LEGAL_EXT_INSTANCE_RANGE(i)    (0 <= (i) && (i) <= 0xffff)
+
+/* Flags to manage Extended Link/Prefix Opaque LSA */
+#define EXT_LPFLG_LSA_INACTIVE          0x00
+#define EXT_LPFLG_LSA_ACTIVE            0x01
+#define EXT_LPFLG_LSA_ENGAGED           0x02
+#define EXT_LPFLG_LSA_LOOKUP_DONE       0x04
+#define EXT_LPFLG_LSA_FORCED_REFRESH    0x08
+#define EXT_LPFLG_FIB_ENTRY_SET         0x10
+
+/*
+ * Following section defines TLV (tag, length, value) structures,
+ * used in Extended Prefix/Link Opaque LSA.
+ */
+
+/* Extended Prefix TLV Route Types */
+#define EXT_TLV_PREF_ROUTE_UNSPEC      0
+#define EXT_TLV_PREF_ROUTE_INTRA_AREA  1
+#define EXT_TLV_PREF_ROUTE_INTER_AREA  3
+#define EXT_TLV_PREF_ROUTE_AS_EXT      5
+#define EXT_TLV_PREF_ROUTE_NSSA_EXT    7
+
+/*
+ * Extended Prefix and Extended Prefix Range TLVs'
+ * Address family flag for IPv4
+ */
+#define EXT_TLV_PREF_AF_IPV4           0
+
+/* Extended Prefix TLV Flags */
+#define EXT_TLV_PREF_AFLG              0x80
+#define EXT_TLV_PREF_NFLG              0x40
+
+/* Extended Prefix Range TLV Flags */
+#define EXT_TLV_PREF_RANGE_IAFLG       0x80
+
+/* ERO subtlvs Flags */
+#define EXT_SUBTLV_ERO_LFLG            0x80
+
+/* Extended Prefix TLV see RFC 7684 section 2.1 */
+#define EXT_TLV_PREFIX                 1
+#define EXT_TLV_PREFIX_SIZE            8
+struct ext_tlv_prefix {
+       struct tlv_header header;
+       uint8_t route_type;
+       uint8_t pref_length;
+       uint8_t af;
+       uint8_t flags;
+       struct in_addr address;
+};
+
+/* Extended Link TLV see RFC 7684 section 3.1 */
+#define EXT_TLV_LINK                   1
+#define EXT_TLV_LINK_SIZE              12
+struct ext_tlv_link {
+       struct tlv_header header;
+       uint8_t link_type;
+       uint8_t reserved[3];
+       struct in_addr link_id;
+       struct in_addr link_data;
+};
+
+/* Remote Interface Address Sub-TLV, Cisco experimental use Sub-TLV */
+#define EXT_SUBTLV_RMT_ITF_ADDR         32768
+#define EXT_SUBTLV_RMT_ITF_ADDR_SIZE   4
+struct ext_subtlv_rmt_itf_addr {
+       struct tlv_header header;
+       struct in_addr value;
+};
+
+/* Internal structure to manage Extended Link/Prefix Opaque LSA */
+struct ospf_ext_lp {
+       bool enabled;
+
+       /* Flags to manage this Extended Prefix/Link Opaque LSA */
+       uint32_t flags;
+
+       /*
+        * Scope is area Opaque Type 10 or AS Opaque LSA Type 11 for
+        * Extended Prefix and area Opaque Type 10 for Extended Link
+        */
+       uint8_t scope;
+
+       /* area pointer if flooding is Type 10 Null if flooding is AS scope */
+       struct ospf_area *area;
+       struct in_addr area_id;
+
+       /* List of interface with Segment Routing enable */
+       struct list *iflist;
+};
+
+/* Structure to aggregate interfaces information for Extended Prefix/Link */
+struct ext_itf {
+       /* 24-bit Opaque-ID field value according to RFC 7684 specification */
+       uint32_t instance;
+       uint8_t type; /* Extended Prefix (7) or Link (8) */
+
+       /* Reference pointer to a Zebra-interface. */
+       struct interface *ifp;
+
+       /* Area info in which this SR link belongs to. */
+       struct ospf_area *area;
+
+       /* Flags to manage this link parameters. */
+       uint32_t flags;
+
+       /* SID type: Node, Adjacency or LAN Adjacency */
+       enum sid_type stype;
+
+       /* extended link/prefix TLV information */
+       struct ext_tlv_prefix prefix;
+       struct ext_subtlv_prefix_sid node_sid;
+       struct ext_tlv_link link;
+       struct ext_subtlv_adj_sid adj_sid[2];
+       struct ext_subtlv_lan_adj_sid lan_sid[2];
+
+       /* cisco experimental subtlv */
+       struct ext_subtlv_rmt_itf_addr rmt_itf_addr;
+};
+
+/* Prototypes. */
+extern int ospf_ext_init(void);
+extern void ospf_ext_term(void);
+extern void ospf_ext_finish(void);
+extern void ospf_ext_update_sr(bool enable);
+extern uint32_t ospf_ext_schedule_prefix_index(struct interface *ifp,
+                                         uint32_t index,
+                                         struct prefix_ipv4 *p,
+                                         uint8_t flags);
+#endif /* _FRR_OSPF_EXT_PREF_H_ */
index 36b6d5143d813885227cf1f4ad9fbe2dc2923026..7ad9cf9f2f1c224c372391ae79e5f2263d1666ab 100644 (file)
@@ -563,6 +563,7 @@ int ospf_flood_through_area(struct ospf_area *area, struct ospf_neighbor *inbr,
        struct ospf_interface *oi;
        int lsa_ack_flag = 0;
 
+       assert(area);
        /* All other types are specific to a single area (Area A).  The
           eligible interfaces are all those interfaces attaching to the
           Area A.  If Area A is the backbone, this includes all the virtual
index c65d8b874361a2dd2b755070390e1adf7da20bad..e570f3337a95ae99238bda47c2a82481b8213e92 100644 (file)
@@ -283,7 +283,7 @@ static void ospf_examine_summaries(struct ospf_area *area,
        struct route_node *rn;
 
        LSDB_LOOP(lsdb_rt, rn, lsa)
-       process_summary_lsa(area, rt, rtrs, lsa);
+               process_summary_lsa(area, rt, rtrs, lsa);
 }
 
 int ospf_area_is_transit(struct ospf_area *area)
@@ -583,7 +583,7 @@ static void ospf_examine_transit_summaries(struct ospf_area *area,
        struct route_node *rn;
 
        LSDB_LOOP(lsdb_rt, rn, lsa)
-       process_transit_summary_lsa(area, rt, rtrs, lsa);
+               process_transit_summary_lsa(area, rt, rtrs, lsa);
 }
 
 void ospf_ia_routing(struct ospf *ospf, struct route_table *rt,
index e8700e7eb062611385170dd92bd40582912a52d2..c8f758525ed07a66378d4bb3141a4bd6c54f7996 100644 (file)
@@ -51,6 +51,28 @@ DEFINE_QOBJ_TYPE(ospf_interface)
 DEFINE_HOOK(ospf_vl_add, (struct ospf_vl_data * vd), (vd))
 DEFINE_HOOK(ospf_vl_delete, (struct ospf_vl_data * vd), (vd))
 
+int ospf_interface_neighbor_count(struct ospf_interface *oi)
+{
+       int count = 0;
+       struct route_node *rn;
+       struct ospf_neighbor *nbr = NULL;
+
+       for (rn = route_top(oi->nbrs); rn; rn = route_next(rn)) {
+               nbr = rn->info;
+               if (nbr) {
+                       /* Do not show myself. */
+                       if (nbr == oi->nbr_self)
+                               continue;
+                       /* Down state is not shown. */
+                       if (nbr->state == NSM_Down)
+                               continue;
+                       count++;
+               }
+       }
+
+       return count;
+}
+
 int ospf_if_get_output_cost(struct ospf_interface *oi)
 {
        /* If all else fails, use default OSPF cost */
index 829a3f4297985f172b5c14448a7742c23df50f83..ab02444f7d82228f5e694af46391929e7986a3c1 100644 (file)
@@ -314,8 +314,8 @@ extern struct crypt_key *ospf_crypt_key_lookup(struct list *, u_char);
 extern struct crypt_key *ospf_crypt_key_new(void);
 extern void ospf_crypt_key_add(struct list *, struct crypt_key *);
 extern int ospf_crypt_key_delete(struct list *, u_char);
-
 extern u_char ospf_default_iftype(struct interface *ifp);
+extern int ospf_interface_neighbor_count(struct ospf_interface *oi);
 
 /* Set all multicast memberships appropriately based on the type and
    state of the interface. */
index a2961992de42bd3e51a8bc3a1027d142019605d1..0f1dd63dfb549c230d92b6629560e3c198ea68c5 100644 (file)
@@ -1872,8 +1872,7 @@ struct ospf_lsa *ospf_translated_nssa_refresh(struct ospf *ospf,
                        if (area->external_routing != OSPF_AREA_NSSA && !type7)
                                continue;
 
-                       LSDB_LOOP(NSSA_LSDB(area), rn, lsa)
-                       {
+                       LSDB_LOOP (NSSA_LSDB(area), rn, lsa) {
                                if (lsa->data->id.s_addr
                                    == type5->data->id.s_addr) {
                                        type7 = lsa;
@@ -3007,27 +3006,27 @@ int ospf_lsa_maxage_walker(struct thread *thread)
 
        for (ALL_LIST_ELEMENTS(ospf->areas, node, nnode, area)) {
                LSDB_LOOP(ROUTER_LSDB(area), rn, lsa)
-               ospf_lsa_maxage_walker_remover(ospf, lsa);
+                       ospf_lsa_maxage_walker_remover(ospf, lsa);
                LSDB_LOOP(NETWORK_LSDB(area), rn, lsa)
-               ospf_lsa_maxage_walker_remover(ospf, lsa);
+                       ospf_lsa_maxage_walker_remover(ospf, lsa);
                LSDB_LOOP(SUMMARY_LSDB(area), rn, lsa)
-               ospf_lsa_maxage_walker_remover(ospf, lsa);
+                       ospf_lsa_maxage_walker_remover(ospf, lsa);
                LSDB_LOOP(ASBR_SUMMARY_LSDB(area), rn, lsa)
-               ospf_lsa_maxage_walker_remover(ospf, lsa);
+                       ospf_lsa_maxage_walker_remover(ospf, lsa);
                LSDB_LOOP(OPAQUE_AREA_LSDB(area), rn, lsa)
-               ospf_lsa_maxage_walker_remover(ospf, lsa);
+                       ospf_lsa_maxage_walker_remover(ospf, lsa);
                LSDB_LOOP(OPAQUE_LINK_LSDB(area), rn, lsa)
-               ospf_lsa_maxage_walker_remover(ospf, lsa);
+                       ospf_lsa_maxage_walker_remover(ospf, lsa);
                LSDB_LOOP(NSSA_LSDB(area), rn, lsa)
-               ospf_lsa_maxage_walker_remover(ospf, lsa);
+                       ospf_lsa_maxage_walker_remover(ospf, lsa);
        }
 
        /* for AS-external-LSAs. */
        if (ospf->lsdb) {
                LSDB_LOOP(EXTERNAL_LSDB(ospf), rn, lsa)
-               ospf_lsa_maxage_walker_remover(ospf, lsa);
+                       ospf_lsa_maxage_walker_remover(ospf, lsa);
                LSDB_LOOP(OPAQUE_AS_LSDB(ospf), rn, lsa)
-               ospf_lsa_maxage_walker_remover(ospf, lsa);
+                       ospf_lsa_maxage_walker_remover(ospf, lsa);
        }
 
        OSPF_TIMER_ON(ospf->t_maxage_walker, ospf_lsa_maxage_walker,
@@ -3350,20 +3349,20 @@ void ospf_flush_self_originated_lsas_now(struct ospf *ospf)
                }
 
                LSDB_LOOP(SUMMARY_LSDB(area), rn, lsa)
-               ospf_lsa_flush_schedule(ospf, lsa);
+                       ospf_lsa_flush_schedule(ospf, lsa);
                LSDB_LOOP(ASBR_SUMMARY_LSDB(area), rn, lsa)
-               ospf_lsa_flush_schedule(ospf, lsa);
+                       ospf_lsa_flush_schedule(ospf, lsa);
                LSDB_LOOP(OPAQUE_LINK_LSDB(area), rn, lsa)
-               ospf_lsa_flush_schedule(ospf, lsa);
+                       ospf_lsa_flush_schedule(ospf, lsa);
                LSDB_LOOP(OPAQUE_AREA_LSDB(area), rn, lsa)
-               ospf_lsa_flush_schedule(ospf, lsa);
+                       ospf_lsa_flush_schedule(ospf, lsa);
        }
 
        if (need_to_flush_ase) {
                LSDB_LOOP(EXTERNAL_LSDB(ospf), rn, lsa)
-               ospf_lsa_flush_schedule(ospf, lsa);
+                       ospf_lsa_flush_schedule(ospf, lsa);
                LSDB_LOOP(OPAQUE_AS_LSDB(ospf), rn, lsa)
-               ospf_lsa_flush_schedule(ospf, lsa);
+                       ospf_lsa_flush_schedule(ospf, lsa);
        }
 
        /*
index cdc9b929fa1f3b3f179b82a842b532faac6a2b8c..1332104b0afdd6a384f2b1cf6ff14a4785107d7c 100644 (file)
@@ -53,3 +53,5 @@ DEFINE_MTYPE(OSPFD, OSPF_IF_PARAMS, "OSPF if params")
 DEFINE_MTYPE(OSPFD, OSPF_MESSAGE, "OSPF message")
 DEFINE_MTYPE(OSPFD, OSPF_MPLS_TE, "OSPF MPLS parameters")
 DEFINE_MTYPE(OSPFD, OSPF_PCE_PARAMS, "OSPF PCE parameters")
+DEFINE_MTYPE(OSPFD, OSPF_EXT_PARAMS, "OSPF Extended parameters")
+DEFINE_MTYPE(OSPFD, OSPF_SR_PARAMS, "OSPF Segment Routing parameters")
index 5f5960eec7cc48c01ffdd9ba047a5f587bd24335..50c6f33ecfbc4c5d03ab4747d9c8c5461f96573b 100644 (file)
@@ -52,5 +52,7 @@ DECLARE_MTYPE(OSPF_IF_PARAMS)
 DECLARE_MTYPE(OSPF_MESSAGE)
 DECLARE_MTYPE(OSPF_MPLS_TE)
 DECLARE_MTYPE(OSPF_PCE_PARAMS)
+DECLARE_MTYPE(OSPF_SR_PARAMS)
+DECLARE_MTYPE(OSPF_EXT_PARAMS)
 
 #endif /* _QUAGGA_OSPF_MEMORY_H */
index ed5e8e027d82834c1c6dc4d642df95e61e5653f3..022a5a138af117483c9665d1c7948ebd493f16a3 100644 (file)
@@ -38,7 +38,7 @@
 #include "ospfd/ospf_lsdb.h"
 #include "ospfd/ospf_neighbor.h"
 #include "ospfd/ospf_packet.h"
-
+#include "ospfd/ospf_dump.h"
 
 /* Join to the OSPF ALL SPF ROUTERS multicast group. */
 int ospf_if_add_allspfrouters(struct ospf *top, struct prefix *p,
@@ -56,10 +56,11 @@ int ospf_if_add_allspfrouters(struct ospf *top, struct prefix *p,
                        "on # of multicast group memberships has been exceeded?",
                        top->fd, inet_ntoa(p->u.prefix4), ifindex,
                        safe_strerror(errno));
-       else
-               zlog_debug(
-                       "interface %s [%u] join AllSPFRouters Multicast group.",
-                       inet_ntoa(p->u.prefix4), ifindex);
+       else {
+               if (IS_DEBUG_OSPF_EVENT)
+                       zlog_debug("interface %s [%u] join AllSPFRouters Multicast group.",
+                                  inet_ntoa(p->u.prefix4), ifindex);
+       }
 
        return ret;
 }
@@ -78,10 +79,11 @@ int ospf_if_drop_allspfrouters(struct ospf *top, struct prefix *p,
                        "ifindex %u, AllSPFRouters): %s",
                        top->fd, inet_ntoa(p->u.prefix4), ifindex,
                        safe_strerror(errno));
-       else
-               zlog_debug(
-                       "interface %s [%u] leave AllSPFRouters Multicast group.",
-                       inet_ntoa(p->u.prefix4), ifindex);
+       else {
+               if (IS_DEBUG_OSPF_EVENT)
+                       zlog_debug("interface %s [%u] leave AllSPFRouters Multicast group.",
+                                  inet_ntoa(p->u.prefix4), ifindex);
+       }
 
        return ret;
 }
index a0ff2bfccf8684f817ad2cf152bee22925bf10f8..54d5dd5d1680fea353667dcbbab657d387075463 100644 (file)
@@ -280,37 +280,37 @@ static int nsm_negotiation_done(struct ospf_neighbor *nbr)
        ospf_proactively_arp(nbr);
 
        LSDB_LOOP(ROUTER_LSDB(area), rn, lsa)
-       ospf_db_summary_add(nbr, lsa);
+               ospf_db_summary_add(nbr, lsa);
        LSDB_LOOP(NETWORK_LSDB(area), rn, lsa)
-       ospf_db_summary_add(nbr, lsa);
+               ospf_db_summary_add(nbr, lsa);
        LSDB_LOOP(SUMMARY_LSDB(area), rn, lsa)
-       ospf_db_summary_add(nbr, lsa);
+               ospf_db_summary_add(nbr, lsa);
        LSDB_LOOP(ASBR_SUMMARY_LSDB(area), rn, lsa)
-       ospf_db_summary_add(nbr, lsa);
+               ospf_db_summary_add(nbr, lsa);
 
        /* Process only if the neighbor is opaque capable. */
        if (CHECK_FLAG(nbr->options, OSPF_OPTION_O)) {
                LSDB_LOOP(OPAQUE_LINK_LSDB(area), rn, lsa)
-               ospf_db_summary_add(nbr, lsa);
+                       ospf_db_summary_add(nbr, lsa);
                LSDB_LOOP(OPAQUE_AREA_LSDB(area), rn, lsa)
-               ospf_db_summary_add(nbr, lsa);
+                       ospf_db_summary_add(nbr, lsa);
        }
 
        if (CHECK_FLAG(nbr->options, OSPF_OPTION_NP)) {
                LSDB_LOOP(NSSA_LSDB(area), rn, lsa)
-               ospf_db_summary_add(nbr, lsa);
+                       ospf_db_summary_add(nbr, lsa);
        }
 
        if (nbr->oi->type != OSPF_IFTYPE_VIRTUALLINK
            && area->external_routing == OSPF_AREA_DEFAULT)
                LSDB_LOOP(EXTERNAL_LSDB(nbr->oi->ospf), rn, lsa)
-       ospf_db_summary_add(nbr, lsa);
+                       ospf_db_summary_add(nbr, lsa);
 
        if (CHECK_FLAG(nbr->options, OSPF_OPTION_O)
            && (nbr->oi->type != OSPF_IFTYPE_VIRTUALLINK
                && area->external_routing == OSPF_AREA_DEFAULT))
                LSDB_LOOP(OPAQUE_AS_LSDB(nbr->oi->ospf), rn, lsa)
-       ospf_db_summary_add(nbr, lsa);
+                       ospf_db_summary_add(nbr, lsa);
 
        return 0;
 }
@@ -702,12 +702,12 @@ static void nsm_change_state(struct ospf_neighbor *nbr, int state)
                                                        oi->ospf);
                }
 
-               zlog_info(
-                       "nsm_change_state(%s, %s -> %s): "
-                       "scheduling new router-LSA origination",
-                       inet_ntoa(nbr->router_id),
-                       lookup_msg(ospf_nsm_state_msg, old_state, NULL),
-                       lookup_msg(ospf_nsm_state_msg, state, NULL));
+               if (CHECK_FLAG(oi->ospf->config, OSPF_LOG_ADJACENCY_DETAIL))
+                       zlog_info("%s:(%s, %s -> %s): "
+                               "scheduling new router-LSA origination",
+                               __PRETTY_FUNCTION__, inet_ntoa(nbr->router_id),
+                               lookup_msg(ospf_nsm_state_msg, old_state, NULL),
+                               lookup_msg(ospf_nsm_state_msg, state, NULL));
 
                ospf_router_lsa_update_area(oi->area);
 
index 6f9da925428973e3e238f47e976bdb690e42230b..009fd997eab9a34beea663b7fb7a879474d92f87 100644 (file)
 #include "ospfd/ospf_route.h"
 #include "ospfd/ospf_ase.h"
 #include "ospfd/ospf_zebra.h"
+#include "ospfd/ospf_te.h"
+#include "ospfd/ospf_sr.h"
+#include "ospfd/ospf_ri.h"
+#include "ospfd/ospf_ext.h"
 
 DEFINE_MTYPE_STATIC(OSPFD, OSPF_OPAQUE_FUNCTAB, "OSPF opaque function table")
 DEFINE_MTYPE_STATIC(OSPFD, OPAQUE_INFO_PER_TYPE, "OSPF opaque per-type info")
@@ -59,9 +63,6 @@ DEFINE_MTYPE_STATIC(OSPFD, OPAQUE_INFO_PER_ID, "OSPF opaque per-ID info")
  * Followings are initialize/terminate functions for Opaque-LSAs handling.
  *------------------------------------------------------------------------*/
 
-#include "ospfd/ospf_te.h"
-#include "ospfd/ospf_ri.h"
-
 #ifdef SUPPORT_OSPF_API
 int ospf_apiserver_init(void);
 void ospf_apiserver_term(void);
@@ -74,6 +75,7 @@ static void ospf_opaque_funclist_init(void);
 static void ospf_opaque_funclist_term(void);
 static void free_opaque_info_per_type(void *val);
 static void free_opaque_info_per_id(void *val);
+static void free_opaque_info_owner(void *val);
 static int ospf_opaque_lsa_install_hook(struct ospf_lsa *lsa);
 static int ospf_opaque_lsa_delete_hook(struct ospf_lsa *lsa);
 
@@ -85,9 +87,16 @@ void ospf_opaque_init(void)
        if (ospf_mpls_te_init() != 0)
                exit(1);
 
+       /* Segment Routing init */
+       if (ospf_sr_init() != 0)
+               exit(1);
+
        if (ospf_router_info_init() != 0)
                exit(1);
 
+       if (ospf_ext_init() != 0)
+               exit(1);
+
 #ifdef SUPPORT_OSPF_API
        if ((ospf_apiserver_enable) && (ospf_apiserver_init() != 0))
                exit(1);
@@ -102,6 +111,10 @@ void ospf_opaque_term(void)
 
        ospf_router_info_term();
 
+       ospf_ext_term();
+
+       ospf_sr_term();
+
 #ifdef SUPPORT_OSPF_API
        ospf_apiserver_term();
 #endif /* SUPPORT_OSPF_API */
@@ -110,6 +123,15 @@ void ospf_opaque_term(void)
        return;
 }
 
+void ospf_opaque_finish(void)
+{
+       ospf_router_info_finish();
+
+       ospf_ext_finish();
+
+       ospf_sr_finish();
+}
+
 int ospf_opaque_type9_lsa_init(struct ospf_interface *oi)
 {
        if (oi->opaque_lsa_self != NULL)
@@ -209,6 +231,12 @@ static const char *ospf_opaque_type_name(u_char opaque_type)
        case OPAQUE_TYPE_ROUTER_INFORMATION_LSA:
                name = "Router Information LSA";
                break;
+       case OPAQUE_TYPE_EXTENDED_PREFIX_LSA:
+               name = "Extended Prefix Opaque LSA";
+               break;
+       case OPAQUE_TYPE_EXTENDED_LINK_LSA:
+               name = "Extended Link Opaque LSA";
+               break;
        default:
                if (OPAQUE_TYPE_RANGE_UNASSIGNED(opaque_type))
                        name = "Unassigned";
@@ -412,9 +440,11 @@ void ospf_delete_opaque_functab(u_char lsa_type, u_char opaque_type)
                        if (functab->opaque_type == opaque_type) {
                                /* Cleanup internal control information, if it
                                 * still remains. */
-                               if (functab->oipt != NULL)
+                               if (functab->oipt != NULL) {
                                        free_opaque_info_per_type(
                                                functab->oipt);
+                                       free_opaque_info_owner(functab->oipt);
+                               }
 
                                /* Dequeue listnode entry from the list. */
                                listnode_delete(funclist, functab);
@@ -545,6 +575,7 @@ register_opaque_info_per_type(struct ospf_opaque_functab *functab,
                top = ospf_lookup_by_vrf_id(new->vrf_id);
                if (new->area != NULL && (top = new->area->ospf) == NULL) {
                        free_opaque_info_per_type((void *)oipt);
+                       free_opaque_info_owner(oipt);
                        oipt = NULL;
                        goto out; /* This case may not exist. */
                }
@@ -556,6 +587,7 @@ register_opaque_info_per_type(struct ospf_opaque_functab *functab,
                        "register_opaque_info_per_type: Unexpected LSA-type(%u)",
                        new->data->type);
                free_opaque_info_per_type((void *)oipt);
+               free_opaque_info_owner(oipt);
                oipt = NULL;
                goto out; /* This case may not exist. */
        }
@@ -573,6 +605,35 @@ out:
        return oipt;
 }
 
+/* Remove "oipt" from its owner's self-originated LSA list. */
+static void free_opaque_info_owner(void *val)
+{
+       struct opaque_info_per_type *oipt = (struct opaque_info_per_type *)val;
+
+        switch (oipt->lsa_type) {
+        case OSPF_OPAQUE_LINK_LSA: {
+                struct ospf_interface *oi =
+                        (struct ospf_interface *)(oipt->owner);
+                listnode_delete(oi->opaque_lsa_self, oipt);
+                break;
+        }
+        case OSPF_OPAQUE_AREA_LSA: {
+                struct ospf_area *area = (struct ospf_area *)(oipt->owner);
+                listnode_delete(area->opaque_lsa_self, oipt);
+                break;
+        }
+        case OSPF_OPAQUE_AS_LSA: {
+                struct ospf *top = (struct ospf *)(oipt->owner);
+                listnode_delete(top->opaque_lsa_self, oipt);
+                break;
+        }
+        default:
+                zlog_warn("free_opaque_info_owner: Unexpected LSA-type(%u)",
+                          oipt->lsa_type);
+                break; /* This case may not exist. */
+        }
+}
+
 static void free_opaque_info_per_type(void *val)
 {
        struct opaque_info_per_type *oipt = (struct opaque_info_per_type *)val;
@@ -589,30 +650,6 @@ static void free_opaque_info_per_type(void *val)
                ospf_opaque_lsa_flush_schedule(lsa);
        }
 
-       /* Remove "oipt" from its owner's self-originated LSA list. */
-       switch (oipt->lsa_type) {
-       case OSPF_OPAQUE_LINK_LSA: {
-               struct ospf_interface *oi =
-                       (struct ospf_interface *)(oipt->owner);
-               listnode_delete(oi->opaque_lsa_self, oipt);
-               break;
-       }
-       case OSPF_OPAQUE_AREA_LSA: {
-               struct ospf_area *area = (struct ospf_area *)(oipt->owner);
-               listnode_delete(area->opaque_lsa_self, oipt);
-               break;
-       }
-       case OSPF_OPAQUE_AS_LSA: {
-               struct ospf *top = (struct ospf *)(oipt->owner);
-               listnode_delete(top->opaque_lsa_self, oipt);
-               break;
-       }
-       default:
-               zlog_warn("free_opaque_info_per_type: Unexpected LSA-type(%u)",
-                         oipt->lsa_type);
-               break; /* This case may not exist. */
-       }
-
        OSPF_TIMER_OFF(oipt->t_opaque_lsa_self);
        list_delete_and_null(&oipt->id_list);
        XFREE(MTYPE_OPAQUE_INFO_PER_TYPE, oipt);
@@ -1786,7 +1823,7 @@ void ospf_opaque_lsa_reoriginate_schedule(void *lsa_type_dependent,
                        lsa_type, delay,
                        GET_OPAQUE_TYPE(ntohl(lsa->data->id.s_addr)));
 
-       OSPF_OPAQUE_TIMER_ON(oipt->t_opaque_lsa_self, func, oipt, delay * 1000);
+       OSPF_OPAQUE_TIMER_ON(oipt->t_opaque_lsa_self, func, oipt, delay);
 
 out:
        return;
index 9dc1f92f4dc16ab0decc992dd94c3fdb1405342d..632b7b039e554285908f54ef2f8f21db69c587f7 100644 (file)
@@ -59,7 +59,9 @@
 #define OPAQUE_TYPE_L1VPN_LSA                          5
 #define OPAQUE_TYPE_ROUTER_INFORMATION_LSA             4
 #define OPAQUE_TYPE_INTER_AS_LSA                       6
-#define OPAQUE_TYPE_MAX                                6
+#define OPAQUE_TYPE_EXTENDED_PREFIX_LSA                7
+#define OPAQUE_TYPE_EXTENDED_LINK_LSA                  8
+#define OPAQUE_TYPE_MAX                                8
 
 /* Followings types are proposed in internet-draft documents. */
 #define OPAQUE_TYPE_8021_QOSPF                         129
@@ -120,6 +122,7 @@ enum lsa_opcode {
 
 extern void ospf_opaque_init(void);
 extern void ospf_opaque_term(void);
+extern void ospf_opaque_finish(void);
 extern int ospf_opaque_type9_lsa_init(struct ospf_interface *oi);
 extern void ospf_opaque_type9_lsa_term(struct ospf_interface *oi);
 extern int ospf_opaque_type10_lsa_init(struct ospf_area *area);
index 65e9cac8371154fe27b3cc31f0958ddadfa78645..881226683c572f1a183f6273cd301be8e9fa89c9 100644 (file)
@@ -1363,9 +1363,11 @@ static void ospf_db_desc(struct ip *iph, struct ospf_header *ospfh,
                        if (IPV4_ADDR_CMP(&nbr->router_id, &oi->ospf->router_id)
                            > 0) {
                                /* We're Slave---obey */
-                               zlog_info(
-                                       "Packet[DD]: Neighbor %s Negotiation done (Slave).",
-                                       inet_ntoa(nbr->router_id));
+                               if (CHECK_FLAG(oi->ospf->config,
+                                              OSPF_LOG_ADJACENCY_DETAIL))
+                                       zlog_info("Packet[DD]: Neighbor %s Negotiation done (Slave).",
+                                                 inet_ntoa(nbr->router_id));
+
                                nbr->dd_seqnum = ntohl(dd->dd_seqnum);
 
                                /* Reset I/MS */
@@ -1374,10 +1376,12 @@ static void ospf_db_desc(struct ip *iph, struct ospf_header *ospfh,
                        } else {
                                /* We're Master, ignore the initial DBD from
                                 * Slave */
-                               zlog_info(
-                                       "Packet[DD]: Neighbor %s: Initial DBD from Slave, "
-                                       "ignoring.",
-                                       inet_ntoa(nbr->router_id));
+                               if (CHECK_FLAG(oi->ospf->config,
+                                              OSPF_LOG_ADJACENCY_DETAIL))
+                                       zlog_info(
+                                               "Packet[DD]: Neighbor %s: Initial DBD from Slave, "
+                                               "ignoring.",
+                                               inet_ntoa(nbr->router_id));
                                break;
                        }
                }
@@ -3893,6 +3897,10 @@ static void ospf_ls_upd_queue_send(struct ospf_interface *oi,
                zlog_debug("listcount = %d, [%s]dst %s", listcount(update),
                           IF_NAME(oi), inet_ntoa(addr));
 
+       /* Check that we have really something to process */
+       if (listcount(update) == 0)
+               return;
+
        op = ospf_ls_upd_packet_new(update, oi);
 
        /* Prepare OSPF common header. */
index ead6923435399ac3018a97a108df0a0bdb6049a1..7c7a6fd795cf79f555d2bf16c0d9af53672920b8 100644 (file)
@@ -3,9 +3,8 @@
  * with support of RFC5088 PCE Capabilites announcement
  *
  * Module name: Router Information
- * Version:     0.99.22
- * Created:     2012-02-01 by Olivier Dugeon
- * Copyright (C) 2012 Orange Labs http://www.orange.com/
+ * Author: Olivier Dugeon <olivier.dugeon@orange.com>
+ * Copyright (C) 2012 - 2017 Orange Labs http://www.orange.com/
  *
  * This file is part of GNU Quagga.
  *
@@ -39,6 +38,7 @@
 #include "thread.h"
 #include "hash.h"
 #include "sockunion.h" /* for inet_aton() */
+#include "mpls.h"
 
 #include "ospfd/ospfd.h"
 #include "ospfd/ospf_interface.h"
@@ -55,8 +55,8 @@
 #include "ospfd/ospf_route.h"
 #include "ospfd/ospf_ase.h"
 #include "ospfd/ospf_zebra.h"
+#include "ospfd/ospf_sr.h"
 #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 {
@@ -69,6 +69,23 @@ struct ospf_pce_info {
        struct ri_pce_subtlv_cap_flag pce_cap_flag;
 };
 
+/*
+ * Store Router Information Segment Routing TLV and SubTLV
+ * in network byte order
+ */
+struct ospf_ri_sr_info {
+       bool enabled;
+       /* Algorithms supported by the node */
+       struct ri_sr_tlv_sr_algorithm algo;
+       /*
+        * Segment Routing Global Block i.e. label range
+        * Only one range supported in this code
+        */
+       struct ri_sr_tlv_sid_label_range range;
+       /* Maximum SID Depth supported by the node */
+       struct ri_sr_tlv_node_msd msd;
+};
+
 /* Following structure are internal use only. */
 struct ospf_router_info {
        bool enabled;
@@ -77,7 +94,7 @@ struct ospf_router_info {
        u_int8_t scope;
 
 /* Flags to manage this router information. */
-#define RIFLG_LSA_ENGAGED                      0x1
+#define RIFLG_LSA_ENGAGED              0x1
 #define RIFLG_LSA_FORCED_REFRESH       0x2
        u_int32_t flags;
 
@@ -90,6 +107,9 @@ struct ospf_router_info {
 
        /* Store PCE capability LSA */
        struct ospf_pce_info pce_info;
+
+       /* Store SR capability LSA */
+       struct ospf_ri_sr_info sr_info;
 };
 
 /*
@@ -113,15 +133,19 @@ 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(enum lsa_opcode opcode);
 static void ospf_router_info_register_vty(void);
+static int ospf_router_info_lsa_update(struct ospf_lsa *lsa);
 static void del_pce_info(void *val);
 
 int ospf_router_info_init(void)
 {
 
+       zlog_info("RI -> Initialize Router Information");
+
        memset(&OspfRI, 0, sizeof(struct ospf_router_info));
        OspfRI.enabled = false;
        OspfRI.registered = 0;
        OspfRI.scope = OSPF_OPAQUE_AS_LSA;
+       OspfRI.area_id.s_addr = 0;
        OspfRI.flags = 0;
 
        /* Initialize pce domain and neighbor list */
@@ -131,6 +155,9 @@ int ospf_router_info_init(void)
        OspfRI.pce_info.pce_neighbor = list_new();
        OspfRI.pce_info.pce_neighbor->del = del_pce_info;
 
+       /* Initialize Segment Routing information structure */
+       OspfRI.sr_info.enabled = false;
+
        ospf_router_info_register_vty();
 
        return 0;
@@ -143,19 +170,22 @@ static int ospf_router_info_register(u_int8_t scope)
        if (OspfRI.registered)
                return rc;
 
-       zlog_info("Register Router Information with scope %s(%d)",
+       zlog_info("RI -> Register Router Information with scope %s(%d)",
                  scope == OSPF_OPAQUE_AREA_LSA ? "Area" : "AS", scope);
        rc = ospf_register_opaque_functab(
                scope, OPAQUE_TYPE_ROUTER_INFORMATION_LSA,
                NULL, /* new interface */
                NULL, /* del interface */
-               ospf_router_info_ism_change, ospf_router_info_nsm_change,
+               ospf_router_info_ism_change,
+               ospf_router_info_nsm_change,
                ospf_router_info_config_write_router,
                NULL, /* Config. write interface */
                NULL, /* Config. write debug */
-               ospf_router_info_show_info, ospf_router_info_lsa_originate,
-               ospf_router_info_lsa_refresh, NULL, /* new_lsa_hook */
-               NULL);                              /* del_lsa_hook */
+               ospf_router_info_show_info,
+               ospf_router_info_lsa_originate,
+               ospf_router_info_lsa_refresh,
+               ospf_router_info_lsa_update,
+               NULL); /* del_lsa_hook */
 
        if (rc != 0) {
                zlog_warn(
@@ -198,12 +228,35 @@ void ospf_router_info_term(void)
        return;
 }
 
+void ospf_router_info_finish(void)
+{
+       list_delete_all_node(OspfRI.pce_info.pce_domain);
+       list_delete_all_node(OspfRI.pce_info.pce_neighbor);
+
+       OspfRI.enabled = false;
+}
+
 static void del_pce_info(void *val)
 {
        XFREE(MTYPE_OSPF_PCE_PARAMS, val);
        return;
 }
 
+/* Catch RI LSA flooding Scope for ospf_ext.[h,c] code */
+struct scope_info ospf_router_info_get_flooding_scope(void)
+{
+       struct scope_info flooding_scope;
+
+       if (OspfRI.scope == OSPF_OPAQUE_AS_LSA) {
+               flooding_scope.scope = OSPF_OPAQUE_AS_LSA;
+               flooding_scope.area_id.s_addr = 0;
+               return flooding_scope;
+       }
+       flooding_scope.scope = OSPF_OPAQUE_AREA_LSA;
+       flooding_scope.area_id.s_addr = OspfRI.area_id.s_addr;
+       return flooding_scope;
+}
+
 /*------------------------------------------------------------------------*
  * Followings are control functions for ROUTER INFORMATION parameters
  *management.
@@ -399,6 +452,78 @@ static void set_pce_cap_flag(u_int32_t cap, struct ospf_pce_info *pce)
        return;
 }
 
+/* Segment Routing TLV setter */
+
+/* Algorithm SubTLV - section 3.1 */
+static void set_sr_algorithm(uint8_t algo)
+{
+
+       OspfRI.sr_info.algo.value[0] = algo;
+       for (int i = 1; i < ALGORITHM_COUNT; i++)
+               OspfRI.sr_info.algo.value[i] = SR_ALGORITHM_UNSET;
+
+       /* Set TLV type and length == only 1 Algorithm */
+       TLV_TYPE(OspfRI.sr_info.algo) = htons(RI_SR_TLV_SR_ALGORITHM);
+       TLV_LEN(OspfRI.sr_info.algo) = htons(sizeof(uint8_t));
+
+}
+
+/* unset Aglogithm SubTLV */
+static void unset_sr_algorithm(uint8_t algo)
+{
+
+       for (int i = 0; i < ALGORITHM_COUNT; i++)
+               OspfRI.sr_info.algo.value[i] = SR_ALGORITHM_UNSET;
+
+       /* Unset TLV type and length */
+       TLV_TYPE(OspfRI.sr_info.algo) = htons(0);
+       TLV_LEN(OspfRI.sr_info.algo) = htons(0);
+
+}
+
+/* Segment Routing Global Block SubTLV - section 3.2 */
+static void set_sr_sid_label_range(struct sr_srgb srgb)
+{
+       /* Set Header */
+       TLV_TYPE(OspfRI.sr_info.range) = htons(RI_SR_TLV_SID_LABEL_RANGE);
+       TLV_LEN(OspfRI.sr_info.range) =
+               htons(SUBTLV_SID_LABEL_SIZE + sizeof(uint32_t));
+       /* Set Range Size */
+       OspfRI.sr_info.range.size = htonl(SET_RANGE_SIZE(srgb.range_size));
+       /* Set Lower bound label SubTLV */
+       TLV_TYPE(OspfRI.sr_info.range.lower) = htons(SUBTLV_SID_LABEL);
+       TLV_LEN(OspfRI.sr_info.range.lower) = htons(SID_RANGE_LABEL_LENGTH);
+       OspfRI.sr_info.range.lower.value = htonl(SET_LABEL(srgb.lower_bound));
+
+}
+
+/* Unset this SRGB SubTLV */
+static void unset_sr_sid_label_range(void)
+{
+
+       TLV_TYPE(OspfRI.sr_info.range) = htons(0);
+       TLV_LEN(OspfRI.sr_info.range) = htons(0);
+       TLV_TYPE(OspfRI.sr_info.range.lower) = htons(0);
+       TLV_LEN(OspfRI.sr_info.range.lower) = htons(0);
+
+}
+
+/* Set Maximum Stack Depth for this router */
+static void set_sr_node_msd(uint8_t msd)
+{
+       TLV_TYPE(OspfRI.sr_info.msd) = htons(RI_SR_TLV_NODE_MSD);
+       TLV_LEN(OspfRI.sr_info.msd) = htons(sizeof(uint32_t));
+       OspfRI.sr_info.msd.value = msd;
+
+}
+
+/* Unset this router MSD */
+static void unset_sr_node_msd(void)
+{
+       TLV_TYPE(OspfRI.sr_info.msd) = htons(0);
+       TLV_LEN(OspfRI.sr_info.msd) = htons(0);
+
+}
 
 static void unset_param(struct tlv_header *tlv)
 {
@@ -466,11 +591,62 @@ static int is_mandated_params_set(struct ospf_router_info ori)
            && (ntohs(ori.pce_info.pce_cap_flag.header.type) == 0))
                return rc;
 
+       if ((ori.sr_info.enabled) && (ntohs(TLV_TYPE(ori.sr_info.algo)) == 0)
+           && (ntohs(TLV_TYPE(ori.sr_info.range)) == 0))
+               return rc;
+
        rc = 1;
 
        return rc;
 }
 
+/*
+ * Used by Segment Routing to set new TLVs and Sub-TLVs values
+ *
+ * @param enable To activate or not Segment Routing router Information flooding
+ * @param size   Size of Label Range i.e. SRGB size
+ * @param lower  Lower bound of the Label Range i.e. SRGB first label
+ * @param msd    Maximum label Stack Depth suported by the router
+ *
+ * @return none
+ */
+void ospf_router_info_update_sr(bool enable, struct sr_srgb srgb, uint8_t msd)
+{
+
+       /* First activate and initialize Router Information is necessary */
+       if (!OspfRI.enabled) {
+               OspfRI.enabled = true;
+               initialize_params(&OspfRI);
+       }
+
+       if (IS_DEBUG_OSPF_SR)
+               zlog_debug("RI-> %s Routing Information for Segment Routing",
+                       enable ? "Enable" : "Disable");
+
+       /* Unset or Set SR parameters */
+       if (!enable) {
+               unset_sr_algorithm(SR_ALGORITHM_SPF);
+               unset_sr_sid_label_range();
+               unset_sr_node_msd();
+               OspfRI.sr_info.enabled = false;
+       } else {
+               // Only SR_ALGORITHM_SPF is supported
+               set_sr_algorithm(SR_ALGORITHM_SPF);
+               set_sr_sid_label_range(srgb);
+               if (msd != 0)
+                       set_sr_node_msd(msd);
+               else
+                       unset_sr_node_msd();
+               OspfRI.sr_info.enabled = true;
+       }
+
+       /* Refresh if already engaged or originate RI LSA */
+       if (CHECK_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED))
+               ospf_router_info_lsa_schedule(REFRESH_THIS_LSA);
+       else
+               ospf_router_info_lsa_schedule(REORIGINATE_THIS_LSA);
+}
+
 /*------------------------------------------------------------------------*
  * Followings are callback functions against generic Opaque-LSAs handling.
  *------------------------------------------------------------------------*/
@@ -519,12 +695,22 @@ static void ospf_router_info_lsa_body_set(struct stream *s)
        /* Build Router Information TLV */
        build_tlv(s, &OspfRI.router_cap.header);
 
-       /* Compute PCE Info header first */
-       set_pce_header (&OspfRI.pce_info);
+       /* Build Segment Routing TLVs if enabled */
+       if (OspfRI.sr_info.enabled) {
+               /* Build Algorithm TLV */
+               build_tlv(s, &TLV_HDR(OspfRI.sr_info.algo));
+               /* Build SRGB TLV */
+               build_tlv(s, &TLV_HDR(OspfRI.sr_info.range));
+               /* Build MSD TLV */
+               build_tlv(s, &TLV_HDR(OspfRI.sr_info.msd));
+       }
 
        /* Add RI PCE TLV if it is set */
        if (OspfRI.pce_info.enabled) {
 
+               /* Compute PCE Info header first */
+               set_pce_header (&OspfRI.pce_info);
+
                /* Build PCE TLV */
                build_tlv_header(s, &OspfRI.pce_info.pce_header.header);
 
@@ -855,6 +1041,43 @@ static void ospf_router_info_lsa_schedule(enum lsa_opcode opcode)
        return;
 }
 
+/* Callback to handle Segment Routing information */
+static int ospf_router_info_lsa_update(struct ospf_lsa *lsa)
+{
+
+       /* Sanity Check */
+       if (lsa == NULL) {
+               zlog_warn("OSPF-RI (%s): Abort! LSA is NULL", __func__);
+               return -1;
+       }
+
+       /* Process only Opaque LSA */
+       if ((lsa->data->type != OSPF_OPAQUE_AREA_LSA)
+           && (lsa->data->type != OSPF_OPAQUE_AS_LSA))
+               return 0;
+
+       /* Process only Router Information LSA */
+       if (GET_OPAQUE_TYPE(ntohl(lsa->data->id.s_addr)) !=
+                       OPAQUE_TYPE_ROUTER_INFORMATION_LSA)
+               return 0;
+
+       /* Check if it is not my LSA */
+       if (IS_LSA_SELF(lsa))
+               return 0;
+
+       /* Check if Router Info & Segment Routing are enable */
+       if (!OspfRI.enabled || !OspfRI.sr_info.enabled)
+               return 0;
+
+       /* Call Segment Routing LSA update or deletion */
+       if (!IS_LSA_MAXAGE(lsa))
+               ospf_sr_ri_lsa_update(lsa);
+       else
+               ospf_sr_ri_lsa_delete(lsa);
+
+       return 0;
+}
+
 /*------------------------------------------------------------------------*
  * Followings are vty session control functions.
  *------------------------------------------------------------------------*/
@@ -1021,6 +1244,99 @@ static u_int16_t show_vty_pce_info(struct vty *vty, struct tlv_header *ri,
        return sum;
 }
 
+/* Display Segment Routing Algorithm TLV information */
+static uint16_t show_vty_sr_algorithm(struct vty *vty, struct tlv_header *tlvh)
+{
+       struct ri_sr_tlv_sr_algorithm *algo =
+               (struct ri_sr_tlv_sr_algorithm *)tlvh;
+       int i;
+
+       if (vty != NULL) {
+               vty_out(vty, "  Segment Routing Algorithm TLV:\n");
+               for (i = 0; i < ntohs(algo->header.length); i++) {
+                       switch (algo->value[i]) {
+                       case 0:
+                               vty_out(vty, "    Algorithm %d: SPF\n", i);
+                               break;
+                       case 1:
+                               vty_out(vty, "    Algorithm %d: Strict SPF\n",
+                                       i);
+                               break;
+                       default:
+                               vty_out(vty,
+                                       "  Algorithm %d: Unknown value %d\n", i,
+                                       algo->value[i]);
+                               break;
+                       }
+               }
+       }
+
+       else {
+               zlog_debug("  Segment Routing Algorithm TLV:\n");
+               for (i = 0; i < ntohs(algo->header.length); i++)
+                       switch (algo->value[i]) {
+                       case 0:
+                               zlog_debug("    Algorithm %d: SPF\n", i);
+                               break;
+                       case 1:
+                               zlog_debug("    Algorithm %d: Strict SPF\n", i);
+                               break;
+                       default:
+                               zlog_debug(
+                                       "    Algorithm %d: Unknown value %d\n",
+                                       i, algo->value[i]);
+                               break;
+                       }
+       }
+
+       return TLV_SIZE(tlvh);
+}
+
+/* Display Segment Routing SID/Label Range TLV information */
+static uint16_t show_vty_sr_range(struct vty *vty, struct tlv_header *tlvh)
+{
+       struct ri_sr_tlv_sid_label_range *range =
+               (struct ri_sr_tlv_sid_label_range *)tlvh;
+
+       if (vty != NULL) {
+               vty_out(vty,
+                       "  Segment Routing Range TLV:\n"
+                       "    Range Size = %d\n"
+                       "    SID Label = %d\n\n",
+                       GET_RANGE_SIZE(ntohl(range->size)),
+                       GET_LABEL(ntohl(range->lower.value)));
+       } else {
+               zlog_debug(
+                       "  Segment Routing Range TLV:\n"
+                       "    Range Size = %d\n"
+                       "    SID Label = %d\n\n",
+                       GET_RANGE_SIZE(ntohl(range->size)),
+                       GET_LABEL(ntohl(range->lower.value)));
+       }
+
+       return TLV_SIZE(tlvh);
+}
+
+/* Display Segment Routing Maximum Stack Depth TLV information */
+static uint16_t show_vty_sr_msd(struct vty *vty, struct tlv_header *tlvh)
+{
+       struct ri_sr_tlv_node_msd *msd = (struct ri_sr_tlv_node_msd *)tlvh;
+
+       if (vty != NULL) {
+               vty_out(vty,
+                       "  Segment Routing MSD TLV:\n"
+                       "    Node Maximum Stack Depth = %d\n",
+                       msd->value);
+       } else {
+               zlog_debug(
+                       "  Segment Routing MSD TLV:\n"
+                       "    Node Maximum Stack Depth = %d\n",
+                       msd->value);
+       }
+
+       return TLV_SIZE(tlvh);
+}
+
 static void ospf_router_info_show_info(struct vty *vty, struct ospf_lsa *lsa)
 {
        struct lsa_header *lsah = (struct lsa_header *)lsa->data;
@@ -1041,6 +1357,16 @@ static void ospf_router_info_show_info(struct vty *vty, struct ospf_lsa *lsa)
                        sum += TLV_HDR_SIZE;
                        sum += show_vty_pce_info(vty, tlvh, length - sum);
                        break;
+               case RI_SR_TLV_SR_ALGORITHM:
+                       sum += show_vty_sr_algorithm(vty, tlvh);
+                       break;
+               case RI_SR_TLV_SID_LABEL_RANGE:
+                       sum += show_vty_sr_range(vty, tlvh);
+                       break;
+               case RI_SR_TLV_NODE_MSD:
+                       sum += show_vty_sr_msd(vty, tlvh);
+                       break;
+
                default:
                        sum += show_vty_unknown_tlv(vty, tlvh);
                        break;
@@ -1058,53 +1384,54 @@ static void ospf_router_info_config_write_router(struct vty *vty)
        struct ri_pce_subtlv_neighbor *neighbor;
        struct in_addr tmp;
 
-       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 (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));
-                                       }
+       if (!OspfRI.enabled)
+               return;
+
+       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 (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;
 }
@@ -1195,9 +1522,6 @@ DEFUN (no_router_info,
        if (CHECK_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED))
                ospf_router_info_lsa_schedule(FLUSH_THIS_LSA);
 
-       /* Unregister the callbacks */
-       ospf_router_info_unregister();
-
        OspfRI.enabled = false;
 
        return CMD_SUCCESS;
@@ -1539,7 +1863,7 @@ DEFUN (show_ip_opsf_router_info_pce,
        struct ri_pce_subtlv_domain *domain;
        struct ri_pce_subtlv_neighbor *neighbor;
 
-       if (OspfRI.enabled) {
+       if ((OspfRI.enabled) && (OspfRI.pce_info.enabled)) {
                vty_out(vty, "--- PCE parameters ---\n");
 
                if (pce->pce_address.header.type != 0)
@@ -1568,7 +1892,7 @@ DEFUN (show_ip_opsf_router_info_pce,
 
        } else {
                vty_out(vty,
-                       "  Router Information is disabled on this router\n");
+                       "  PCE info is disabled on this router\n");
        }
 
        return CMD_SUCCESS;
index 2d90730d93ecfde5411de5c5283ddca990932a95..39ebb720092a18663be3eb883def263ff034fad3 100644 (file)
@@ -1,11 +1,13 @@
 /*
  * This is an implementation of RFC4970 Router Information
  * with support of RFC5088 PCE Capabilites announcement
+ * and support of draft-ietf-ospf-segment-routing-extensions-18
+ * for Segment Routing Capabilities announcement
+ *
  *
  * Module name: Router Information
- * Version:     0.99.22
- * Created:     2012-02-01 by Olivier Dugeon
- * Copyright (C) 2012 Orange Labs http://www.orange.com/
+ * Author: Olivier Dugeon <olivier.dugeon@orange.com>
+ * Copyright (C) 2012 - 2017 Orange Labs http://www.orange.com/
  *
  * This file is part of GNU Zebra.
  *
@@ -33,7 +35,7 @@
  *
  *        24       16        8        0
  * +--------+--------+--------+--------+
- * |    1   |  MBZ   |........|........|
+ * |    4   |  MBZ   |........|........|
  * +--------+--------+--------+--------+
  * |<-Type->|<Resv'd>|<-- Instance --->|
  *
@@ -57,9 +59,8 @@
  * +--------+--------+--------+--------+  |
  * |   LS checksum   |     Length      |  V
  * +--------+--------+--------+--------+ ---
- * |      Type       |     Length      |  A
- * +--------+--------+--------+--------+  |  TLV part for Router Information;
- * Values might be
+ * |      Type       |     Length      |  A  TLV part for Router Information;
+ * +--------+--------+--------+--------+  |  Values might be
  * |              Values ...           |  V  structured as a set of sub-TLVs.
  * +--------+--------+--------+--------+ ---
  */
@@ -68,9 +69,9 @@
  * Following section defines TLV body parts.
  */
 
-/* Up to now, 8 code point have been assigned to Router Information */
+/* Up to now, 11 code points have been assigned to Router Information */
 /* Only type 1 Router Capabilities and 6 PCE are supported with this code */
-#define RI_IANA_MAX_TYPE               8
+#define RI_IANA_MAX_TYPE               11
 
 /* RFC4970: Router Information Capabilities TLV */ /* Mandatory */
 #define RI_TLV_CAPABILITIES            1
@@ -80,12 +81,13 @@ struct ri_tlv_router_cap {
        u_int32_t value;
 };
 
-#define RI_GRACE_RESTART       0x01
-#define RI_GRACE_HELPER                0x02
-#define RI_STUB_SUPPORT                0x04
-#define RI_TE_SUPPORT          0x08
-#define RI_P2P_OVER_LAN                0x10
-#define RI_TE_EXPERIMENTAL     0x20
+/* Capabilities bits are left align */
+#define RI_GRACE_RESTART       0x80000000
+#define RI_GRACE_HELPER                0x40000000
+#define RI_STUB_SUPPORT                0x20000000
+#define RI_TE_SUPPORT          0x10000000
+#define RI_P2P_OVER_LAN                0x08000000
+#define RI_TE_EXPERIMENTAL     0x04000000
 
 #define RI_TLV_LENGTH          4
 
@@ -151,22 +153,32 @@ struct ri_pce_subtlv_neighbor {
 #define RI_PCE_SUBTLV_CAP_FLAG         5
 
 #define PCE_CAP_GMPLS_LINK             0x0001
-#define PCE_CAP_BIDIRECTIONAL  0x0002
-#define PCE_CAP_DIVERSE_PATH   0x0004
-#define PCE_CAP_LOAD_BALANCE   0x0008
-#define PCE_CAP_SYNCHRONIZED   0x0010
+#define PCE_CAP_BIDIRECTIONAL          0x0002
+#define PCE_CAP_DIVERSE_PATH           0x0004
+#define PCE_CAP_LOAD_BALANCE           0x0008
+#define PCE_CAP_SYNCHRONIZED           0x0010
 #define PCE_CAP_OBJECTIVES             0x0020
 #define PCE_CAP_ADDITIVE               0x0040
-#define PCE_CAP_PRIORIZATION   0x0080
-#define PCE_CAP_MULTIPLE_REQ   0x0100
+#define PCE_CAP_PRIORIZATION           0x0080
+#define PCE_CAP_MULTIPLE_REQ           0x0100
 
 struct ri_pce_subtlv_cap_flag {
        struct tlv_header header; /* Type = 5; Length = n x 4 bytes. */
        u_int32_t value;
 };
 
+/* Structure to share flooding scope info for Segment Routing */
+struct scope_info {
+       uint8_t scope;
+       struct in_addr area_id;
+};
+
 /* Prototypes. */
 extern int ospf_router_info_init(void);
 extern void ospf_router_info_term(void);
-
+extern void ospf_router_info_finish(void);
+extern int ospf_router_info_enable(void);
+extern void ospf_router_info_update_sr(bool enable, struct sr_srgb srgb,
+                                      uint8_t msd);
+extern struct scope_info ospf_router_info_get_flooding_scope(void);
 #endif /* _ZEBRA_OSPF_ROUTER_INFO_H */
index b7a47602d0b16037a5090ab49a8054235cf75f87..f2769c6f38e108ccf6a24e4c336c6334cff05804 100644 (file)
@@ -337,6 +337,7 @@ static struct route_map_rule_cmd route_match_tag_cmd = {
 };
 
 struct ospf_metric {
+       enum { metric_increment, metric_decrement, metric_absolute } type;
        bool used;
        u_int32_t metric;
 };
@@ -356,8 +357,19 @@ static route_map_result_t route_set_metric(void *rule, struct prefix *prefix,
                ei = object;
 
                /* Set metric out value. */
-               if (metric->used)
+               if (!metric->used)
+                       return RMAP_OKAY;
+               if (metric->type == metric_increment)
+                       ei->route_map_set.metric += metric->metric;
+               if (metric->type == metric_decrement)
+                       ei->route_map_set.metric -= metric->metric;
+               if (metric->type == metric_absolute)
                        ei->route_map_set.metric = metric->metric;
+
+               if ((signed int)ei->route_map_set.metric < 1)
+                       ei->route_map_set.metric = -1;
+               if (ei->route_map_set.metric > OSPF_LS_INFINITY)
+                       ei->route_map_set.metric = OSPF_LS_INFINITY;
        }
        return RMAP_OKAY;
 }
@@ -370,23 +382,28 @@ static void *route_set_metric_compile(const char *arg)
        metric = XCALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(u_int32_t));
        metric->used = false;
 
-       /* OSPF doesn't support the +/- in
-          set metric <+/-metric> check
-          Ignore the +/- component */
-       if (!all_digit(arg)) {
-               if ((arg[0] == '+' || arg[0] == '-') && all_digit(arg + 1)) {
-                       zlog_warn("OSPF does not support 'set metric +/-'");
-                       arg++;
-               } else {
-                       if (strmatch(arg, "+rtt") || strmatch(arg, "-rtt"))
-                               zlog_warn(
-                                       "OSPF does not support 'set metric +rtt / -rtt'");
-
-                       return metric;
-               }
+       if (all_digit(arg))
+               metric->type = metric_absolute;
+
+       if (strmatch(arg, "+rtt") || strmatch(arg, "-rtt")) {
+               zlog_warn("OSPF does not support 'set metric +rtt / -rtt'");
+               return metric;
+       }
+
+       if ((arg[0] == '+') && all_digit(arg + 1)) {
+               metric->type = metric_increment;
+               arg++;
        }
+
+       if ((arg[0] == '-') && all_digit(arg + 1)) {
+               metric->type = metric_decrement;
+               arg++;
+       }
+
        metric->metric = strtoul(arg, NULL, 10);
-       metric->used = true;
+
+       if (metric->metric)
+               metric->used = true;
 
        return metric;
 }
index 36ae091f99ecdd527a8e4c8cc687f66e21bd205c..b28aebb81f5cfb99e5cb59f43393b598f3e1873b 100644 (file)
@@ -2589,8 +2589,9 @@ static void ospfTrapNbrStateChange(struct ospf_neighbor *on)
        char msgbuf[16];
 
        ospf_nbr_state_message(on, msgbuf, sizeof(msgbuf));
-       zlog_info("ospfTrapNbrStateChange trap sent: %s now %s",
-                 inet_ntoa(on->address.u.prefix4), msgbuf);
+       if (IS_DEBUG_OSPF_EVENT)
+               zlog_info("%s: trap sent: %s now %s", __PRETTY_FUNCTION__,
+                         inet_ntoa(on->address.u.prefix4), msgbuf);
 
        oid_copy_addr(index, &(on->address.u.prefix4), IN_ADDR_SIZE);
        index[IN_ADDR_SIZE] = 0;
@@ -2646,9 +2647,10 @@ static void ospfTrapIfStateChange(struct ospf_interface *oi)
 {
        oid index[sizeof(oid) * (IN_ADDR_SIZE + 1)];
 
-       zlog_info("ospfTrapIfStateChange trap sent: %s now %s",
-                 inet_ntoa(oi->address->u.prefix4),
-                 lookup_msg(ospf_ism_state_msg, oi->state, NULL));
+       if (IS_DEBUG_OSPF_EVENT)
+               zlog_info("%s: trap sent: %s now %s", __PRETTY_FUNCTION__,
+                         inet_ntoa(oi->address->u.prefix4),
+                         lookup_msg(ospf_ism_state_msg, oi->state, NULL));
 
        oid_copy_addr(index, &(oi->address->u.prefix4), IN_ADDR_SIZE);
        index[IN_ADDR_SIZE] = 0;
index 65437dba9e38dd3f70f7e86f0ff49c795e2ade82..9c747cd56562fad1e226da6758c12d5137e59299 100644 (file)
@@ -46,6 +46,7 @@
 #include "ospfd/ospf_ase.h"
 #include "ospfd/ospf_abr.h"
 #include "ospfd/ospf_dump.h"
+#include "ospfd/ospf_sr.h"
 
 /* Variables to ensure a SPF scheduled log message is printed only once */
 
@@ -1339,7 +1340,6 @@ static int ospf_spf_calculate_timer(struct thread *thread)
 
        ospf_ase_calculate_timer_add(ospf);
 
-
        if (IS_DEBUG_OSPF_EVENT)
                zlog_debug("%s: ospf install new route, vrf %s id %u new_table count %lu",
                           __PRETTY_FUNCTION__,
@@ -1366,6 +1366,9 @@ static int ospf_spf_calculate_timer(struct thread *thread)
                ospf_abr_task(ospf);
        abr_time = monotime_since(&start_time, NULL);
 
+       /* Schedule Segment Routing update */
+       ospf_sr_update_timer_add(ospf);
+
        total_spf_time =
                monotime_since(&spf_start_time, &ospf->ts_spf_duration);
 
@@ -1463,9 +1466,7 @@ void ospf_spf_calculate_schedule(struct ospf *ospf, ospf_spf_reason_t reason)
        }
 
        if (IS_DEBUG_OSPF_EVENT)
-               zlog_debug("SPF: calculation timer delay = %ld", delay);
-
-       zlog_info("SPF: Scheduled in %ld msec", delay);
+               zlog_debug("SPF: calculation timer delay = %ld msec", delay);
 
        ospf->t_spf_calc = NULL;
        thread_add_timer_msec(master, ospf_spf_calculate_timer, ospf, delay,
diff --git a/ospfd/ospf_sr.c b/ospfd/ospf_sr.c
new file mode 100644 (file)
index 0000000..9827eac
--- /dev/null
@@ -0,0 +1,2273 @@
+/*
+ * This is an implementation of Segment Routing
+ * as per draft draft-ietf-ospf-segment-routing-extensions-24
+ *
+ * Module name: Segment Routing
+ *
+ * Author: Olivier Dugeon <olivier.dugeon@orange.com>
+ * Author: Anselme Sawadogo <anselmesawadogo@gmail.com>
+ *
+ * Copyright (C) 2016 - 2018 Orange Labs http://www.orange.com
+ *
+ * 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 <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <zebra.h>
+
+#include "command.h"
+#include "hash.h"
+#include "if.h"
+#include "if.h"
+#include "jhash.h"
+#include "libospf.h" /* for ospf interface types */
+#include "linklist.h"
+#include "log.h"
+#include "memory.h"
+#include "monotime.h"
+#include "network.h"
+#include "prefix.h"
+#include "sockunion.h" /* for inet_aton() */
+#include "stream.h"
+#include "table.h"
+#include "thread.h"
+#include "vty.h"
+#include "zclient.h"
+
+#include "ospfd/ospfd.h"
+#include "ospfd/ospf_interface.h"
+#include "ospfd/ospf_ism.h"
+#include "ospfd/ospf_asbr.h"
+#include "ospfd/ospf_lsa.h"
+#include "ospfd/ospf_lsdb.h"
+#include "ospfd/ospf_neighbor.h"
+#include "ospfd/ospf_nsm.h"
+#include "ospfd/ospf_flood.h"
+#include "ospfd/ospf_packet.h"
+#include "ospfd/ospf_spf.h"
+#include "ospfd/ospf_dump.h"
+#include "ospfd/ospf_route.h"
+#include "ospfd/ospf_ase.h"
+#include "ospfd/ospf_sr.h"
+#include "ospfd/ospf_ri.h"
+#include "ospfd/ospf_ext.h"
+#include "ospfd/ospf_zebra.h"
+
+/*
+ * Global variable to manage Segment Routing on this node.
+ * Note that all parameter values are stored in network byte order.
+ */
+static struct ospf_sr_db OspfSR;
+static void ospf_sr_register_vty(void);
+static inline void del_sid_nhlfe(struct sr_nhlfe nhlfe);
+
+/*
+ * Segment Routing Data Base functions
+ */
+
+/* Hash function for Segment Routing entry */
+static unsigned int sr_hash(void *p)
+{
+       const struct in_addr *rid = p;
+
+       return jhash_1word(rid->s_addr, 0);
+}
+
+/* Compare 2 Router ID hash entries based on SR Node */
+static int sr_cmp(const void *p1, const void *p2)
+{
+       const struct sr_node *srn = p1;
+       const struct in_addr *rid = p2;
+
+       return IPV4_ADDR_SAME(&srn->adv_router, rid);
+}
+
+/* Functions to remove an SR Link */
+static void del_sr_link(void *val)
+{
+       struct sr_link *srl = (struct sr_link *)val;
+
+       del_sid_nhlfe(srl->nhlfe[0]);
+       del_sid_nhlfe(srl->nhlfe[1]);
+       XFREE(MTYPE_OSPF_SR_PARAMS, val);
+
+}
+
+/* Functions to remove an SR Prefix */
+static void del_sr_pref(void *val)
+{
+       struct sr_prefix *srp = (struct sr_prefix *)val;
+
+       del_sid_nhlfe(srp->nhlfe);
+       XFREE(MTYPE_OSPF_SR_PARAMS, val);
+
+}
+
+/* Allocate new Segment Routine node */
+static struct sr_node *sr_node_new(struct in_addr *rid)
+{
+
+       if (rid == NULL)
+               return NULL;
+
+       struct sr_node *new;
+
+       /* Allocate Segment Routing node memory */
+       new = XCALLOC(MTYPE_OSPF_SR_PARAMS, sizeof(struct sr_node));
+
+       /* Sanity Check */
+       if (new == NULL) {
+               zlog_err("SR (%s): Abort! can't create new SR node", __func__);
+               return NULL;
+       }
+
+       /* Default Algorithm, SRGB and MSD */
+       for (int i = 0; i < ALGORITHM_COUNT; i++)
+               new->algo[i] = SR_ALGORITHM_UNSET;
+
+       new->srgb.range_size = 0;
+       new->srgb.lower_bound = 0;
+       new->msd = 0;
+
+       /* Create Link, Prefix and Range TLVs list */
+       new->ext_link = list_new();
+       new->ext_prefix = list_new();
+       new->ext_link->del = del_sr_link;
+       new->ext_prefix->del = del_sr_pref;
+
+       IPV4_ADDR_COPY(&new->adv_router, rid);
+       new->neighbor = NULL;
+       new->instance = 0;
+
+       if (IS_DEBUG_OSPF_SR)
+               zlog_debug("  |-  Created new SR node for %s",
+                          inet_ntoa(new->adv_router));
+       return new;
+}
+
+/* Delete Segment Routing node */
+static void sr_node_del(struct sr_node *srn)
+{
+       /* Sanity Check */
+       if (srn == NULL)
+               return;
+
+       /* Clean Extended Link */
+       list_delete_and_null(&srn->ext_link);
+
+       /* Clean Prefix List */
+       list_delete_and_null(&srn->ext_prefix);
+
+       XFREE(MTYPE_OSPF_SR_PARAMS, srn);
+}
+
+/* Get SR Node for a given nexthop */
+static struct sr_node *get_sr_node_by_nexthop(struct ospf *ospf,
+                                             struct in_addr nexthop)
+{
+       struct ospf_interface *oi = NULL;
+       struct ospf_neighbor *nbr = NULL;
+       struct listnode *node;
+       struct route_node *rn;
+       struct sr_node *srn;
+       bool found;
+
+       /* Sanity check */
+       if (OspfSR.neighbors == NULL)
+               return NULL;
+
+       if (IS_DEBUG_OSPF_SR)
+               zlog_debug("      |-  Search SR-Node for nexthop %s",
+                          inet_ntoa(nexthop));
+
+       /* First, search neighbor Router ID for this nexthop */
+       found = false;
+       for (ALL_LIST_ELEMENTS_RO(ospf->oiflist, node, oi)) {
+               for (rn = route_top(oi->nbrs); rn; rn = route_next(rn)) {
+                       nbr = rn->info;
+                       if ((nbr) && (IPV4_ADDR_SAME(&nexthop, &nbr->src))) {
+                               found = true;
+                               break;
+                       }
+               }
+               if (found)
+                       break;
+       }
+
+       if (!found)
+               return NULL;
+
+       if (IS_DEBUG_OSPF_SR)
+               zlog_debug("      |-  Found nexthop Router ID %s",
+                          inet_ntoa(nbr->router_id));
+       /* Then, search SR Node */
+       srn = (struct sr_node *)hash_lookup(OspfSR.neighbors, &nbr->router_id);
+
+       return srn;
+}
+
+/*
+ * Segment Routing Initialization functions
+ */
+
+/* Segment Routing starter function */
+static int ospf_sr_start(struct ospf *ospf)
+{
+       struct route_node *rn;
+       struct ospf_lsa *lsa;
+       struct sr_node *srn;
+       int rc = 0;
+
+       if (IS_DEBUG_OSPF_SR)
+               zlog_debug("SR (%s): Start Segment Routing", __func__);
+
+       /* Initialize self SR Node */
+       srn = hash_get(OspfSR.neighbors, (void *)&(ospf->router_id),
+                      (void *)sr_node_new);
+
+       /* Sanity Check */
+       if (srn == NULL)
+               return rc;
+
+       /* Complete & Store self SR Node */
+       srn->srgb.range_size = OspfSR.srgb.range_size;
+       srn->srgb.lower_bound = OspfSR.srgb.lower_bound;
+       srn->algo[0] = OspfSR.algo[0];
+       srn->msd = OspfSR.msd;
+       OspfSR.self = srn;
+
+       if (IS_DEBUG_OSPF_EVENT)
+               zlog_debug("SR (%s): Update SR-DB from LSDB", __func__);
+
+       /* Start by looking to Router Info & Extended LSA in lsdb */
+       if ((ospf != NULL) && (ospf->backbone != NULL)) {
+               LSDB_LOOP(OPAQUE_AREA_LSDB(ospf->backbone), rn, lsa)
+               {
+                       if (IS_LSA_MAXAGE(lsa) || IS_LSA_SELF(lsa))
+                               continue;
+                       int lsa_id =
+                               GET_OPAQUE_TYPE(ntohl(lsa->data->id.s_addr));
+                       switch (lsa_id) {
+                       case OPAQUE_TYPE_ROUTER_INFORMATION_LSA:
+                               ospf_sr_ri_lsa_update(lsa);
+                               break;
+                       case OPAQUE_TYPE_EXTENDED_PREFIX_LSA:
+                               ospf_sr_ext_prefix_lsa_update(lsa);
+                               break;
+                       case OPAQUE_TYPE_EXTENDED_LINK_LSA:
+                               ospf_sr_ext_link_lsa_update(lsa);
+                               break;
+                       default:
+                               break;
+                       }
+               }
+       }
+
+       rc = 1;
+       return rc;
+}
+
+/* Stop Segment Routing */
+static void ospf_sr_stop(void)
+{
+
+       if (IS_DEBUG_OSPF_SR)
+               zlog_debug("SR (%s): Stop Segment Routing", __func__);
+
+       /*
+        * Remove all SR Nodes from the Hash table. Prefix and Link SID will
+        * be remove though list_delete_and_null() call. See sr_node_del()
+        */
+       hash_clean(OspfSR.neighbors, (void *)sr_node_del);
+}
+
+/*
+ * Segment Routing initialize function
+ *
+ * @param - nothing
+ *
+ * @return 0 if OK, -1 otherwise
+ */
+int ospf_sr_init(void)
+{
+       int rc = -1;
+
+       zlog_info("SR (%s): Initialize SR Data Base", __func__);
+
+       memset(&OspfSR, 0, sizeof(struct ospf_sr_db));
+       OspfSR.enabled = false;
+       /* Only AREA flooding is supported in this release */
+       OspfSR.scope = OSPF_OPAQUE_AREA_LSA;
+
+       /* Initialize SRGB, Algorithms and MSD TLVs */
+       /* Only Algorithm SPF is supported */
+       OspfSR.algo[0] = SR_ALGORITHM_SPF;
+       for (int i = 1; i < ALGORITHM_COUNT; i++)
+               OspfSR.algo[i] = SR_ALGORITHM_UNSET;
+
+       OspfSR.srgb.range_size = MPLS_DEFAULT_MAX_SRGB_SIZE;
+       OspfSR.srgb.lower_bound = MPLS_DEFAULT_MIN_SRGB_LABEL;
+       OspfSR.msd = 0;
+
+       /* Initialize Hash table for neighbor SR nodes */
+       OspfSR.neighbors = hash_create(sr_hash, sr_cmp, "OSPF_SR");
+       if (OspfSR.neighbors == NULL)
+               return rc;
+
+       /* Initialize Route Table for prefix */
+       OspfSR.prefix = route_table_init();
+       if (OspfSR.prefix == NULL)
+               return rc;
+
+       /* Register Segment Routing VTY command */
+       ospf_sr_register_vty();
+
+       rc = 0;
+       return rc;
+}
+
+/*
+ * Segment Routing termination function
+ *
+ * @param - nothing
+ * @return - nothing
+ */
+void ospf_sr_term(void)
+{
+
+       /* Stop Segment Routing */
+       ospf_sr_stop();
+
+       /* Clear SR Node Table */
+       if (OspfSR.neighbors)
+               hash_free(OspfSR.neighbors);
+
+       /* Clear Prefix Table */
+       if (OspfSR.prefix)
+               route_table_finish(OspfSR.prefix);
+
+       OspfSR.enabled = false;
+       OspfSR.self = NULL;
+}
+
+/*
+ * Segment Routing finish function
+ *
+ * @param - nothing
+ * @return - nothing
+ */
+void ospf_sr_finish(void)
+{
+       /* Stop Segment Routing */
+       ospf_sr_stop();
+
+       OspfSR.enabled = false;
+}
+
+/*
+ * Following functions are used to manipulate the
+ * Next Hop Label Forwarding entry (NHLFE)
+ */
+
+/* Compute label from index */
+static mpls_label_t index2label(uint32_t index, struct sr_srgb srgb)
+{
+       mpls_label_t label;
+
+       label = srgb.lower_bound + index;
+       if (label > (srgb.lower_bound + srgb.range_size))
+               return MPLS_INVALID_LABEL;
+       else
+               return label;
+}
+
+/* Get neighbor full structure from address */
+static struct ospf_neighbor *get_neighbor_by_addr(struct ospf *top,
+                                                 struct in_addr addr)
+{
+       struct ospf_neighbor *nbr;
+       struct ospf_interface *oi;
+       struct listnode *node;
+       struct route_node *rn;
+
+       /* Sanity Check */
+       if (top == NULL)
+               return NULL;
+
+       for (ALL_LIST_ELEMENTS_RO(top->oiflist, node, oi))
+               for (rn = route_top(oi->nbrs); rn; rn = route_next(rn)) {
+                       nbr = rn->info;
+                       if (nbr)
+                               if (IPV4_ADDR_SAME(&nbr->address.u.prefix4,
+                                                  &addr)
+                                   || IPV4_ADDR_SAME(&nbr->router_id, &addr)) {
+                                       route_unlock_node(rn);
+                                       return nbr;
+                               }
+               }
+       return NULL;
+}
+
+/* Get OSPF Path from address */
+static struct ospf_path *get_nexthop_by_addr(struct ospf *top,
+                                            struct prefix_ipv4 p)
+{
+       struct ospf_route *or;
+       struct ospf_path *path;
+       struct listnode *node;
+       struct route_node *rn;
+
+       /* Sanity Check */
+       if (top == NULL)
+               return NULL;
+
+       if (IS_DEBUG_OSPF_SR)
+               zlog_debug("      |-  Search Nexthop for prefix %s/%u",
+                          inet_ntoa(p.prefix), p.prefixlen);
+
+       rn = route_node_lookup(top->new_table, (struct prefix *)&p);
+
+       /*
+        * Check if we found an OSPF route. May be NULL if SPF has not
+        * yet populate routing table for this prefix.
+        */
+       if (rn == NULL)
+               return NULL;
+
+       route_unlock_node(rn);
+       or = rn->info;
+       if (or == NULL)
+               return NULL;
+
+       /* Then search path from this route */
+       for (ALL_LIST_ELEMENTS_RO(or->paths, node, path))
+               if (path->nexthop.s_addr != INADDR_ANY || path->ifindex != 0)
+                       return path;
+
+       return NULL;
+}
+
+/* Compute NHLFE entry for Extended Link */
+static int compute_link_nhlfe(struct sr_link *srl)
+{
+       struct ospf *top = ospf_lookup_by_vrf_id(VRF_DEFAULT);
+       struct ospf_neighbor *nh;
+       int rc = 0;
+
+       if (IS_DEBUG_OSPF_SR)
+               zlog_debug("    |-  Compute NHLFE for link %s/%u",
+                          inet_ntoa(srl->nhlfe[0].prefv4.prefix),
+                          srl->nhlfe[0].prefv4.prefixlen);
+
+       /* First determine the OSPF Neighbor */
+       nh = get_neighbor_by_addr(top, srl->nhlfe[0].nexthop);
+
+       /* Neighbor could be not found when OSPF Adjacency just fire up
+        * because SPF don't yet populate routing table. This NHLFE will
+        * be fixed later when SR SPF schedule will be called.
+        */
+       if (nh == NULL)
+               return rc;
+
+       if (IS_DEBUG_OSPF_SR)
+               zlog_debug("    |-  Found nexthop NHLFE %s",
+                          inet_ntoa(nh->router_id));
+
+       /* Set ifindex for this neighbor */
+       srl->nhlfe[0].ifindex = nh->oi->ifp->ifindex;
+       srl->nhlfe[1].ifindex = nh->oi->ifp->ifindex;
+
+       /* Set Input & Output Label */
+       if (CHECK_FLAG(srl->flags[0], EXT_SUBTLV_LINK_ADJ_SID_VFLG))
+               srl->nhlfe[0].label_in = srl->sid[0];
+       else
+               srl->nhlfe[0].label_in =
+                       index2label(srl->sid[0], srl->srn->srgb);
+       if (CHECK_FLAG(srl->flags[1], EXT_SUBTLV_LINK_ADJ_SID_VFLG))
+               srl->nhlfe[1].label_in = srl->sid[1];
+       else
+               srl->nhlfe[1].label_in =
+                       index2label(srl->sid[1], srl->srn->srgb);
+
+       srl->nhlfe[0].label_out = MPLS_LABEL_IMPLICIT_NULL;
+       srl->nhlfe[1].label_out = MPLS_LABEL_IMPLICIT_NULL;
+
+       rc = 1;
+       return rc;
+}
+
+/*
+ * Compute NHLFE entry for Extended Prefix
+ *
+ * @param srp - Segment Routing Prefix
+ *
+ * @return -1 if next hop is not found, 0 if nexthop has not changed
+ *         and 1 if success
+ */
+static int compute_prefix_nhlfe(struct sr_prefix *srp)
+{
+       struct ospf *top = ospf_lookup_by_vrf_id(VRF_DEFAULT);
+       struct ospf_path *nh = NULL;
+       struct sr_node *srnext;
+       int rc = -1;
+
+       if (IS_DEBUG_OSPF_SR)
+               zlog_debug("    |-  Compute NHLFE for prefix %s/%u",
+                          inet_ntoa(srp->nhlfe.prefv4.prefix),
+                          srp->nhlfe.prefv4.prefixlen);
+
+       /* First determine the nexthop */
+       nh = get_nexthop_by_addr(top, srp->nhlfe.prefv4);
+
+       /* Nexthop could be not found when OSPF Adjacency just fire up
+        * because SPF don't yet populate routing table. This NHLFE will
+        * be fixed later when SR SPF schedule will be called.
+        */
+       if (nh == NULL)
+               return rc;
+
+       /* Check if NextHop has changed when call after running a new SPF */
+       if (IPV4_ADDR_SAME(&nh->nexthop, &srp->nhlfe.nexthop)
+           && (nh->ifindex == srp->nhlfe.ifindex))
+               return 0;
+
+       if (IS_DEBUG_OSPF_SR)
+               zlog_debug("    |-  Found new next hop for this NHLFE: %s",
+                          inet_ntoa(nh->nexthop));
+
+       /*
+        * Get SR-Node for this nexthop. Could be not yet available
+        * as Extende Link / Prefix and Router Information are flooded
+        * after LSA Type 1 & 2 which populate the OSPF Route Table
+        */
+       srnext = get_sr_node_by_nexthop(top, nh->nexthop);
+       if (srnext == NULL)
+               return rc;
+
+       /* And store this information for later update if SR Node is found */
+       srnext->neighbor = OspfSR.self;
+       if (IPV4_ADDR_SAME(&srnext->adv_router, &srp->adv_router))
+               srp->nexthop = NULL;
+       else
+               srp->nexthop = srnext;
+
+       /*
+        * SR Node could be known, but SRGB could be not initialize
+        * This is due to the fact that Extended Link / Prefix could
+        * be received before corresponding Router Information LSA
+        */
+       if ((srnext == NULL) || (srnext->srgb.lower_bound == 0)
+           || (srnext->srgb.range_size == 0))
+               return rc;
+
+       if (IS_DEBUG_OSPF_SR)
+               zlog_debug("    |-  Found SRGB %u/%u for next hop SR-Node %s",
+                          srnext->srgb.range_size, srnext->srgb.lower_bound,
+                          inet_ntoa(srnext->adv_router));
+
+       /* Set ip addr & ifindex for this neighbor */
+       IPV4_ADDR_COPY(&srp->nhlfe.nexthop, &nh->nexthop);
+       srp->nhlfe.ifindex = nh->ifindex;
+
+       /* Compute Input Label with self SRGB */
+       srp->nhlfe.label_in = index2label(srp->sid, OspfSR.srgb);
+       /*
+        * and Output Label with Next hop SR Node SRGB or Implicit Null label
+        * if next hop is the destination and request PHP
+        */
+       if ((srp->nexthop == NULL)
+           && (!CHECK_FLAG(srp->flags, EXT_SUBTLV_PREFIX_SID_NPFLG)))
+               srp->nhlfe.label_out = MPLS_LABEL_IMPLICIT_NULL;
+       else if (CHECK_FLAG(srp->flags, EXT_SUBTLV_PREFIX_SID_VFLG))
+               srp->nhlfe.label_out = srp->sid;
+       else
+               srp->nhlfe.label_out = index2label(srp->sid, srnext->srgb);
+
+       if (IS_DEBUG_OSPF_SR)
+               zlog_debug("    |-  Computed new labels in: %u out: %u",
+                          srp->nhlfe.label_in, srp->nhlfe.label_out);
+
+       rc = 1;
+       return rc;
+}
+
+/* Send MPLS Label entry to Zebra for installation or deletion */
+static int ospf_zebra_send_mpls_labels(int cmd, struct sr_nhlfe nhlfe)
+{
+       struct stream *s;
+
+       /* Reset stream. */
+       s = zclient->obuf;
+       stream_reset(s);
+
+       zclient_create_header(s, cmd, VRF_DEFAULT);
+       stream_putc(s, ZEBRA_LSP_SR);
+       /* OSPF Segment Routing currently support only IPv4 */
+       stream_putl(s, nhlfe.prefv4.family);
+       stream_put_in_addr(s, &nhlfe.prefv4.prefix);
+       stream_putc(s, nhlfe.prefv4.prefixlen);
+       stream_put_in_addr(s, &nhlfe.nexthop);
+       stream_putl(s, nhlfe.ifindex);
+       stream_putc(s, OSPF_SR_PRIORITY_DEFAULT);
+       stream_putl(s, nhlfe.label_in);
+       stream_putl(s, nhlfe.label_out);
+
+       /* Put length at the first point of the stream. */
+       stream_putw_at(s, 0, stream_get_endp(s));
+
+       if (IS_DEBUG_OSPF_SR)
+               zlog_debug("    |-  %s LSP %u/%u for %s/%u via %u",
+                          cmd == ZEBRA_MPLS_LABELS_ADD ? "Add" : "Delete",
+                          nhlfe.label_in, nhlfe.label_out,
+                          inet_ntoa(nhlfe.prefv4.prefix),
+                          nhlfe.prefv4.prefixlen, nhlfe.ifindex);
+
+       return zclient_send_message(zclient);
+}
+
+/* Request zebra to install/remove FEC in FIB */
+static int ospf_zebra_send_mpls_ftn(int cmd, struct sr_nhlfe nhlfe)
+{
+       struct zapi_route api;
+       struct zapi_nexthop *api_nh;
+
+       /* Support only IPv4 */
+       if (nhlfe.prefv4.family != AF_INET)
+               return -1;
+
+       memset(&api, 0, sizeof(api));
+       api.vrf_id = VRF_DEFAULT;
+       api.type = ZEBRA_ROUTE_OSPF;
+       api.safi = SAFI_UNICAST;
+       memcpy(&api.prefix, &nhlfe.prefv4, sizeof(struct prefix_ipv4));
+
+       if (cmd == ZEBRA_ROUTE_ADD) {
+               /* Metric value. */
+               SET_FLAG(api.message, ZAPI_MESSAGE_METRIC);
+               api.metric = OSPF_SR_DEFAULT_METRIC;
+               /* Nexthop */
+               SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP);
+               api_nh = &api.nexthops[0];
+               IPV4_ADDR_COPY(&api_nh->gate.ipv4, &nhlfe.nexthop);
+               api_nh->type = NEXTHOP_TYPE_IPV4_IFINDEX;
+               api_nh->ifindex = nhlfe.ifindex;
+               /* MPLS labels */
+               SET_FLAG(api.message, ZAPI_MESSAGE_LABEL);
+               api_nh->labels[0] = nhlfe.label_out;
+               api_nh->label_num = 1;
+               api.nexthop_num = 1;
+       }
+
+       if (IS_DEBUG_OSPF_SR)
+               zlog_debug("    |-  %s FEC %u for %s/%u via %u",
+                          cmd == ZEBRA_ROUTE_ADD ? "Add" : "Delete",
+                          nhlfe.label_out, inet_ntoa(nhlfe.prefv4.prefix),
+                          nhlfe.prefv4.prefixlen, nhlfe.ifindex);
+
+       return zclient_route_send(cmd, zclient, &api);
+}
+
+/* Add new NHLFE entry for SID */
+static inline void add_sid_nhlfe(struct sr_nhlfe nhlfe)
+{
+       if ((nhlfe.label_in != 0) && (nhlfe.label_out != 0)) {
+               ospf_zebra_send_mpls_labels(ZEBRA_MPLS_LABELS_ADD, nhlfe);
+               if (nhlfe.label_out != MPLS_LABEL_IMPLICIT_NULL)
+                       ospf_zebra_send_mpls_ftn(ZEBRA_ROUTE_ADD, nhlfe);
+       }
+}
+
+/* Remove NHLFE entry for SID */
+static inline void del_sid_nhlfe(struct sr_nhlfe nhlfe)
+{
+       if ((nhlfe.label_in != 0) && (nhlfe.label_out != 0)) {
+               ospf_zebra_send_mpls_labels(ZEBRA_MPLS_LABELS_DELETE, nhlfe);
+               if (nhlfe.label_out != MPLS_LABEL_IMPLICIT_NULL)
+                       ospf_zebra_send_mpls_ftn(ZEBRA_ROUTE_DELETE, nhlfe);
+       }
+}
+
+/* Update NHLFE entry for SID */
+static inline void update_sid_nhlfe(struct sr_nhlfe n1, struct sr_nhlfe n2)
+{
+
+       del_sid_nhlfe(n1);
+       add_sid_nhlfe(n2);
+}
+
+/*
+ * Functions to parse and get Extended Link / Prefix
+ * TLVs and SubTLVs
+ */
+
+/* Extended Link SubTLVs Getter */
+static struct sr_link *get_ext_link_sid(struct tlv_header *tlvh)
+{
+
+       struct sr_link *srl;
+       struct ext_tlv_link *link = (struct ext_tlv_link *)tlvh;
+       struct ext_subtlv_adj_sid *adj_sid;
+       struct ext_subtlv_lan_adj_sid *lan_sid;
+       struct ext_subtlv_rmt_itf_addr *rmt_itf;
+
+       struct tlv_header *sub_tlvh;
+       uint16_t length = 0, sum = 0, i = 0;
+
+       srl = XCALLOC(MTYPE_OSPF_SR_PARAMS, sizeof(struct sr_link));
+
+       if (srl == NULL)
+               return NULL;
+
+       /* Initialize TLV browsing */
+       length = ntohs(tlvh->length) - EXT_TLV_LINK_SIZE;
+       sub_tlvh = (struct tlv_header *)((char *)(tlvh) + TLV_HDR_SIZE
+                                        + EXT_TLV_LINK_SIZE);
+       for (; sum < length; sub_tlvh = TLV_HDR_NEXT(sub_tlvh)) {
+               switch (ntohs(sub_tlvh->type)) {
+               case EXT_SUBTLV_ADJ_SID:
+                       adj_sid = (struct ext_subtlv_adj_sid *)sub_tlvh;
+                       srl->type = ADJ_SID;
+                       i = CHECK_FLAG(adj_sid->flags,
+                                      EXT_SUBTLV_LINK_ADJ_SID_BFLG)
+                                   ? 1
+                                   : 0;
+                       srl->flags[i] = adj_sid->flags;
+                       if (CHECK_FLAG(adj_sid->flags,
+                                      EXT_SUBTLV_LINK_ADJ_SID_VFLG))
+                               srl->sid[i] = GET_LABEL(ntohl(adj_sid->value));
+                       else
+                               srl->sid[i] = ntohl(adj_sid->value);
+                       IPV4_ADDR_COPY(&srl->nhlfe[i].nexthop, &link->link_id);
+                       break;
+               case EXT_SUBTLV_LAN_ADJ_SID:
+                       lan_sid = (struct ext_subtlv_lan_adj_sid *)sub_tlvh;
+                       srl->type = LAN_ADJ_SID;
+                       i = CHECK_FLAG(lan_sid->flags,
+                                      EXT_SUBTLV_LINK_ADJ_SID_BFLG)
+                                   ? 1
+                                   : 0;
+                       srl->flags[i] = lan_sid->flags;
+                       if (CHECK_FLAG(lan_sid->flags,
+                                      EXT_SUBTLV_LINK_ADJ_SID_VFLG))
+                               srl->sid[i] = GET_LABEL(ntohl(lan_sid->value));
+                       else
+                               srl->sid[i] = ntohl(lan_sid->value);
+                       IPV4_ADDR_COPY(&srl->nhlfe[i].nexthop,
+                                      &lan_sid->neighbor_id);
+                       break;
+               case EXT_SUBTLV_RMT_ITF_ADDR:
+                       rmt_itf = (struct ext_subtlv_rmt_itf_addr *)sub_tlvh;
+                       IPV4_ADDR_COPY(&srl->nhlfe[0].nexthop, &rmt_itf->value);
+                       IPV4_ADDR_COPY(&srl->nhlfe[1].nexthop, &rmt_itf->value);
+                       break;
+               default:
+                       break;
+               }
+               sum += TLV_SIZE(sub_tlvh);
+       }
+
+       IPV4_ADDR_COPY(&srl->nhlfe[0].prefv4.prefix, &link->link_data);
+       srl->nhlfe[0].prefv4.prefixlen = IPV4_MAX_PREFIXLEN;
+       srl->nhlfe[0].prefv4.family = AF_INET;
+       apply_mask_ipv4(&srl->nhlfe[0].prefv4);
+       IPV4_ADDR_COPY(&srl->nhlfe[1].prefv4.prefix, &link->link_data);
+       srl->nhlfe[1].prefv4.prefixlen = IPV4_MAX_PREFIXLEN;
+       srl->nhlfe[1].prefv4.family = AF_INET;
+       apply_mask_ipv4(&srl->nhlfe[1].prefv4);
+
+       if (IS_DEBUG_OSPF_SR) {
+               zlog_debug("  |-  Found primary Adj/Lan Sid %u for %s/%u",
+                          srl->sid[0], inet_ntoa(srl->nhlfe[0].prefv4.prefix),
+                          srl->nhlfe[0].prefv4.prefixlen);
+               zlog_debug("  |-  Found backup Adj/Lan Sid %u for %s/%u",
+                          srl->sid[1], inet_ntoa(srl->nhlfe[1].prefv4.prefix),
+                          srl->nhlfe[1].prefv4.prefixlen);
+       }
+
+       return srl;
+}
+
+/* Extended Prefix SubTLVs Getter */
+static struct sr_prefix *get_ext_prefix_sid(struct tlv_header *tlvh)
+{
+
+       struct sr_prefix *srp;
+       struct ext_tlv_prefix *pref = (struct ext_tlv_prefix *)tlvh;
+       struct ext_subtlv_prefix_sid *psid;
+
+       struct tlv_header *sub_tlvh;
+       uint16_t length = 0, sum = 0;
+
+       srp = XCALLOC(MTYPE_OSPF_SR_PARAMS, sizeof(struct sr_prefix));
+
+       if (srp == NULL)
+               return NULL;
+
+       /* Initialize TLV browsing */
+       length = ntohs(tlvh->length) - EXT_TLV_PREFIX_SIZE;
+       sub_tlvh = (struct tlv_header *)((char *)(tlvh) + TLV_HDR_SIZE
+                                        + EXT_TLV_PREFIX_SIZE);
+       for (; sum < length; sub_tlvh = TLV_HDR_NEXT(sub_tlvh)) {
+               switch (ntohs(sub_tlvh->type)) {
+               case EXT_SUBTLV_PREFIX_SID:
+                       psid = (struct ext_subtlv_prefix_sid *)sub_tlvh;
+                       if (psid->algorithm != SR_ALGORITHM_SPF) {
+                               zlog_err(
+                                       "SR (%s): Unsupported Algorithm",
+                                       __func__);
+                               XFREE(MTYPE_OSPF_SR_PARAMS, srp);
+                               return NULL;
+                       }
+                       srp->type = PREF_SID;
+                       srp->flags = psid->flags;
+                       if (CHECK_FLAG(psid->flags, EXT_SUBTLV_PREFIX_SID_VFLG))
+                               srp->sid = GET_LABEL(ntohl(psid->value));
+                       else
+                               srp->sid = ntohl(psid->value);
+                       IPV4_ADDR_COPY(&srp->nhlfe.prefv4.prefix,
+                                      &pref->address);
+                       srp->nhlfe.prefv4.prefixlen = pref->pref_length;
+                       srp->nhlfe.prefv4.family = AF_INET;
+                       apply_mask_ipv4(&srp->nhlfe.prefv4);
+                       break;
+               default:
+                       break;
+               }
+               sum += TLV_SIZE(sub_tlvh);
+       }
+
+       if (IS_DEBUG_OSPF_SR)
+               zlog_debug("  |-  Found SID %u for prefix %s/%u", srp->sid,
+                          inet_ntoa(srp->nhlfe.prefv4.prefix),
+                          srp->nhlfe.prefv4.prefixlen);
+       return srp;
+}
+
+/*
+ * Functions to manipulate Segment Routing Link & Prefix structures
+ */
+
+/* Compare two Segment Link: return 0 if equal, 1 otherwise */
+static inline int sr_link_cmp(struct sr_link *srl1, struct sr_link *srl2)
+{
+       if ((srl1->sid[0] == srl2->sid[0]) && (srl1->sid[1] == srl2->sid[1])
+           && (srl1->type == srl2->type) && (srl1->flags[0] == srl2->flags[0])
+           && (srl1->flags[1] == srl2->flags[1]))
+               return 0;
+       else
+               return 1;
+}
+
+/* Compare two Segment Prefix: return 0 if equal, 1 otherwise */
+static inline int sr_prefix_cmp(struct sr_prefix *srp1, struct sr_prefix *srp2)
+{
+       if ((srp1->sid == srp2->sid) && (srp1->flags == srp2->flags))
+               return 0;
+       else
+               return 1;
+}
+
+/* Update Segment Link of given Segment Routing Node */
+static void update_ext_link_sid(struct sr_node *srn, struct sr_link *srl,
+                               u_char lsa_flags)
+{
+       struct listnode *node;
+       struct sr_link *lk;
+       bool found = false;
+
+       /* Sanity check */
+       if ((srn == NULL) || (srl == NULL))
+               return;
+
+       if (IS_DEBUG_OSPF_SR)
+               zlog_debug("  |-  Process Extended Link Adj/Lan-SID");
+
+       /* Process only Local Adj/Lan_Adj SID coming from LSA SELF */
+       if (!CHECK_FLAG(srl->flags[0], EXT_SUBTLV_LINK_ADJ_SID_LFLG)
+           || !CHECK_FLAG(srl->flags[1], EXT_SUBTLV_LINK_ADJ_SID_LFLG)
+           || !CHECK_FLAG(lsa_flags, OSPF_LSA_SELF))
+               return;
+
+       /* Search for existing Segment Link */
+       for (ALL_LIST_ELEMENTS_RO(srn->ext_link, node, lk))
+               if (lk->instance == srl->instance) {
+                       found = true;
+                       break;
+               }
+
+       if (IS_DEBUG_OSPF_SR)
+               zlog_debug("  |-  %s SR Link 8.0.0.%u for SR node %s",
+                          found ? "Update" : "Add",
+                          GET_OPAQUE_ID(srl->instance),
+                          inet_ntoa(srn->adv_router));
+
+       /* if not found, add new Segment Link and install NHLFE */
+       if (!found) {
+               /* Complete SR-Link and add it to SR-Node list */
+               srl->srn = srn;
+               IPV4_ADDR_COPY(&srl->adv_router, &srn->adv_router);
+               listnode_add(srn->ext_link, srl);
+               /* Try to set MPLS table */
+               if (compute_link_nhlfe(srl)) {
+                       add_sid_nhlfe(srl->nhlfe[0]);
+                       add_sid_nhlfe(srl->nhlfe[1]);
+               }
+       } else {
+               if (sr_link_cmp(lk, srl)) {
+                       if (compute_link_nhlfe(srl)) {
+                               update_sid_nhlfe(lk->nhlfe[0], srl->nhlfe[0]);
+                               update_sid_nhlfe(lk->nhlfe[1], srl->nhlfe[1]);
+                               /* Replace Segment List */
+                               listnode_delete(srn->ext_link, lk);
+                               XFREE(MTYPE_OSPF_SR_PARAMS, lk);
+                               srl->srn = srn;
+                               IPV4_ADDR_COPY(&srl->adv_router,
+                                              &srn->adv_router);
+                               listnode_add(srn->ext_link, srl);
+                       } else {
+                               /* New NHLFE was not found.
+                                * Just free the SR Link
+                                */
+                               XFREE(MTYPE_OSPF_SR_PARAMS, srl);
+                       }
+               } else {
+                       /*
+                        * This is just an LSA refresh.
+                        * Stop processing and free SR Link
+                        */
+                       XFREE(MTYPE_OSPF_SR_PARAMS, srl);
+               }
+       }
+}
+
+/* Update Segment Prefix of given Segment Routing Node */
+static void update_ext_prefix_sid(struct sr_node *srn, struct sr_prefix *srp)
+{
+
+       struct listnode *node;
+       struct sr_prefix *pref;
+       bool found = false;
+
+       /* Sanity check */
+       if (srn == NULL || srp == NULL)
+               return;
+
+       if (IS_DEBUG_OSPF_SR)
+               zlog_debug("  |-  Process Extended Prefix SID %u", srp->sid);
+
+       /* Process only Global Prefix SID */
+       if (CHECK_FLAG(srp->flags, EXT_SUBTLV_PREFIX_SID_LFLG))
+               return;
+
+       /* Search for existing Segment Prefix */
+       for (ALL_LIST_ELEMENTS_RO(srn->ext_prefix, node, pref))
+               if (pref->instance == srp->instance) {
+                       found = true;
+                       break;
+               }
+
+       if (IS_DEBUG_OSPF_SR)
+               zlog_debug("  |-  %s SR LSA ID 7.0.0.%u for SR node %s",
+                          found ? "Update" : "Add",
+                          GET_OPAQUE_ID(srp->instance),
+                          inet_ntoa(srn->adv_router));
+
+       /* if not found, add new Segment Prefix and install NHLFE */
+       if (!found) {
+               /* Complete SR-Prefix and add it to SR-Node list */
+               srp->srn = srn;
+               IPV4_ADDR_COPY(&srp->adv_router, &srn->adv_router);
+               listnode_add(srn->ext_prefix, srp);
+               /* Try to set MPLS table */
+               if (compute_prefix_nhlfe(srp) == 1)
+                       add_sid_nhlfe(srp->nhlfe);
+       } else {
+               if (sr_prefix_cmp(pref, srp)) {
+                       if (compute_prefix_nhlfe(srp) == 1) {
+                               update_sid_nhlfe(pref->nhlfe, srp->nhlfe);
+                               /* Replace Segment Prefix */
+                               listnode_delete(srn->ext_prefix, pref);
+                               XFREE(MTYPE_OSPF_SR_PARAMS, pref);
+                               srp->srn = srn;
+                               IPV4_ADDR_COPY(&srp->adv_router,
+                                              &srn->adv_router);
+                               listnode_add(srn->ext_prefix, srp);
+                       } else {
+                               /* New NHLFE was not found.
+                                * Just free the SR Prefix
+                                */
+                               XFREE(MTYPE_OSPF_SR_PARAMS, srp);
+                       }
+               } else {
+                       /* This is just an LSA refresh.
+                        * Stop processing and free SR Prefix
+                        */
+                       XFREE(MTYPE_OSPF_SR_PARAMS, srp);
+               }
+       }
+}
+
+/*
+ * When change the FRR Self SRGB, update the NHLFE Input Label
+ * for all Extended Prefix with SID index through hash_iterate()
+ */
+static void update_in_nhlfe(struct hash_backet *backet, void *args)
+{
+       struct listnode *node;
+       struct sr_node *srn = (struct sr_node *)backet->data;
+       struct sr_prefix *srp;
+       struct sr_nhlfe new;
+
+       /* Process Every Extended Prefix for this SR-Node */
+       for (ALL_LIST_ELEMENTS_RO(srn->ext_prefix, node, srp)) {
+               /* Process Self SRN only if NO-PHP is requested */
+               if ((srn == OspfSR.self)
+                   && !CHECK_FLAG(srp->flags, EXT_SUBTLV_PREFIX_SID_NPFLG))
+                       continue;
+
+               /* Process only SID Index */
+               if (CHECK_FLAG(srp->flags, EXT_SUBTLV_PREFIX_SID_VFLG))
+                       continue;
+
+               /* OK. Compute new NHLFE */
+               memcpy(&new, &srp->nhlfe, sizeof(struct sr_nhlfe));
+               new.label_in = index2label(srp->sid, OspfSR.srgb);
+               /* Update MPLS LFIB */
+               update_sid_nhlfe(srp->nhlfe, new);
+               /* Finally update Input Label */
+               srp->nhlfe.label_in = new.label_in;
+       }
+}
+
+/*
+ * When SRGB has changed, update NHLFE Output Label for all Extended Prefix
+ * with SID index which use the given SR-Node as nexthop though hash_iterate()
+ */
+static void update_out_nhlfe(struct hash_backet *backet, void *args)
+{
+       struct listnode *node;
+       struct sr_node *srn = (struct sr_node *)backet->data;
+       struct sr_node *srnext = (struct sr_node *)args;
+       struct sr_prefix *srp;
+       struct sr_nhlfe new;
+
+       for (ALL_LIST_ELEMENTS_RO(srn->ext_prefix, node, srp)) {
+               /* Process only SID Index for next hop without PHP */
+               if ((srp->nexthop == NULL)
+                   && (!CHECK_FLAG(srp->flags, EXT_SUBTLV_PREFIX_SID_NPFLG)))
+                       continue;
+               memcpy(&new, &srp->nhlfe, sizeof(struct sr_nhlfe));
+               new.label_out = index2label(srp->sid, srnext->srgb);
+               update_sid_nhlfe(srp->nhlfe, new);
+               srp->nhlfe.label_out = new.label_out;
+       }
+}
+
+/*
+ * Following functions are call when new Segment Routing LSA are received
+ *  - Router Information: ospf_sr_ri_lsa_update() & ospf_sr_ri_lsa_delete()
+ *  - Extended Link: ospf_sr_ext_link_update() & ospf_sr_ext_link_delete()
+ *  - Extended Prefix: ospf_ext_prefix_update() & ospf_sr_ext_prefix_delete()
+ */
+
+/* Update Segment Routing from Router Information LSA */
+void ospf_sr_ri_lsa_update(struct ospf_lsa *lsa)
+{
+       struct sr_node *srn;
+       struct tlv_header *tlvh;
+       struct lsa_header *lsah = (struct lsa_header *)lsa->data;
+       struct ri_sr_tlv_sid_label_range *ri_srgb;
+       struct ri_sr_tlv_sr_algorithm *algo;
+       struct sr_srgb srgb;
+       uint16_t length = 0, sum = 0;
+
+       if (IS_DEBUG_OSPF_SR)
+               zlog_debug(
+                       "SR (%s): Process Router "
+                       "Information LSA 4.0.0.%u from %s",
+                       __func__,
+                       GET_OPAQUE_ID(ntohl(lsah->id.s_addr)),
+                       inet_ntoa(lsah->adv_router));
+
+       /* Sanity check */
+       if (IS_LSA_SELF(lsa))
+               return;
+
+       if (OspfSR.neighbors == NULL) {
+               zlog_err("SR (%s): Abort! no valid SR DataBase", __func__);
+               return;
+       }
+
+       /* Get SR Node in hash table from Router ID */
+       srn = hash_get(OspfSR.neighbors, (void *)&(lsah->adv_router),
+                      (void *)sr_node_new);
+
+       /* Sanity check */
+       if (srn == NULL) {
+               zlog_err(
+                       "SR (%s): Abort! can't create SR node in hash table",
+                       __func__);
+               return;
+       }
+
+       if ((srn->instance != 0) && (srn->instance != ntohl(lsah->id.s_addr))) {
+               zlog_err(
+                       "SR (%s): Abort! Wrong "
+                       "LSA ID 4.0.0.%u for SR node %s/%u",
+                       __func__,
+                       GET_OPAQUE_ID(ntohl(lsah->id.s_addr)),
+                       inet_ntoa(lsah->adv_router), srn->instance);
+               return;
+       }
+
+       /* Collect Router Information Sub TLVs */
+       /* Initialize TLV browsing */
+       length = ntohs(lsah->length) - OSPF_LSA_HEADER_SIZE;
+       srgb.range_size = 0;
+       srgb.lower_bound = 0;
+
+       for (tlvh = TLV_HDR_TOP(lsah); (sum < length) && (tlvh != NULL);
+            tlvh = TLV_HDR_NEXT(tlvh)) {
+               switch (ntohs(tlvh->type)) {
+               case RI_SR_TLV_SR_ALGORITHM:
+                       algo = (struct ri_sr_tlv_sr_algorithm *)tlvh;
+                       int i;
+
+                       for (i = 0; i < ntohs(algo->header.length); i++)
+                               srn->algo[i] = algo->value[0];
+                       for (; i < ALGORITHM_COUNT; i++)
+                               srn->algo[i] = SR_ALGORITHM_UNSET;
+                       sum += TLV_SIZE(tlvh);
+                       break;
+               case RI_SR_TLV_SID_LABEL_RANGE:
+                       ri_srgb = (struct ri_sr_tlv_sid_label_range *)tlvh;
+                       srgb.range_size = GET_RANGE_SIZE(ntohl(ri_srgb->size));
+                       srgb.lower_bound =
+                               GET_LABEL(ntohl(ri_srgb->lower.value));
+                       sum += TLV_SIZE(tlvh);
+                       break;
+               case RI_SR_TLV_NODE_MSD:
+                       srn->msd = ((struct ri_sr_tlv_node_msd *)(tlvh))->value;
+                       sum += TLV_SIZE(tlvh);
+                       break;
+               default:
+                       sum += TLV_SIZE(tlvh);
+                       break;
+               }
+       }
+
+       /* Check that we collect mandatory parameters */
+       if (srn->algo[0] == SR_ALGORITHM_UNSET || srgb.range_size == 0
+           || srgb.lower_bound == 0) {
+               zlog_warn(
+                       "SR (%s): Missing mandatory parameters. Abort!",
+                       __func__);
+               hash_release(OspfSR.neighbors, &(srn->adv_router));
+               XFREE(MTYPE_OSPF_SR_PARAMS, srn);
+               return;
+       }
+
+       /* Check if it is a new SR Node or not */
+       if (srn->instance == 0) {
+               /* update LSA ID */
+               srn->instance = ntohl(lsah->id.s_addr);
+               /* Copy SRGB */
+               srn->srgb.range_size = srgb.range_size;
+               srn->srgb.lower_bound = srgb.lower_bound;
+       }
+
+       /* Check if SRGB has changed */
+       if ((srn->srgb.range_size != srgb.range_size)
+           || (srn->srgb.lower_bound != srgb.lower_bound)) {
+               srn->srgb.range_size = srgb.range_size;
+               srn->srgb.lower_bound = srgb.lower_bound;
+               /* Update NHLFE if it is a neighbor SR node */
+               if (srn->neighbor == OspfSR.self)
+                       hash_iterate(OspfSR.neighbors,
+                                    (void (*)(struct hash_backet *,
+                                              void *))update_out_nhlfe,
+                                    (void *)srn);
+       }
+
+}
+
+/*
+ * Delete SR Node entry in hash table information corresponding to an expired
+ * Router Information LSA
+ */
+void ospf_sr_ri_lsa_delete(struct ospf_lsa *lsa)
+{
+       struct sr_node *srn;
+       struct lsa_header *lsah = (struct lsa_header *)lsa->data;
+
+       if (IS_DEBUG_OSPF_SR)
+               zlog_debug(
+                       "SR (%s): Remove SR node %s from lsa_id 4.0.0.%u",
+                       __func__, inet_ntoa(lsah->adv_router),
+                       GET_OPAQUE_ID(ntohl(lsah->id.s_addr)));
+
+       /* Sanity check */
+       if (OspfSR.neighbors == NULL) {
+               zlog_err("SR (%s): Abort! no valid SR Data Base", __func__);
+               return;
+       }
+
+       /* Release Router ID entry in SRDB hash table */
+       srn = hash_release(OspfSR.neighbors, &(lsah->adv_router));
+
+       /* Sanity check */
+       if (srn == NULL) {
+               zlog_err(
+                       "SR (%s): Abort! no entry in SRDB for SR Node %s",
+                       __func__, inet_ntoa(lsah->adv_router));
+               return;
+       }
+
+       if ((srn->instance != 0) && (srn->instance != ntohl(lsah->id.s_addr))) {
+               zlog_err(
+                       "SR (%s): Abort! Wrong LSA ID 4.0.0.%u for SR node %s",
+                       __func__, GET_OPAQUE_ID(ntohl(lsah->id.s_addr)),
+                       inet_ntoa(lsah->adv_router));
+               return;
+       }
+
+       /* Remove SR node */
+       sr_node_del(srn);
+
+}
+
+/* Update Segment Routing from Extended Link LSA */
+void ospf_sr_ext_link_lsa_update(struct ospf_lsa *lsa)
+{
+       struct sr_node *srn;
+       struct tlv_header *tlvh;
+       struct lsa_header *lsah = (struct lsa_header *)lsa->data;
+       struct sr_link *srl;
+
+       uint16_t length, sum;
+
+       if (IS_DEBUG_OSPF_SR)
+               zlog_debug(
+                       "SR (%s): Process Extended Link LSA 8.0.0.%u from %s",
+                       __func__, GET_OPAQUE_ID(ntohl(lsah->id.s_addr)),
+                       inet_ntoa(lsah->adv_router));
+
+       /* Sanity check */
+       if (OspfSR.neighbors == NULL) {
+               zlog_err("SR (%s): Abort! no valid SR DataBase", __func__);
+               return;
+       }
+
+       /* Get SR Node in hash table from Router ID */
+       srn = (struct sr_node *)hash_get(OspfSR.neighbors,
+                                        (void *)&(lsah->adv_router),
+                                        (void *)sr_node_new);
+
+       /* Sanity check */
+       if (srn == NULL) {
+               zlog_err(
+                       "SR (%s): Abort! can't create SR node in hash table",
+                       __func__);
+               return;
+       }
+
+       /* Initialize TLV browsing */
+       length = ntohs(lsah->length) - OSPF_LSA_HEADER_SIZE;
+       sum = 0;
+       for (tlvh = TLV_HDR_TOP(lsah); (sum < length) && (tlvh != NULL);
+            tlvh = TLV_HDR_NEXT(tlvh)) {
+               if (ntohs(tlvh->type) == EXT_TLV_LINK) {
+                       /* Got Extended Link information */
+                       srl = get_ext_link_sid(tlvh);
+                       /* Update SID if not null */
+                       if (srl != NULL) {
+                               srl->instance = ntohl(lsah->id.s_addr);
+                               update_ext_link_sid(srn, srl, lsa->flags);
+                       }
+               }
+               sum += TLV_SIZE(tlvh);
+       }
+}
+
+/* Delete Segment Routing from Extended Link LSA */
+void ospf_sr_ext_link_lsa_delete(struct ospf_lsa *lsa)
+{
+       struct listnode *node;
+       struct sr_link *srl;
+       struct sr_node *srn;
+       struct lsa_header *lsah = (struct lsa_header *)lsa->data;
+       uint32_t instance = ntohl(lsah->id.s_addr);
+
+       if (IS_DEBUG_OSPF_SR)
+               zlog_debug(
+                       "SR (%s): Remove Extended Link LSA 8.0.0.%u from %s",
+                       __func__, GET_OPAQUE_ID(ntohl(lsah->id.s_addr)),
+                       inet_ntoa(lsah->adv_router));
+
+       /* Sanity check */
+       if (OspfSR.neighbors == NULL) {
+               zlog_err("SR (%s): Abort! no valid SR DataBase", __func__);
+               return;
+       }
+
+       /* Search SR Node in hash table from Router ID */
+       srn = (struct sr_node *)hash_lookup(OspfSR.neighbors,
+                                           (void *)&(lsah->adv_router));
+
+       /*
+        * SR-Node may be NULL if it has been remove previously when
+        * processing Router Information LSA deletion
+        */
+       if (srn == NULL) {
+               zlog_warn(
+                       "SR (%s): Stop! no entry in SRDB for SR Node %s",
+                       __func__, inet_ntoa(lsah->adv_router));
+               return;
+       }
+
+       /* Search for corresponding Segment Link */
+       for (ALL_LIST_ELEMENTS_RO(srn->ext_link, node, srl))
+               if (srl->instance == instance)
+                       break;
+
+       /* Remove Segment Link if found */
+       if ((srl != NULL) && (srl->instance == instance)) {
+               del_sid_nhlfe(srl->nhlfe[0]);
+               del_sid_nhlfe(srl->nhlfe[1]);
+               listnode_delete(srn->ext_link, srl);
+               XFREE(MTYPE_OSPF_SR_PARAMS, srl);
+       } else {
+               zlog_warn(
+                       "SR (%s): Didn't found corresponding SR Link 8.0.0.%u "
+                       "for SR Node %s", __func__,
+                       GET_OPAQUE_ID(ntohl(lsah->id.s_addr)),
+                       inet_ntoa(lsah->adv_router));
+       }
+
+}
+
+/* Update Segment Routing from Extended Prefix LSA */
+void ospf_sr_ext_prefix_lsa_update(struct ospf_lsa *lsa)
+{
+       struct sr_node *srn;
+       struct tlv_header *tlvh;
+       struct lsa_header *lsah = (struct lsa_header *)lsa->data;
+       struct sr_prefix *srp;
+
+       uint16_t length, sum;
+
+       if (IS_DEBUG_OSPF_SR)
+               zlog_debug(
+                       "SR (%s): Process Extended Prefix LSA "
+                       "7.0.0.%u from %s", __func__,
+                       GET_OPAQUE_ID(ntohl(lsah->id.s_addr)),
+                       inet_ntoa(lsah->adv_router));
+
+       /* Sanity check */
+       if (OspfSR.neighbors == NULL) {
+               zlog_err("SR (%s): Abort! no valid SR DataBase", __func__);
+               return;
+       }
+
+       /* Get SR Node in hash table from Router ID */
+       srn = (struct sr_node *)hash_get(OspfSR.neighbors,
+                                        (void *)&(lsah->adv_router),
+                                        (void *)sr_node_new);
+
+       /* Sanity check */
+       if (srn == NULL) {
+               zlog_err(
+                       "SR (%s): Abort! can't create SR node in hash table",
+                       __func__);
+               return;
+       }
+
+       /* Initialize TLV browsing */
+       length = ntohs(lsah->length) - OSPF_LSA_HEADER_SIZE;
+       sum = 0;
+       for (tlvh = TLV_HDR_TOP(lsah); sum < length;
+            tlvh = TLV_HDR_NEXT(tlvh)) {
+               if (ntohs(tlvh->type) == EXT_TLV_LINK) {
+                       /* Got Extended Link information */
+                       srp = get_ext_prefix_sid(tlvh);
+                       /* Update SID if not null */
+                       if (srp != NULL) {
+                               srp->instance = ntohl(lsah->id.s_addr);
+                               update_ext_prefix_sid(srn, srp);
+                       }
+               }
+               sum += TLV_SIZE(tlvh);
+       }
+}
+
+/* Delete Segment Routing from Extended Prefix LSA */
+void ospf_sr_ext_prefix_lsa_delete(struct ospf_lsa *lsa)
+{
+       struct listnode *node;
+       struct sr_prefix *srp;
+       struct sr_node *srn;
+       struct lsa_header *lsah = (struct lsa_header *)lsa->data;
+       uint32_t instance = ntohl(lsah->id.s_addr);
+
+       if (IS_DEBUG_OSPF_SR)
+               zlog_debug(
+                       "SR (%s): Remove Extended Prefix LSA 7.0.0.%u from %s",
+                       __func__, GET_OPAQUE_ID(ntohl(lsah->id.s_addr)),
+                       inet_ntoa(lsah->adv_router));
+
+       /* Sanity check */
+       if (OspfSR.neighbors == NULL) {
+               zlog_err("SR (%s): Abort! no valid SR DataBase", __func__);
+               return;
+       }
+
+       /* Search SR Node in hash table from Router ID */
+       srn = (struct sr_node *)hash_lookup(OspfSR.neighbors,
+                                           (void *)&(lsah->adv_router));
+
+       /*
+        * SR-Node may be NULL if it has been remove previously when
+        * processing Router Information LSA deletion
+        */
+       if (srn == NULL) {
+               zlog_warn(
+                       "SR (%s):  Stop! no entry in SRDB for SR Node %s",
+                       __func__, inet_ntoa(lsah->adv_router));
+               return;
+       }
+
+       /* Search for corresponding Segment Link */
+       for (ALL_LIST_ELEMENTS_RO(srn->ext_prefix, node, srp))
+               if (srp->instance == instance)
+                       break;
+
+       /* Remove Segment Link if found */
+       if ((srp != NULL) && (srp->instance == instance)) {
+               del_sid_nhlfe(srp->nhlfe);
+               listnode_delete(srn->ext_link, srp);
+               XFREE(MTYPE_OSPF_SR_PARAMS, srp);
+       } else {
+               zlog_warn(
+                       "SR (%s): Didn't found corresponding SR Prefix "
+                       "7.0.0.%u for SR Node %s", __func__,
+                       GET_OPAQUE_ID(ntohl(lsah->id.s_addr)),
+                       inet_ntoa(lsah->adv_router));
+       }
+
+}
+
+/* Get Label for Extended Link SID */
+/* TODO: To be replace by Zebra Label Manager */
+uint32_t get_ext_link_label_value(void)
+{
+       static uint32_t label = ADJ_SID_MIN - 1;
+
+       if (label < ADJ_SID_MAX)
+               label += 1;
+
+       return label;
+}
+
+/*
+ * Update Prefix SID. Call by ospf_ext_pref_ism_change to
+ * complete initial CLI command at startutp.
+ *
+ * @param ifp - Loopback interface
+ * @param pref - Prefix address of this interface
+ *
+ * @return - void
+ */
+void ospf_sr_update_prefix(struct interface *ifp, struct prefix *p)
+{
+       struct listnode *node;
+       struct sr_prefix *srp;
+
+       /* Sanity Check */
+       if ((ifp == NULL) || (p == NULL))
+               return;
+
+       /*
+        * Search if there is a Segment Prefix that correspond to this
+        * interface or prefix, and update it if found
+        */
+       for (ALL_LIST_ELEMENTS_RO(OspfSR.self->ext_prefix, node, srp)) {
+               if ((srp->nhlfe.ifindex == ifp->ifindex)
+                   || ((IPV4_ADDR_SAME(&srp->nhlfe.prefv4.prefix,
+                   &p->u.prefix4))
+                   && (srp->nhlfe.prefv4.prefixlen == p->prefixlen))) {
+
+                       /* Update Interface & Prefix info */
+                       srp->nhlfe.ifindex = ifp->ifindex;
+                       IPV4_ADDR_COPY(&srp->nhlfe.prefv4.prefix,
+                               &p->u.prefix4);
+                       srp->nhlfe.prefv4.prefixlen = p->prefixlen;
+                       srp->nhlfe.prefv4.family = p->family;
+                       IPV4_ADDR_COPY(&srp->nhlfe.nexthop, &p->u.prefix4);
+
+                       /* OK. Let's Schedule Extended Prefix LSA */
+                       srp->instance = ospf_ext_schedule_prefix_index(ifp,
+                               srp->sid, &srp->nhlfe.prefv4, srp->flags);
+
+                       /* Install NHLFE if NO-PHP is requested */
+                       if (CHECK_FLAG(srp->flags,
+                           EXT_SUBTLV_PREFIX_SID_NPFLG)) {
+                               srp->nhlfe.label_in = index2label(srp->sid,
+                                               OspfSR.self->srgb);
+                               srp->nhlfe.label_out = MPLS_LABEL_IMPLICIT_NULL;
+                               add_sid_nhlfe(srp->nhlfe);
+                       }
+               }
+       }
+}
+
+/*
+ * Following functions are used to update MPLS LFIB after a SPF run
+ */
+
+static void ospf_sr_nhlfe_update(struct hash_backet *backet, void *args)
+{
+
+       struct sr_node *srn = (struct sr_node *)backet->data;
+       struct listnode *node;
+       struct sr_prefix *srp;
+       struct sr_nhlfe old;
+       int rc;
+
+       /* Sanity Check */
+       if (srn == NULL)
+               return;
+
+       if (IS_DEBUG_OSPF_SR)
+               zlog_debug("  |-  Update Prefix for SR Node %s",
+                          inet_ntoa(srn->adv_router));
+
+       /* Skip Self SR Node */
+       if (srn == OspfSR.self)
+               return;
+
+       /* Update Extended Prefix */
+       for (ALL_LIST_ELEMENTS_RO(srn->ext_prefix, node, srp)) {
+
+               /* Backup current NHLFE */
+               memcpy(&old, &srp->nhlfe, sizeof(struct sr_nhlfe));
+
+               /* Compute the new NHLFE */
+               rc = compute_prefix_nhlfe(srp);
+
+               /* Check computation result */
+               switch (rc) {
+               /* next hop is not know, remove old NHLFE to avoid loop */
+               case -1:
+                       del_sid_nhlfe(srp->nhlfe);
+                       break;
+               /* next hop has not changed, skip it */
+               case 0:
+                       break;
+               /* there is a new next hop, update NHLFE */
+               case 1:
+                       update_sid_nhlfe(old, srp->nhlfe);
+                       break;
+               default:
+                       break;
+               }
+       }
+}
+
+static int ospf_sr_update_schedule(struct thread *t)
+{
+
+       struct ospf *ospf;
+       struct timeval start_time, stop_time;
+
+       ospf = THREAD_ARG(t);
+       ospf->t_sr_update = NULL;
+
+       if (!OspfSR.update)
+               return 0;
+
+       monotime(&start_time);
+
+       if (IS_DEBUG_OSPF_SR)
+               zlog_debug("SR (%s): Start SPF update", __func__);
+
+       hash_iterate(OspfSR.neighbors, (void (*)(struct hash_backet *,
+                                                void *))ospf_sr_nhlfe_update,
+                    NULL);
+
+       monotime(&stop_time);
+
+       zlog_info(
+               "SR (%s): SPF Processing Time(usecs): %lld\n",
+               __func__,
+               (stop_time.tv_sec - start_time.tv_sec) * 1000000LL
+                       + (stop_time.tv_usec - start_time.tv_usec));
+
+       OspfSR.update = false;
+       return 1;
+}
+
+#define OSPF_SR_UPDATE_INTERVAL        1
+
+void ospf_sr_update_timer_add(struct ospf *ospf)
+{
+
+       if (ospf == NULL)
+               return;
+
+       /* Check if an update is not alreday engage */
+       if (OspfSR.update)
+               return;
+
+       OspfSR.update = true;
+
+       thread_add_timer(master, ospf_sr_update_schedule, ospf,
+                        OSPF_SR_UPDATE_INTERVAL, &ospf->t_sr_update);
+}
+
+/*
+ * --------------------------------------
+ * Followings are vty command functions.
+ * --------------------------------------
+ */
+
+/*
+ * Segment Routing Router configuration
+ *
+ * Must be centralize as it concerns both Extended Link/Prefix LSA
+ * and Router Information LSA. Choose to call it from Extended Prefix
+ * write_config() call back.
+ *
+ * @param vty VTY output
+ *
+ * @return none
+ */
+void ospf_sr_config_write_router(struct vty *vty)
+{
+       struct listnode *node;
+       struct sr_prefix *srp;
+
+       if (OspfSR.enabled) {
+               vty_out(vty, " segment-routing on\n");
+
+               if ((OspfSR.srgb.lower_bound != MPLS_DEFAULT_MIN_SRGB_LABEL)
+                   || (OspfSR.srgb.range_size != MPLS_DEFAULT_MAX_SRGB_SIZE)) {
+                       vty_out(vty, " segment-routing global-block %u %u\n",
+                                       OspfSR.srgb.lower_bound,
+                                       OspfSR.srgb.lower_bound +
+                                       OspfSR.srgb.range_size - 1);
+               }
+               if (OspfSR.msd != 0)
+                       vty_out(vty, " segment-routing node-msd %u\n",
+                               OspfSR.msd);
+
+               if (OspfSR.self != NULL) {
+                       for (ALL_LIST_ELEMENTS_RO(OspfSR.self->ext_prefix, node,
+                                                 srp)) {
+                               vty_out(vty,
+                                       " segment-routing prefix %s/%u "
+                                       "index %u%s\n",
+                                       inet_ntoa(srp->nhlfe.prefv4.prefix),
+                                       srp->nhlfe.prefv4.prefixlen, srp->sid,
+                                       CHECK_FLAG(srp->flags,
+                                               EXT_SUBTLV_PREFIX_SID_NPFLG) ?
+                                               " no-php-flag" : "");
+                       }
+               }
+       }
+}
+
+DEFUN(ospf_sr_enable,
+       ospf_sr_enable_cmd,
+       "segment-routing on",
+       SR_STR
+       "Enable Segment Routing\n")
+{
+
+       VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
+
+       if (OspfSR.enabled)
+               return CMD_SUCCESS;
+
+       if (ospf->vrf_id != VRF_DEFAULT) {
+               vty_out(vty, "Segment Routing is only supported in default "
+                            "VRF\n");
+               return CMD_WARNING_CONFIG_FAILED;
+       }
+
+       if (IS_DEBUG_OSPF_EVENT)
+               zlog_debug("SR: Segment Routing: OFF -> ON");
+
+       /* Start Segment Routing */
+       OspfSR.enabled = true;
+       if (!ospf_sr_start(ospf)) {
+               zlog_warn("SR: Unable to start Segment Routing. Abort!");
+               return CMD_WARNING;
+       }
+
+       /* Set Router Information SR parameters */
+       if (IS_DEBUG_OSPF_EVENT)
+               zlog_debug("SR: Activate SR for Router Information LSA");
+
+       ospf_router_info_update_sr(true, OspfSR.srgb, OspfSR.msd);
+
+       /* Update Ext LSA */
+       if (IS_DEBUG_OSPF_EVENT)
+               zlog_debug("SR: Activate SR for Extended Link/Prefix LSA");
+
+       ospf_ext_update_sr(true);
+
+       return CMD_SUCCESS;
+}
+
+DEFUN (no_ospf_sr_enable,
+       no_ospf_sr_enable_cmd,
+       "no segment-routing [on]",
+       NO_STR
+       SR_STR
+       "Disable Segment Routing\n")
+{
+
+       if (!OspfSR.enabled)
+               return CMD_SUCCESS;
+
+       if (IS_DEBUG_OSPF_EVENT)
+               zlog_debug("SR: Segment Routing: ON -> OFF");
+
+       /* Start by Disabling Extended Link & Prefix LSA */
+       ospf_ext_update_sr(false);
+
+       /* then, disable Router Information SR parameters */
+       ospf_router_info_update_sr(false, OspfSR.srgb, OspfSR.msd);
+
+       /* Finally, stop Segment Routing */
+       ospf_sr_stop();
+       OspfSR.enabled = false;
+
+       return CMD_SUCCESS;
+}
+
+static int ospf_sr_enabled(struct vty *vty)
+{
+       if (OspfSR.enabled)
+               return 1;
+
+       if (vty)
+               vty_out(vty, "%% OSPF SR is not turned on\n");
+
+       return 0;
+}
+
+DEFUN (sr_sid_label_range,
+       sr_sid_label_range_cmd,
+       "segment-routing global-block (0-1048575) (0-1048575)",
+       SR_STR
+       "Segment Routing Global Block label range\n"
+       "Lower-bound range in decimal (0-1048575)\n"
+       "Upper-bound range in decimal (0-1048575)\n")
+{
+       uint32_t upper;
+       uint32_t lower;
+       uint32_t size;
+       int idx_low = 2;
+       int idx_up = 3;
+
+       if (!ospf_sr_enabled(vty))
+               return CMD_WARNING_CONFIG_FAILED;
+
+       /* Get lower and upper bound */
+       lower = strtoul(argv[idx_low]->arg, NULL, 10);
+       upper = strtoul(argv[idx_up]->arg, NULL, 10);
+       size = upper - lower + 1;
+
+       if (size > MPLS_DEFAULT_MAX_SRGB_SIZE || size <= 0) {
+               vty_out(vty,
+                       "Range size cannot be less than 0 or more than %u\n",
+                       MPLS_DEFAULT_MAX_SRGB_SIZE);
+               return CMD_WARNING_CONFIG_FAILED;
+       }
+
+       if (upper > MPLS_DEFAULT_MAX_SRGB_LABEL) {
+               vty_out(vty, "Upper-bound cannot exceed %u\n",
+                       MPLS_DEFAULT_MAX_SRGB_LABEL);
+               return CMD_WARNING_CONFIG_FAILED;
+       }
+
+       if (upper < MPLS_DEFAULT_MIN_SRGB_LABEL) {
+               vty_out(vty, "Upper-bound cannot be lower than %u\n",
+                       MPLS_DEFAULT_MIN_SRGB_LABEL);
+               return CMD_WARNING_CONFIG_FAILED;
+       }
+
+       /* Check if values have changed */
+       if ((OspfSR.srgb.range_size == size)
+           && (OspfSR.srgb.lower_bound == lower))
+               return CMD_SUCCESS;
+
+       /* Set SID/Label range SRGB */
+       OspfSR.srgb.range_size = size;
+       OspfSR.srgb.lower_bound = lower;
+       if (OspfSR.self != NULL) {
+               OspfSR.self->srgb.range_size = size;
+               OspfSR.self->srgb.lower_bound = lower;
+       }
+
+       /* Set Router Information SR parameters */
+       ospf_router_info_update_sr(true, OspfSR.srgb, OspfSR.msd);
+
+       /* Update NHLFE entries */
+       hash_iterate(OspfSR.neighbors,
+                    (void (*)(struct hash_backet *, void *))update_in_nhlfe,
+                    NULL);
+
+       return CMD_SUCCESS;
+}
+
+DEFUN (no_sr_sid_label_range,
+       no_sr_sid_label_range_cmd,
+       "no segment-routing global-block [(0-1048575) (0-1048575)]",
+       NO_STR
+       SR_STR
+       "Segment Routing Global Block label range\n"
+       "Lower-bound range in decimal (0-1048575)\n"
+       "Upper-bound range in decimal (0-1048575)\n")
+{
+
+       if (!ospf_sr_enabled(vty))
+               return CMD_WARNING_CONFIG_FAILED;
+
+       /* Revert to default SRGB value */
+       OspfSR.srgb.range_size = MPLS_DEFAULT_MIN_SRGB_SIZE;
+       OspfSR.srgb.lower_bound = MPLS_DEFAULT_MIN_SRGB_LABEL;
+       if (OspfSR.self != NULL) {
+               OspfSR.self->srgb.range_size = OspfSR.srgb.range_size;
+               OspfSR.self->srgb.lower_bound = OspfSR.srgb.lower_bound;
+       }
+
+       /* Set Router Information SR parameters */
+       ospf_router_info_update_sr(true, OspfSR.srgb, OspfSR.msd);
+
+       /* Update NHLFE entries */
+       hash_iterate(OspfSR.neighbors,
+                    (void (*)(struct hash_backet *, void *))update_in_nhlfe,
+                    NULL);
+
+       return CMD_SUCCESS;
+}
+
+DEFUN (sr_node_msd,
+       sr_node_msd_cmd,
+       "segment-routing node-msd (1-16)",
+       SR_STR
+       "Maximum Stack Depth for this router\n"
+       "Maximum number of label that could be stack (1-16)\n")
+{
+       uint32_t msd;
+       int idx = 1;
+
+       if (!ospf_sr_enabled(vty))
+               return CMD_WARNING_CONFIG_FAILED;
+
+       /* Get MSD */
+       argv_find(argv, argc, "(1-16)", &idx);
+       msd = strtoul(argv[idx]->arg, NULL, 10);
+       if (msd < 1 || msd > MPLS_MAX_LABELS) {
+               vty_out(vty, "MSD must be comprise between 1 and %u\n",
+                       MPLS_MAX_LABELS);
+               return CMD_WARNING_CONFIG_FAILED;
+       }
+
+       /* Check if value has changed */
+       if (OspfSR.msd == msd)
+               return CMD_SUCCESS;
+
+       /* Set this router MSD */
+       OspfSR.msd = msd;
+       if (OspfSR.self != NULL)
+               OspfSR.self->msd = msd;
+
+       /* Set Router Information SR parameters */
+       ospf_router_info_update_sr(true, OspfSR.srgb, OspfSR.msd);
+
+       return CMD_SUCCESS;
+}
+
+DEFUN (no_sr_node_msd,
+       no_sr_node_msd_cmd,
+       "no segment-routing node-msd [(1-16)]",
+       NO_STR
+       SR_STR
+       "Maximum Stack Depth for this router\n"
+       "Maximum number of label that could be stack (1-16)\n")
+{
+
+       if (!ospf_sr_enabled(vty))
+               return CMD_WARNING_CONFIG_FAILED;
+
+       /* unset this router MSD */
+       OspfSR.msd = 0;
+       if (OspfSR.self != NULL)
+               OspfSR.self->msd = 0;
+
+       /* Set Router Information SR parameters */
+       ospf_router_info_update_sr(true, OspfSR.srgb, 0);
+
+       return CMD_SUCCESS;
+}
+
+DEFUN (sr_prefix_sid,
+       sr_prefix_sid_cmd,
+       "segment-routing prefix A.B.C.D/M index (0-65535) [no-php-flag]",
+       SR_STR
+       "Prefix SID\n"
+       "IPv4 Prefix as A.B.C.D/M\n"
+       "SID index for this prefix in decimal (0-65535)\n"
+       "Index value inside SRGB (lower_bound < index < upper_bound)\n"
+       "Don't request Penultimate Hop Popping (PHP)\n")
+{
+       int idx = 0;
+       struct prefix p;
+       uint32_t index;
+       struct listnode *node;
+       struct sr_prefix *srp, *new;
+       struct interface *ifp;
+
+       if (!ospf_sr_enabled(vty))
+               return CMD_WARNING_CONFIG_FAILED;
+
+       /* Get network prefix */
+       argv_find(argv, argc, "A.B.C.D/M", &idx);
+       if (!str2prefix(argv[idx]->arg, &p)) {
+               vty_out(vty, "Invalid prefix format %s\n",
+                       argv[idx]->arg);
+               return CMD_WARNING_CONFIG_FAILED;
+       }
+
+       /* Get & verify index value */
+       argv_find(argv, argc, "(0-65535)", &idx);
+       index = strtoul(argv[idx]->arg, NULL, 10);
+       if (index > OspfSR.srgb.range_size - 1) {
+               vty_out(vty, "Index %u must be lower than range size %u\n",
+                       index, OspfSR.srgb.range_size);
+               return CMD_WARNING_CONFIG_FAILED;
+       }
+
+       /* check that the index is not already used */
+       for (ALL_LIST_ELEMENTS_RO(OspfSR.self->ext_prefix, node, srp)) {
+               if (srp->sid == index) {
+                       vty_out(vty, "Index %u is already used\n", index);
+                       return CMD_WARNING_CONFIG_FAILED;
+               }
+       }
+
+       /* Create new Extended Prefix to SRDB if not found */
+       new = XCALLOC(MTYPE_OSPF_SR_PARAMS, sizeof(struct sr_prefix));
+       IPV4_ADDR_COPY(&new->nhlfe.prefv4.prefix, &p.u.prefix4);
+       IPV4_ADDR_COPY(&new->nhlfe.nexthop, &p.u.prefix4);
+       new->nhlfe.prefv4.prefixlen = p.prefixlen;
+       new->nhlfe.prefv4.family = p.family;
+       new->sid = index;
+       /* Set NO PHP flag if present and compute NHLFE */
+       if (argv_find(argv, argc, "no-php-flag", &idx)) {
+               SET_FLAG(new->flags, EXT_SUBTLV_PREFIX_SID_NPFLG);
+               new->nhlfe.label_in = index2label(new->sid, OspfSR.self->srgb);
+               new->nhlfe.label_out = MPLS_LABEL_IMPLICIT_NULL;
+       }
+
+       if (IS_DEBUG_OSPF_SR)
+               zlog_debug(
+                       "SR (%s): Add new index %u to Prefix %s/%u",
+                       __func__, index, inet_ntoa(new->nhlfe.prefv4.prefix),
+                       new->nhlfe.prefv4.prefixlen);
+
+       /* Get Interface and check if it is a Loopback */
+       ifp = if_lookup_prefix(&p, VRF_DEFAULT);
+       if (ifp == NULL) {
+               /*
+                * Interface could be not yet available i.e. when this
+                * command is in the configuration file, OSPF is not yet
+                * ready. In this case, store the prefix SID for latter
+                * update of this Extended Prefix
+                */
+               listnode_add(OspfSR.self->ext_prefix, new);
+               zlog_warn(
+                       "Interface for prefix %s/%u not found. Deferred LSA "
+                       "flooding", inet_ntoa(p.u.prefix4), p.prefixlen);
+               return CMD_SUCCESS;
+       }
+
+       if (!if_is_loopback(ifp)) {
+               vty_out(vty, "interface %s is not a Loopback\n", ifp->name);
+               XFREE(MTYPE_OSPF_SR_PARAMS, new);
+               return CMD_WARNING_CONFIG_FAILED;
+       }
+       new->nhlfe.ifindex = ifp->ifindex;
+
+       /* Search if this prefix already exist */
+       for (ALL_LIST_ELEMENTS_RO(OspfSR.self->ext_prefix, node, srp)) {
+               if ((IPV4_ADDR_SAME(&srp->nhlfe.prefv4.prefix, &p.u.prefix4)
+                   && srp->nhlfe.prefv4.prefixlen == p.prefixlen))
+                       break;
+               else
+                       srp = NULL;
+       }
+
+       /* Update or Add this new SR Prefix */
+       if (srp) {
+               update_sid_nhlfe(srp->nhlfe, new->nhlfe);
+               listnode_delete(OspfSR.self->ext_prefix, srp);
+               listnode_add(OspfSR.self->ext_prefix, new);
+       } else {
+               listnode_add(OspfSR.self->ext_prefix, new);
+               add_sid_nhlfe(new->nhlfe);
+       }
+
+       /* Finally, update Extended Prefix LSA */
+       new->instance = ospf_ext_schedule_prefix_index(ifp, new->sid,
+                               &new->nhlfe.prefv4, new->flags);
+       if (new->instance == 0) {
+               vty_out(vty, "Unable to set index %u for prefix %s/%u\n", index,
+                       inet_ntoa(p.u.prefix4), p.prefixlen);
+               return CMD_WARNING;
+       }
+
+       return CMD_SUCCESS;
+}
+
+DEFUN (no_sr_prefix_sid,
+       no_sr_prefix_sid_cmd,
+       "no segment-routing prefix A.B.C.D/M [index (0-65535) no-php-flag]",
+       NO_STR
+       SR_STR
+       "Prefix SID\n"
+       "IPv4 Prefix as A.B.C.D/M\n"
+       "SID index for this prefix in decimal (0-65535)\n"
+       "Index value inside SRGB (lower_bound < index < upper_bound)\n"
+       "Don't request Penultimate Hop Popping (PHP)\n")
+{
+       int idx = 0;
+       struct prefix p;
+       struct listnode *node;
+       struct sr_prefix *srp;
+       struct interface *ifp;
+       bool found = false;
+       int rc;
+
+       /* Get network prefix */
+       argv_find(argv, argc, "A.B.C.D/M", &idx);
+       rc = str2prefix(argv[idx]->arg, &p);
+       if (!rc) {
+               vty_out(vty, "Invalid prefix format %s\n",
+                       argv[idx]->arg);
+               return CMD_WARNING_CONFIG_FAILED;
+       }
+
+       /* check that the prefix is already set */
+       for (ALL_LIST_ELEMENTS_RO(OspfSR.self->ext_prefix, node, srp))
+               if (IPV4_ADDR_SAME(&srp->nhlfe.prefv4.prefix, &p.u.prefix4)
+                   && (srp->nhlfe.prefv4.prefixlen == p.prefixlen)) {
+                       found = true;
+                       break;
+               }
+
+       if (!found) {
+               vty_out(vty, "Prefix %s is not found. Abort!\n",
+                       argv[idx]->arg);
+               return CMD_WARNING_CONFIG_FAILED;
+       }
+
+       /* Get Interface */
+       ifp = if_lookup_by_index(srp->nhlfe.ifindex, VRF_DEFAULT);
+       if (ifp == NULL) {
+               vty_out(vty, "interface for prefix %s not found.\n",
+                       argv[idx]->arg);
+               return CMD_WARNING_CONFIG_FAILED;
+       }
+
+       /* Update Extended Prefix LSA */
+       if (!ospf_ext_schedule_prefix_index(ifp, 0, NULL, 0)) {
+               vty_out(vty, "No corresponding loopback interface. Abort!\n");
+               return CMD_WARNING;
+       }
+
+       if (IS_DEBUG_OSPF_SR)
+               zlog_debug(
+                       "SR (%s): Remove Prefix %s/%u with index %u",
+                       __func__, inet_ntoa(srp->nhlfe.prefv4.prefix),
+                       srp->nhlfe.prefv4.prefixlen, srp->sid);
+
+       /* Delete NHLFE is NO-PHP is set */
+       if (CHECK_FLAG(srp->flags, EXT_SUBTLV_PREFIX_SID_NPFLG))
+               del_sid_nhlfe(srp->nhlfe);
+
+       /* OK, all is clean, remove SRP from SRDB */
+       listnode_delete(OspfSR.self->ext_prefix, srp);
+       XFREE(MTYPE_OSPF_SR_PARAMS, srp);
+
+       return CMD_SUCCESS;
+}
+
+
+
+static void show_vty_sr_node(struct vty *vty, struct sr_node *srn)
+{
+
+       struct listnode *node;
+       struct sr_link *srl;
+       struct sr_prefix *srp;
+       struct interface *itf;
+       char pref[16];
+       char sid[22];
+       char label[8];
+
+       /* Sanity Check */
+       if (srn == NULL)
+               return;
+
+       vty_out(vty, "SR-Node: %s", inet_ntoa(srn->adv_router));
+       vty_out(vty, "\tSRGB (Size/Label): %u/%u", srn->srgb.range_size,
+               srn->srgb.lower_bound);
+       vty_out(vty, "\tAlgorithm(s): %s",
+               srn->algo[0] == SR_ALGORITHM_SPF ? "SPF" : "S-SPF");
+       for (int i = 1; i < ALGORITHM_COUNT; i++) {
+               if (srn->algo[i] == SR_ALGORITHM_UNSET)
+                       continue;
+               vty_out(vty, "/%s",
+                       srn->algo[i] == SR_ALGORITHM_SPF ? "SPF" : "S-SPF");
+       }
+       if (srn->msd != 0)
+               vty_out(vty, "\tMSD: %u", srn->msd);
+
+       vty_out(vty,
+               "\n\n    Prefix or Link  Label In  Label Out       "
+               "Node or Adj. SID  Interface          Nexthop\n");
+       vty_out(vty,
+               "------------------  --------  ---------  "
+               "---------------------  ---------  ---------------\n");
+       for (ALL_LIST_ELEMENTS_RO(srn->ext_prefix, node, srp)) {
+               strncpy(pref, inet_ntoa(srp->nhlfe.prefv4.prefix), 16);
+               snprintf(sid, 22, "SR Pfx (idx %u)", srp->sid);
+               if (srp->nhlfe.label_out == MPLS_LABEL_IMPLICIT_NULL)
+                       sprintf(label, "pop");
+               else
+                       sprintf(label, "%u", srp->nhlfe.label_out);
+               itf = if_lookup_by_index(srp->nhlfe.ifindex, VRF_DEFAULT);
+               vty_out(vty, "%15s/%u  %8u  %9s  %21s  %9s  %15s\n", pref,
+                       srp->nhlfe.prefv4.prefixlen, srp->nhlfe.label_in, label,
+                       sid, itf ? itf->name : "-",
+                       inet_ntoa(srp->nhlfe.nexthop));
+       }
+
+       for (ALL_LIST_ELEMENTS_RO(srn->ext_link, node, srl)) {
+               strncpy(pref, inet_ntoa(srl->nhlfe[0].prefv4.prefix), 16);
+               snprintf(sid, 22, "SR Adj. (lbl %u)", srl->sid[0]);
+               if (srl->nhlfe[0].label_out == MPLS_LABEL_IMPLICIT_NULL)
+                       sprintf(label, "pop");
+               else
+                       sprintf(label, "%u", srl->nhlfe[0].label_out);
+               itf = if_lookup_by_index(srl->nhlfe[0].ifindex, VRF_DEFAULT);
+               vty_out(vty, "%15s/%u  %8u  %9s  %21s  %9s  %15s\n", pref,
+                       srl->nhlfe[0].prefv4.prefixlen, srl->nhlfe[0].label_in,
+                       label, sid, itf ? itf->name : "-",
+                       inet_ntoa(srl->nhlfe[0].nexthop));
+               snprintf(sid, 22, "SR Adj. (lbl %u)", srl->sid[1]);
+               if (srl->nhlfe[1].label_out == MPLS_LABEL_IMPLICIT_NULL)
+                       sprintf(label, "pop");
+               else
+                       sprintf(label, "%u", srl->nhlfe[0].label_out);
+               vty_out(vty, "%15s/%u  %8u  %9s  %21s  %9s  %15s\n", pref,
+                       srl->nhlfe[1].prefv4.prefixlen, srl->nhlfe[1].label_in,
+                       label, sid, itf ? itf->name : "-",
+                       inet_ntoa(srl->nhlfe[1].nexthop));
+       }
+       vty_out(vty, "\n");
+}
+
+static void show_srdb_entry(struct hash_backet *backet, void *args)
+{
+       struct vty *vty = (struct vty *)args;
+       struct sr_node *srn = (struct sr_node *)backet->data;
+
+       show_vty_sr_node(vty, srn);
+}
+
+DEFUN (show_ip_opsf_srdb,
+       show_ip_ospf_srdb_cmd,
+       "show ip ospf database segment-routing [adv-router A.B.C.D|self-originate]",
+       SHOW_STR
+       IP_STR
+       OSPF_STR
+       "Database summary\n"
+       "Show Segment Routing Data Base\n"
+       "Advertising SR node\n"
+       "Advertising SR node ID (as an IP address)\n"
+       "Self-originated SR node\n")
+{
+       int idx = 0;
+       struct in_addr rid;
+       struct sr_node *srn;
+
+       if (!OspfSR.enabled) {
+               vty_out(vty, "Segment Routing is disabled on this router\n");
+               return CMD_WARNING;
+       }
+
+       vty_out(vty, "\n          OSPF Segment Routing database for ID %s\n\n",
+               inet_ntoa(OspfSR.self->adv_router));
+
+       if (argv_find(argv, argc, "self-originate", &idx)) {
+               srn = OspfSR.self;
+               show_vty_sr_node(vty, srn);
+               return CMD_SUCCESS;
+       }
+
+       if (argv_find(argv, argc, "A.B.C.D", &idx)) {
+               if (!inet_aton(argv[idx]->arg, &rid)) {
+                       vty_out(vty,
+                               "Specified Router ID %s is invalid\n",
+                               argv[idx]->arg);
+                       return CMD_WARNING_CONFIG_FAILED;
+               }
+               /* Get the SR Node from the SRDB */
+               srn = (struct sr_node *)hash_lookup(OspfSR.neighbors,
+                                                   (void *)&rid);
+               show_vty_sr_node(vty, srn);
+               return CMD_SUCCESS;
+       }
+
+       /* No parameters have been provided, Iterate through all the SRDB */
+       hash_iterate(
+               OspfSR.neighbors,
+               (void (*)(struct hash_backet *, void *))show_srdb_entry,
+               (void *)vty);
+       return CMD_SUCCESS;
+}
+
+/* Install new CLI commands */
+void ospf_sr_register_vty(void)
+{
+       install_element(VIEW_NODE, &show_ip_ospf_srdb_cmd);
+
+       install_element(OSPF_NODE, &ospf_sr_enable_cmd);
+       install_element(OSPF_NODE, &no_ospf_sr_enable_cmd);
+       install_element(OSPF_NODE, &sr_sid_label_range_cmd);
+       install_element(OSPF_NODE, &no_sr_sid_label_range_cmd);
+       install_element(OSPF_NODE, &sr_node_msd_cmd);
+       install_element(OSPF_NODE, &no_sr_node_msd_cmd);
+       install_element(OSPF_NODE, &sr_prefix_sid_cmd);
+       install_element(OSPF_NODE, &no_sr_prefix_sid_cmd);
+
+}
diff --git a/ospfd/ospf_sr.h b/ospfd/ospf_sr.h
new file mode 100644 (file)
index 0000000..cb7d083
--- /dev/null
@@ -0,0 +1,316 @@
+/*
+ * This is an implementation of Segment Routing
+ * as per draft draft-ietf-ospf-segment-routing-extensions-24
+ *
+ * Module name: Segment Routing header definitions
+ *
+ * Author: Olivier Dugeon <olivier.dugeon@orange.com>
+ * Author: Anselme Sawadogo <anselmesawadogo@gmail.com>
+ *
+ * Copyright (C) 2016 - 2018 Orange Labs http://www.orange.com
+ *
+ * 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_OSPF_SR_H
+#define _FRR_OSPF_SR_H
+
+/* Default Route priority for OSPF Segment Routing */
+#define OSPF_SR_PRIORITY_DEFAULT       10
+
+/* macros and constants for segment routing */
+#define SET_RANGE_SIZE_MASK             0xffffff00
+#define GET_RANGE_SIZE_MASK             0x00ffffff
+#define SET_LABEL_MASK                  0xffffff00
+#define GET_LABEL_MASK                  0x00ffffff
+#define SET_RANGE_SIZE(range_size) ((range_size << 8) & SET_RANGE_SIZE_MASK)
+#define GET_RANGE_SIZE(range_size) ((range_size >> 8) & GET_RANGE_SIZE_MASK)
+#define SET_LABEL(label) ((label << 8) & SET_LABEL_MASK)
+#define GET_LABEL(label) ((label >> 8) & GET_LABEL_MASK)
+
+/* Label range for Adj-SID attribution purpose. Start just right after SRGB */
+#define ADJ_SID_MIN                     MPLS_DEFAULT_MAX_SRGB_LABEL
+#define ADJ_SID_MAX                     (MPLS_DEFAULT_MAX_SRGB_LABEL + 1000)
+
+#define OSPF_SR_DEFAULT_METRIC         1
+
+/* Segment Routing TLVs as per draft-ietf-ospf-segment-routing-extensions-19 */
+
+/* Segment ID could be a Label (3 bytes) or an Index (4 bytes) */
+#define SID_BASE_SIZE  4
+#define SID_LABEL      3
+#define SID_LABEL_SIZE (SID_BASE_SIZE + SID_LABEL)
+#define SID_INDEX      4
+#define SID_INDEX_SIZE (SID_BASE_SIZE + SID_INDEX)
+
+/* SID/Label Sub TLV - section 2.1 */
+#define SUBTLV_SID_LABEL               1
+#define SUBTLV_SID_LABEL_SIZE          8
+struct subtlv_sid_label {
+       /* Length is 3 (20 rightmost bits MPLS label) or 4 (32 bits SID) */
+       struct tlv_header header;
+       uint32_t value;
+};
+
+/*
+ * Following section defines Segment Routing TLV (tag, length, value)
+ * structures, used in Router Information Opaque LSA.
+ */
+
+/* RI SR-Algorithm TLV - section 3.1 */
+#define RI_SR_TLV_SR_ALGORITHM          8
+struct ri_sr_tlv_sr_algorithm {
+       struct tlv_header header;
+#define SR_ALGORITHM_SPF         0
+#define SR_ALGORITHM_STRICT_SPF  1
+#define SR_ALGORITHM_UNSET       255
+#define ALGORITHM_COUNT          4
+       /* Only 4 algorithms supported in this code */
+       uint8_t value[ALGORITHM_COUNT];
+};
+
+/* RI SID/Label Range TLV - section 3.2 */
+#define RI_SR_TLV_SID_LABEL_RANGE      9
+struct ri_sr_tlv_sid_label_range {
+       struct tlv_header header;
+/* Only 24 upper most bits are significant */
+#define SID_RANGE_LABEL_LENGTH 3
+       uint32_t size;
+       /* A SID/Label sub-TLV will follow. */
+       struct subtlv_sid_label lower;
+};
+
+/* RI Node/MSD TLV as per draft-ietf-ospf-segment-routing-msd-05 */
+#define RI_SR_TLV_NODE_MSD             12
+struct ri_sr_tlv_node_msd {
+       struct tlv_header header;
+       uint8_t subtype; /* always = 1 */
+       uint8_t value;
+       uint16_t padding;
+};
+
+/*
+ * Following section defines Segment Routing TLV (tag, length, value)
+ * structures, used in Extended Prefix/Link Opaque LSA.
+ */
+
+/* Adj-SID and LAN-Ajd-SID subtlvs' flags */
+#define EXT_SUBTLV_LINK_ADJ_SID_BFLG   0x80
+#define EXT_SUBTLV_LINK_ADJ_SID_VFLG   0x40
+#define EXT_SUBTLV_LINK_ADJ_SID_LFLG   0x20
+#define EXT_SUBTLV_LINK_ADJ_SID_SFLG   0x10
+
+/* Prefix SID subtlv Flags */
+#define EXT_SUBTLV_PREFIX_SID_NPFLG    0x40
+#define EXT_SUBTLV_PREFIX_SID_MFLG     0x20
+#define EXT_SUBTLV_PREFIX_SID_EFLG     0x10
+#define EXT_SUBTLV_PREFIX_SID_VFLG     0x08
+#define EXT_SUBTLV_PREFIX_SID_LFLG     0x04
+
+/* SID/Label Binding subtlv Flags */
+#define EXT_SUBTLV_SID_BINDING_MFLG    0x80
+
+/* Extended Prefix Range TLV - section 4 */
+#define EXT_TLV_PREF_RANGE             2
+#define EXT_SUBTLV_PREFIX_RANGE_SIZE   12
+struct ext_tlv_prefix_range {
+       struct tlv_header header;
+       uint8_t pref_length;
+       uint8_t af;
+       uint16_t range_size;
+       uint8_t flags;
+       uint8_t reserved[3];
+       struct in_addr address;
+};
+
+/* Prefix SID Sub-TLV - section 5 */
+#define EXT_SUBTLV_PREFIX_SID          2
+#define EXT_SUBTLV_PREFIX_SID_SIZE     8
+struct ext_subtlv_prefix_sid {
+       struct tlv_header header;
+       uint8_t flags;
+       uint8_t reserved;
+       uint8_t mtid;
+       uint8_t algorithm;
+       uint32_t value;
+};
+
+/* Adj-SID Sub-TLV - section 6.1 */
+#define EXT_SUBTLV_ADJ_SID             2
+#define EXT_SUBTLV_ADJ_SID_SIZE                8
+struct ext_subtlv_adj_sid {
+       struct tlv_header header;
+       uint8_t flags;
+       uint8_t reserved;
+       uint8_t mtid;
+       uint8_t weight;
+       uint32_t value;
+};
+
+/* LAN Adj-SID Sub-TLV - section 6.2 */
+#define EXT_SUBTLV_LAN_ADJ_SID         3
+#define EXT_SUBTLV_LAN_ADJ_SID_SIZE    12
+struct ext_subtlv_lan_adj_sid {
+       struct tlv_header header;
+       uint8_t flags;
+       uint8_t reserved;
+       uint8_t mtid;
+       uint8_t weight;
+       struct in_addr neighbor_id;
+       uint32_t value;
+};
+
+/*
+ * Following section define structure used to manage Segment Routing
+ * information and TLVs / SubTLVs
+ */
+
+/* Structure aggregating SRGB info retrieved from an lsa */
+struct sr_srgb {
+       uint32_t range_size;
+       uint32_t lower_bound;
+};
+
+/* SID type to make difference between loopback interfaces and others */
+enum sid_type { PREF_SID, ADJ_SID, LAN_ADJ_SID };
+
+/* Structure aggregating all OSPF Segment Routing information for the node */
+struct ospf_sr_db {
+       /* Status of Segment Routing: enable or disable */
+       bool enabled;
+
+       /* Ongoing Update following an OSPF SPF */
+       bool update;
+
+       /* Flooding Scope: Area = 10 or AS = 11 */
+       uint8_t scope;
+
+       /* FRR SR node */
+       struct sr_node *self;
+
+       /* List of neighbour SR nodes */
+       struct hash *neighbors;
+
+       /* List of SR prefix */
+       struct route_table *prefix;
+
+       /* Local SR info announced in Router Info LSA */
+
+       /* Algorithms supported by the node */
+       uint8_t algo[ALGORITHM_COUNT];
+       /*
+        * Segment Routing Global Block i.e. label range
+        * Only one range supported in this code
+        */
+       struct sr_srgb srgb;
+       /* Maximum SID Depth supported by the node */
+       uint8_t msd;
+};
+
+/* Structure aggregating all received SR info from LSAs by node */
+struct sr_node {
+       struct in_addr adv_router; /* used to identify sender of LSA */
+       /* 24-bit Opaque-ID field value according to RFC 7684 specification */
+       uint32_t instance;
+
+       uint8_t algo[ALGORITHM_COUNT]; /* Algorithms supported by the node */
+       /* Segment Routing Global Block i.e. label range */
+       struct sr_srgb srgb;
+       uint8_t msd; /* Maximum SID Depth */
+
+       /* List of Prefix & Link advertise by this node */
+       struct list *ext_prefix; /* For Node SID */
+       struct list *ext_link;   /* For Adj and LAN SID */
+
+       /* Pointer to FRR SR-Node or NULL if it is not a neighbor */
+       struct sr_node *neighbor;
+};
+
+
+/* Segment Routing - NHLFE info: support IPv4 Only */
+struct sr_nhlfe {
+       struct prefix_ipv4 prefv4;
+       struct in_addr nexthop;
+       ifindex_t ifindex;
+       mpls_label_t label_in;
+       mpls_label_t label_out;
+};
+
+/* Structure aggregating all Segment Routing Link information */
+/* Link are generally advertised by pair: primary + backup */
+struct sr_link {
+       struct in_addr adv_router; /* used to identify sender of LSA */
+       /* 24-bit Opaque-ID field value according to RFC 7684 specification */
+       uint32_t instance;
+
+       /* Flags to manage this link parameters. */
+       uint8_t flags[2];
+
+       /* Segment Routing ID */
+       uint32_t sid[2];
+       enum sid_type type;
+
+       /* SR NHLFE for this link */
+       struct sr_nhlfe nhlfe[2];
+
+       /* Back pointer to SR Node which advertise this Link */
+       struct sr_node *srn;
+};
+
+/* Structure aggregating all Segment Routing Prefix information */
+struct sr_prefix {
+       struct in_addr adv_router; /* used to identify sender of LSA */
+       /* 24-bit Opaque-ID field value according to RFC 7684 specification */
+       uint32_t instance;
+
+       /* Flags to manage this prefix parameters. */
+       uint8_t flags;
+
+       /* Segment Routing ID */
+       uint32_t sid;
+       enum sid_type type;
+
+       /* SR NHLFE for this prefix */
+       struct sr_nhlfe nhlfe;
+
+       /* Back pointer to SR Node which advertise this Prefix */
+       struct sr_node *srn;
+
+       /*
+        * Pointer to SR Node which is the next hop for this Prefix
+        * or NULL if next hop is the destination of the prefix
+        */
+       struct sr_node *nexthop;
+};
+
+/* Prototypes definition */
+/* Segment Routing initialisation functions */
+extern int ospf_sr_init(void);
+extern void ospf_sr_term(void);
+extern void ospf_sr_finish(void);
+/* Segment Routing LSA update & delete functions */
+extern void ospf_sr_ri_lsa_update(struct ospf_lsa *lsa);
+extern void ospf_sr_ri_lsa_delete(struct ospf_lsa *lsa);
+extern void ospf_sr_ext_link_lsa_update(struct ospf_lsa *lsa);
+extern void ospf_sr_ext_link_lsa_delete(struct ospf_lsa *lsa);
+extern void ospf_sr_ext_prefix_lsa_update(struct ospf_lsa *lsa);
+extern void ospf_sr_ext_prefix_lsa_delete(struct ospf_lsa *lsa);
+/* Segment Routing configuration functions */
+extern uint32_t get_ext_link_label_value(void);
+extern void ospf_sr_config_write_router(struct vty *vty);
+extern void ospf_sr_update_prefix(struct interface *ifp, struct prefix *p);
+/* Segment Routing re-routing function */
+extern void ospf_sr_update_timer_add(struct ospf *ospf);
+#endif /* _FRR_OSPF_SR_H */
index 253b272df67f266367d7bded1de589ba9a6bfb31..ab395207b99406766695a6dcb9326506615d785c 100644 (file)
@@ -170,6 +170,7 @@ void ospf_mpls_te_term(void)
 
        ospf_delete_opaque_functab(OSPF_OPAQUE_AREA_LSA,
                                   OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA);
+
        OspfMplsTE.enabled = false;
 
        ospf_mpls_te_unregister();
@@ -178,6 +179,14 @@ void ospf_mpls_te_term(void)
        return;
 }
 
+void ospf_mpls_te_finish(void)
+{
+       // list_delete_all_node(OspfMplsTE.iflist);
+
+       OspfMplsTE.enabled = false;
+       OspfMplsTE.inter_as = Off;
+}
+
 /*------------------------------------------------------------------------*
  * Followings are control functions for MPLS-TE parameters management.
  *------------------------------------------------------------------------*/
index 013421451057691235b2a25887b8ce44500ae19d..ed71e54f5404c79b26a0d27e4bf16b1c6f040628 100644 (file)
@@ -406,6 +406,7 @@ struct mpls_te_link {
 /* Prototypes. */
 extern int ospf_mpls_te_init(void);
 extern void ospf_mpls_te_term(void);
+extern void ospf_mpls_te_finish(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 *, enum lsa_opcode);
index a5ea14793a8e8ace5237f4f6bc5d970d6fcacc2c..09350b45a857713d77a5199213e62ea8ebc915e7 100644 (file)
@@ -218,7 +218,7 @@ DEFUN_NOSH (router_ospf,
                if (ospf->vrf_id != VRF_UNKNOWN)
                        ospf->oi_running = 1;
                if (IS_DEBUG_OSPF_EVENT)
-                       zlog_debug("Config command 'router ospf %d' received, vrf %s id %d oi_running %u",
+                       zlog_debug("Config command 'router ospf %d' received, vrf %s id %u oi_running %u",
                                   instance,  ospf->name ? ospf->name : "NIL",
                                   ospf->vrf_id, ospf->oi_running);
                VTY_PUSH_CONTEXT(OSPF_NODE, ospf);
@@ -534,11 +534,11 @@ DEFUN (no_ospf_passive_interface,
        }
 
        if (ospf->vrf_id != VRF_UNKNOWN)
-               ifp = if_get_by_name(argv[1]->arg, ospf->vrf_id, 0);
+               ifp = if_get_by_name(argv[2]->arg, ospf->vrf_id, 0);
 
        if (ifp == NULL) {
                vty_out(vty, "interface %s not found.\n",
-                       (char *)argv[1]->arg);
+                       (char *)argv[2]->arg);
                return CMD_WARNING_CONFIG_FAILED;
        }
 
@@ -619,7 +619,7 @@ DEFUN (ospf_network_area,
        ret = ospf_network_set(ospf, &p, area_id, format);
        if (ret == 0) {
                vty_out(vty, "There is already same network statement.\n");
-               return CMD_WARNING;
+               return CMD_WARNING_CONFIG_FAILED;
        }
 
        return CMD_SUCCESS;
@@ -1974,12 +1974,13 @@ DEFUN (ospf_area_authentication_message_digest,
        "Use message-digest authentication\n")
 {
        VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
-       int idx_ipv4_number = 1;
+       int idx = 0;
        struct ospf_area *area;
        struct in_addr area_id;
        int format;
 
-       VTY_GET_OSPF_AREA_ID(area_id, format, argv[idx_ipv4_number]->arg);
+       argv_find(argv, argc, "area", &idx);
+       VTY_GET_OSPF_AREA_ID(area_id, format, argv[idx + 1]->arg);
 
        area = ospf_area_get(ospf, area_id);
        ospf_area_display_format_set(ospf, area, format);
@@ -3692,14 +3693,15 @@ static int show_ip_ospf_interface_common(struct vty *vty, struct ospf *ospf,
 {
        struct interface *ifp;
        struct vrf *vrf = vrf_lookup_by_id(ospf->vrf_id);
-       json_object *json_vrf = NULL;
-       json_object *json_interface_sub = NULL;
+       json_object *json_vrf = NULL, *json_intf_array = NULL;
+       json_object *json_interface_sub = NULL, *json_interface = NULL;
 
        if (use_json) {
                if (use_vrf)
                        json_vrf = json_object_new_object();
                else
                        json_vrf = json;
+               json_intf_array = json_object_new_array();
        }
 
        if (ospf->instance) {
@@ -3713,21 +3715,29 @@ static int show_ip_ospf_interface_common(struct vty *vty, struct ospf *ospf,
        ospf_show_vrf_name(ospf, vty, json_vrf, use_vrf);
 
        if (intf_name == NULL) {
+               if (use_json)
+                       json_object_object_add(json_vrf, "interfaces",
+                                      json_intf_array);
                /* Show All Interfaces.*/
                FOR_ALL_INTERFACES (vrf, ifp) {
                        if (ospf_oi_count(ifp)) {
-                               if (use_json)
+                               if (use_json) {
+                                       json_interface =
+                                               json_object_new_object();
                                        json_interface_sub =
                                                json_object_new_object();
-
+                               }
                                show_ip_ospf_interface_sub(vty, ospf, ifp,
                                                           json_interface_sub,
                                                           use_json);
 
-                               if (use_json)
+                               if (use_json) {
+                                       json_object_array_add(json_intf_array,
+                                                             json_interface);
                                        json_object_object_add(
-                                               json_vrf, ifp->name,
+                                               json_interface, ifp->name,
                                                json_interface_sub);
+                               }
                        }
                }
        } else {
@@ -3740,15 +3750,23 @@ static int show_ip_ospf_interface_common(struct vty *vty, struct ospf *ospf,
                        else
                                vty_out(vty, "No such interface name\n");
                } else {
-                       if (use_json)
+                       if (use_json) {
                                json_interface_sub = json_object_new_object();
+                               json_interface = json_object_new_object();
+                               json_object_object_add(json_vrf, "interfaces",
+                                                      json_intf_array);
+                       }
 
                        show_ip_ospf_interface_sub(
                                vty, ospf, ifp, json_interface_sub, use_json);
 
-                       if (use_json)
-                               json_object_object_add(json_vrf, ifp->name,
+                       if (use_json) {
+                               json_object_array_add(json_intf_array,
+                                                     json_interface);
+                               json_object_object_add(json_interface,
+                                                      ifp->name,
                                                       json_interface_sub);
+                       }
                }
        }
 
@@ -4282,13 +4300,15 @@ static int show_ip_ospf_neighbor_common(struct vty *vty, struct ospf *ospf,
 {
        struct ospf_interface *oi;
        struct listnode *node;
-       json_object *json_vrf = NULL;
+       json_object *json_vrf = NULL, *json_nbr_array = NULL;
+       json_object *json_nbr_sub = NULL;
 
        if (use_json) {
                if (use_vrf)
                        json_vrf = json_object_new_object();
                else
                        json_vrf = json;
+               json_nbr_array = json_object_new_array();
        }
 
        if (ospf->instance) {
@@ -4302,9 +4322,19 @@ static int show_ip_ospf_neighbor_common(struct vty *vty, struct ospf *ospf,
        ospf_show_vrf_name(ospf, vty, json_vrf, use_vrf);
        if (!use_json)
                show_ip_ospf_neighbour_header(vty);
+       else
+               json_object_object_add(json_vrf, "neighbors",
+                                      json_nbr_array);
 
-       for (ALL_LIST_ELEMENTS_RO(ospf->oiflist, node, oi))
-               show_ip_ospf_neighbor_sub(vty, oi, json_vrf, use_json);
+       for (ALL_LIST_ELEMENTS_RO(ospf->oiflist, node, oi)) {
+               if (ospf_interface_neighbor_count(oi) == 0)
+                       continue;
+               if (use_json) {
+                       json_nbr_sub = json_object_new_object();
+                       json_object_array_add(json_nbr_array, json_nbr_sub);
+               }
+               show_ip_ospf_neighbor_sub(vty, oi, json_nbr_sub, use_json);
+       }
 
        if (use_json) {
                if (use_vrf) {
@@ -4680,7 +4710,6 @@ static int show_ip_ospf_neighbor_int_common(struct vty *vty, struct ospf *ospf,
 
        ospf_show_vrf_name(ospf, vty, json, use_vrf);
 
-       /*ifp = if_lookup_by_name(argv[arg_base]->arg, ospf->vrf_id);*/
        ifp = if_lookup_by_name_all_vrf(argv[arg_base]->arg);
        if (!ifp) {
                if (use_json)
@@ -6166,7 +6195,7 @@ static void show_ip_ospf_database_summary(struct vty *vty, struct ospf *ospf,
                                        show_database_header[type]);
 
                                LSDB_LOOP(AREA_LSDB(area, type), rn, lsa)
-                               show_lsa_summary(vty, lsa, self);
+                                       show_lsa_summary(vty, lsa, self);
 
                                vty_out(vty, "\n");
                        }
@@ -6188,7 +6217,7 @@ static void show_ip_ospf_database_summary(struct vty *vty, struct ospf *ospf,
                        vty_out(vty, "%s\n", show_database_header[type]);
 
                        LSDB_LOOP(AS_LSDB(ospf, type), rn, lsa)
-                       show_lsa_summary(vty, lsa, self);
+                               show_lsa_summary(vty, lsa, self);
 
                        vty_out(vty, "\n");
                }
@@ -8098,7 +8127,7 @@ DEFUN (no_ip_ospf_area,
 
 DEFUN (ospf_redistribute_source,
        ospf_redistribute_source_cmd,
-       "redistribute " FRR_REDIST_STR_OSPFD " [<metric (0-16777214)|metric-type (1-2)|route-map WORD>]",
+       "redistribute " FRR_REDIST_STR_OSPFD " [{metric (0-16777214)|metric-type (1-2)|route-map WORD}]",
        REDIST_STR
        FRR_REDIST_HELP_STR_OSPFD
        "Metric for redistributed routes\n"
@@ -8131,13 +8160,15 @@ DEFUN (ospf_redistribute_source,
                if (!str2metric(argv[idx]->arg, &metric))
                        return CMD_WARNING_CONFIG_FAILED;
        }
+       idx = 1;
        /* Get metric type. */
-       else if (argv_find(argv, argc, "(1-2)", &idx)) {
+       if (argv_find(argv, argc, "(1-2)", &idx)) {
                if (!str2metric_type(argv[idx]->arg, &type))
                        return CMD_WARNING_CONFIG_FAILED;
        }
+       idx = 1;
        /* Get route-map */
-       else if (argv_find(argv, argc, "WORD", &idx)) {
+       if (argv_find(argv, argc, "WORD", &idx)) {
                ospf_routemap_set(red, argv[idx]->arg);
        } else
                ospf_routemap_unset(red);
@@ -8147,7 +8178,7 @@ DEFUN (ospf_redistribute_source,
 
 DEFUN (no_ospf_redistribute_source,
        no_ospf_redistribute_source_cmd,
-       "no redistribute " FRR_REDIST_STR_OSPFD " [<metric (0-16777214)|metric-type (1-2)|route-map WORD>]",
+       "no redistribute " FRR_REDIST_STR_OSPFD " [{metric (0-16777214)|metric-type (1-2)|route-map WORD}]",
        NO_STR
        REDIST_STR
        FRR_REDIST_HELP_STR_OSPFD
@@ -8337,7 +8368,7 @@ DEFUN (no_ospf_distribute_list_out,
 /* Default information originate. */
 DEFUN (ospf_default_information_originate,
        ospf_default_information_originate_cmd,
-       "default-information originate [<always|metric (0-16777214)|metric-type (1-2)|route-map WORD>]",
+       "default-information originate [{always|metric (0-16777214)|metric-type (1-2)|route-map WORD}]",
        "Control distribution of default information\n"
        "Distribute a default route\n"
        "Always advertise default route\n"
@@ -8360,18 +8391,21 @@ DEFUN (ospf_default_information_originate,
        /* Check whether "always" was specified */
        if (argv_find(argv, argc, "always", &idx))
                default_originate = DEFAULT_ORIGINATE_ALWAYS;
+       idx = 1;
        /* Get metric value */
-       else if (argv_find(argv, argc, "(0-16777214)", &idx)) {
+       if (argv_find(argv, argc, "(0-16777214)", &idx)) {
                if (!str2metric(argv[idx]->arg, &metric))
                        return CMD_WARNING_CONFIG_FAILED;
        }
+       idx = 1;
        /* Get metric type. */
-       else if (argv_find(argv, argc, "(1-2)", &idx)) {
+       if (argv_find(argv, argc, "(1-2)", &idx)) {
                if (!str2metric_type(argv[idx]->arg, &type))
                        return CMD_WARNING_CONFIG_FAILED;
        }
+       idx = 1;
        /* Get route-map */
-       else if (argv_find(argv, argc, "WORD", &idx))
+       if (argv_find(argv, argc, "WORD", &idx))
                ospf_routemap_set(red, argv[idx]->arg);
        else
                ospf_routemap_unset(red);
@@ -8382,7 +8416,7 @@ DEFUN (ospf_default_information_originate,
 
 DEFUN (no_ospf_default_information_originate,
        no_ospf_default_information_originate_cmd,
-       "no default-information originate [<always|metric (0-16777214)|metric-type (1-2)|route-map WORD>]",
+       "no default-information originate [{always|metric (0-16777214)|metric-type (1-2)|route-map WORD}]",
        NO_STR
        "Control distribution of default information\n"
        "Distribute a default route\n"
@@ -8524,6 +8558,10 @@ DEFUN (ospf_distance_ospf,
        VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
        int idx = 0;
 
+       ospf->distance_intra = 0;
+       ospf->distance_inter = 0;
+       ospf->distance_external = 0;
+
        if (argv_find(argv, argc, "intra-area", &idx))
                ospf->distance_intra = atoi(argv[idx + 1]->arg);
        idx = 0;
@@ -9495,9 +9533,9 @@ DEFUN (show_ip_ospf_route,
                        }
 
                        if (uj) {
+                               /* Keep Non-pretty format */
                                vty_out(vty, "%s\n",
-                                       json_object_to_json_string_ext(json,
-                                                 JSON_C_TO_STRING_PRETTY));
+                                       json_object_to_json_string(json));
                                json_object_free(json);
                        }
 
@@ -9521,9 +9559,9 @@ DEFUN (show_ip_ospf_route,
 
        if (ospf) {
                ret = show_ip_ospf_route_common(vty, ospf, json, use_vrf);
+               /* Keep Non-pretty format */
                if (uj)
-                       vty_out(vty, "%s\n", json_object_to_json_string_ext(
-                                            json, JSON_C_TO_STRING_PRETTY));
+                       vty_out(vty, "%s\n", json_object_to_json_string(json));
        }
 
        if (uj)
@@ -9582,7 +9620,7 @@ DEFUN (show_ip_ospf_vrfs,
        for (ALL_LIST_ELEMENTS_RO(om->ospf, node, ospf)) {
                json_object *json_vrf = NULL;
                const char *name = NULL;
-               int vrf_id_ui = 0;
+               int64_t vrf_id_ui = 0;
 
                count++;
 
@@ -9596,7 +9634,8 @@ DEFUN (show_ip_ospf_vrfs,
                else
                        name = ospf->name;
 
-               vrf_id_ui = (ospf->vrf_id == VRF_UNKNOWN) ? -1 : ospf->vrf_id;
+               vrf_id_ui = (ospf->vrf_id == VRF_UNKNOWN) ? -1 :
+                       (int64_t) ospf->vrf_id;
 
                if (uj) {
                        json_object_int_add(json_vrf, "vrfId", vrf_id_ui);
@@ -10201,6 +10240,7 @@ static int config_write_ospf_distribute(struct vty *vty, struct ospf *ospf)
                                if (red->dmetric.value >= 0)
                                        vty_out(vty, " metric %d",
                                                red->dmetric.value);
+
                                if (red->dmetric.type == EXTERNAL_METRIC_TYPE_1)
                                        vty_out(vty, " metric-type 1");
 
index 9fd0c3ed4cc371e177604d9d59e8ec0c61a41513..5eb6842be35cc876fbc59f7ae1ecc42fd4adeb3e 100644 (file)
@@ -44,6 +44,7 @@
                        vty_out(vty,                                           \
                                "%% You can't configure %s to backbone\n",     \
                                NAME);                                         \
+                       return CMD_WARNING;                                \
                }                                                              \
        }
 
index 66be29dbb417e6a591a078c501919d701d1ca8b0..93aa6039082a7d4789e848a36cf2c814cf5ea287 100644 (file)
@@ -441,6 +441,7 @@ void ospf_zebra_add(struct ospf *ospf, struct prefix_ipv4 *p,
                        api_nh->ifindex = path->ifindex;
                        api_nh->type = NEXTHOP_TYPE_IFINDEX;
                }
+               api_nh->vrf_id = ospf->vrf_id;
                count++;
 
                if (IS_DEBUG_OSPF(zebra, ZEBRA_REDISTRIBUTE)) {
index ceb8440eebd9707d07e0bda90ae598abeca3f2c8..86a3293d7110bc4987e5ba0fc3438814eeaf2924 100644 (file)
@@ -32,6 +32,7 @@
 #include "log.h"
 #include "sockunion.h" /* for inet_aton () */
 #include "zclient.h"
+#include "routemap.h"
 #include "plist.h"
 #include "sockopt.h"
 #include "bfd.h"
@@ -159,8 +160,8 @@ void ospf_router_id_update(struct ospf *ospf)
                        struct ospf_lsa *lsa;
 
                        LSDB_LOOP(EXTERNAL_LSDB(ospf), rn, lsa)
-                       if (IS_LSA_SELF(lsa))
-                               ospf_lsa_flush_schedule(ospf, lsa);
+                               if (IS_LSA_SELF(lsa))
+                                       ospf_lsa_flush_schedule(ospf, lsa);
                }
 
                ospf->router_id = router_id;
@@ -183,8 +184,7 @@ void ospf_router_id_update(struct ospf *ospf)
                        struct route_node *rn;
                        struct ospf_lsa *lsa;
 
-                       LSDB_LOOP(EXTERNAL_LSDB(ospf), rn, lsa)
-                       {
+                       LSDB_LOOP (EXTERNAL_LSDB(ospf), rn, lsa) {
                                /* AdvRouter and Router ID is the same. */
                                if (IPV4_ADDR_SAME(&lsa->data->adv_router,
                                                   &ospf->router_id)) {
@@ -241,7 +241,7 @@ static struct ospf *ospf_new(u_short instance, const char *name)
                new->name = XSTRDUP(MTYPE_OSPF_TOP, name);
                vrf = vrf_lookup_by_name(new->name);
                if (IS_DEBUG_OSPF_EVENT)
-                       zlog_debug("%s: Create new ospf instance with vrf_name %s vrf_id %d",
+                       zlog_debug("%s: Create new ospf instance with vrf_name %s vrf_id %u",
                                   __PRETTY_FUNCTION__, name, new->vrf_id);
                if (vrf)
                        ospf_vrf_link(new, vrf);
@@ -555,6 +555,20 @@ void ospf_terminate(void)
        for (ALL_LIST_ELEMENTS(om->ospf, node, nnode, ospf))
                ospf_finish(ospf);
 
+       /* Cleanup route maps */
+       route_map_add_hook(NULL);
+       route_map_delete_hook(NULL);
+       route_map_event_hook(NULL);
+       route_map_finish();
+
+       /* reverse prefix_list_init */
+       prefix_list_add_hook(NULL);
+       prefix_list_delete_hook(NULL);
+       prefix_list_reset();
+
+       /* Cleanup vrf info */
+       ospf_vrf_terminate();
+
        /* Deliberately go back up, hopefully to thread scheduler, as
         * One or more ospf_finish()'s may have deferred shutdown to a timer
         * thread
@@ -596,6 +610,8 @@ static void ospf_finish_final(struct ospf *ospf)
 
        ospf_opaque_type11_lsa_term(ospf);
 
+       ospf_opaque_finish();
+
        ospf_flush_self_originated_lsas_now(ospf);
 
        /* Unregister redistribution */
@@ -693,9 +709,9 @@ static void ospf_finish_final(struct ospf *ospf)
        stream_free(ospf->ibuf);
 
        LSDB_LOOP(OPAQUE_AS_LSDB(ospf), rn, lsa)
-       ospf_discard_from_db(ospf, ospf->lsdb, lsa);
+               ospf_discard_from_db(ospf, ospf->lsdb, lsa);
        LSDB_LOOP(EXTERNAL_LSDB(ospf), rn, lsa)
-       ospf_discard_from_db(ospf, ospf->lsdb, lsa);
+               ospf_discard_from_db(ospf, ospf->lsdb, lsa);
 
        ospf_lsdb_delete_all(ospf->lsdb);
        ospf_lsdb_free(ospf->lsdb);
@@ -830,22 +846,21 @@ static void ospf_area_free(struct ospf_area *area)
 
        /* Free LSDBs. */
        LSDB_LOOP(ROUTER_LSDB(area), rn, lsa)
-       ospf_discard_from_db(area->ospf, area->lsdb, lsa);
+               ospf_discard_from_db(area->ospf, area->lsdb, lsa);
        LSDB_LOOP(NETWORK_LSDB(area), rn, lsa)
-       ospf_discard_from_db(area->ospf, area->lsdb, lsa);
+               ospf_discard_from_db(area->ospf, area->lsdb, lsa);
        LSDB_LOOP(SUMMARY_LSDB(area), rn, lsa)
-       ospf_discard_from_db(area->ospf, area->lsdb, lsa);
+               ospf_discard_from_db(area->ospf, area->lsdb, lsa);
        LSDB_LOOP(ASBR_SUMMARY_LSDB(area), rn, lsa)
-       ospf_discard_from_db(area->ospf, area->lsdb, lsa);
+               ospf_discard_from_db(area->ospf, area->lsdb, lsa);
 
        LSDB_LOOP(NSSA_LSDB(area), rn, lsa)
-       ospf_discard_from_db(area->ospf, area->lsdb, lsa);
+               ospf_discard_from_db(area->ospf, area->lsdb, lsa);
        LSDB_LOOP(OPAQUE_AREA_LSDB(area), rn, lsa)
-       ospf_discard_from_db(area->ospf, area->lsdb, lsa);
+               ospf_discard_from_db(area->ospf, area->lsdb, lsa);
        LSDB_LOOP(OPAQUE_LINK_LSDB(area), rn, lsa)
-       ospf_discard_from_db(area->ospf, area->lsdb, 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);
 
@@ -1031,9 +1046,15 @@ int ospf_network_set(struct ospf *ospf, struct prefix_ipv4 *p,
 
        rn = route_node_get(ospf->networks, (struct prefix *)p);
        if (rn->info) {
-               /* There is already same network statement. */
+               network = rn->info;
                route_unlock_node(rn);
-               return 0;
+
+               if (IPV4_ADDR_SAME(&area_id, &network->area_id)) {
+                       return 1;
+               } else {
+                       /* There is already same network statement. */
+                       return 0;
+               }
        }
 
        rn->info = network = ospf_network_new(area_id);
@@ -2008,7 +2029,7 @@ void ospf_vrf_unlink(struct ospf *ospf, struct vrf *vrf)
 static int ospf_vrf_new(struct vrf *vrf)
 {
        if (IS_DEBUG_OSPF_EVENT)
-               zlog_debug("%s: VRF Created: %s(%d)", __PRETTY_FUNCTION__,
+               zlog_debug("%s: VRF Created: %s(%u)", __PRETTY_FUNCTION__,
                           vrf->name, vrf->vrf_id);
 
        return 0;
@@ -2018,7 +2039,7 @@ static int ospf_vrf_new(struct vrf *vrf)
 static int ospf_vrf_delete(struct vrf *vrf)
 {
        if (IS_DEBUG_OSPF_EVENT)
-               zlog_debug("%s: VRF Deletion: %s(%d)", __PRETTY_FUNCTION__,
+               zlog_debug("%s: VRF Deletion: %s(%u)", __PRETTY_FUNCTION__,
                           vrf->name, vrf->vrf_id);
 
        return 0;
@@ -2031,7 +2052,7 @@ static int ospf_vrf_enable(struct vrf *vrf)
        vrf_id_t old_vrf_id = VRF_DEFAULT;
 
        if (IS_DEBUG_OSPF_EVENT)
-               zlog_debug("%s: VRF %s id %d enabled",
+               zlog_debug("%s: VRF %s id %u enabled",
                           __PRETTY_FUNCTION__, vrf->name, vrf->vrf_id);
 
        ospf = ospf_lookup_by_name(vrf->name);
@@ -2040,7 +2061,7 @@ static int ospf_vrf_enable(struct vrf *vrf)
                /* We have instance configured, link to VRF and make it "up". */
                ospf_vrf_link(ospf, vrf);
                if (IS_DEBUG_OSPF_EVENT)
-                       zlog_debug("%s: ospf linked to vrf %s vrf_id %d (old id %d)",
+                       zlog_debug("%s: ospf linked to vrf %s vrf_id %u (old id %u)",
                                   __PRETTY_FUNCTION__, vrf->name, ospf->vrf_id,
                                   old_vrf_id);
 
index 5cb8ca85bc9acf93b0493fef9104e2700dc45aff..6954660e0247f11d589de44626396b2777103919 100644 (file)
@@ -240,6 +240,7 @@ struct ospf {
        struct thread *t_external_lsa;      /* AS-external-LSA origin timer. */
        struct thread
                *t_opaque_lsa_self; /* Type-11 Opaque-LSAs origin event. */
+       struct thread *t_sr_update; /* Segment Routing update timer */
 
        unsigned int maxage_delay;      /* Delay on Maxage remover timer, sec */
        struct thread *t_maxage;        /* MaxAge LSA remover timer. */
index e063415fbdfa6f03ebf4f55ff9b1f7ba2ef3978f..9f04260366a1598d20b553e181e5f0b01272e50c 100644 (file)
@@ -20,6 +20,7 @@ ospfd_libfrrospf_a_SOURCES = \
        ospfd/ospf_bfd.c \
        ospfd/ospf_dump.c \
        ospfd/ospf_dump_api.c \
+       ospfd/ospf_ext.c \
        ospfd/ospf_flood.c \
        ospfd/ospf_ia.c \
        ospfd/ospf_interface.c \
@@ -36,6 +37,7 @@ ospfd_libfrrospf_a_SOURCES = \
        ospfd/ospf_route.c \
        ospfd/ospf_routemap.c \
        ospfd/ospf_spf.c \
+       ospfd/ospf_sr.c \
        ospfd/ospf_te.c \
        ospfd/ospf_vty.c \
        ospfd/ospf_zebra.c \
@@ -66,6 +68,7 @@ noinst_HEADERS += \
        ospfd/ospf_apiserver.h \
        ospfd/ospf_ase.h \
        ospfd/ospf_bfd.h \
+       ospfd/ospf_ext.h \
        ospfd/ospf_flood.h \
        ospfd/ospf_ia.h \
        ospfd/ospf_interface.h \
@@ -76,6 +79,7 @@ noinst_HEADERS += \
        ospfd/ospf_ri.h \
        ospfd/ospf_route.h \
        ospfd/ospf_spf.h \
+       ospfd/ospf_sr.h \
        ospfd/ospf_te.h \
        ospfd/ospf_vty.h \
        ospfd/ospf_zebra.h \
index e23216b058a7de476952e7b25f8219b74fdb61a3..1f56cfaecdabd2dac7344f859ef8710ce6b03079 100644 (file)
@@ -2,6 +2,7 @@
 Makefile.in
 libpim.a
 pimd
+mtracebis
 test_igmpv3_join
 tags
 TAGS
index c545eca56e45d034132b5dac63c3496416c7c82b..6f2e020bd87f5c146d5c5574fa55790f7671cbcd 100644 (file)
@@ -59,6 +59,7 @@ debug commands:
        clear ip pim interfaces         Reset PIM interfaces
        clear ip pim oil                        Rescan PIM OIL (output interface list)
        debug igmp                      IGMP protocol activity
+       debug mtrace                    Mtrace protocol activity
        debug mroute                    PIM interaction with kernel MFC cache
        debug pim                       PIM protocol activity
        debug pim zebra                 ZEBRA protocol activity
@@ -76,4 +77,6 @@ statistics commands:
        pimd:
        show memory pim         PIM memory statistics
 
+vtysh:
+       mtrace                  Multicast traceroute
 -x-
diff --git a/pimd/mtracebis.c b/pimd/mtracebis.c
new file mode 100644 (file)
index 0000000..2032cdc
--- /dev/null
@@ -0,0 +1,371 @@
+/*
+ * Multicast Traceroute for FRRouting
+ * Copyright (C) 2018  Mladen Sablic
+ *
+ * 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
+ */
+
+#ifdef __linux__
+
+#include "pim_igmp_mtrace.h"
+
+#include "checksum.h"
+#include "mtracebis_routeget.h"
+
+#include <sys/select.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <net/if.h>
+
+#define MTRACEBIS_VERSION "0.1"
+#define MTRACE_TIMEOUT (5)
+
+#define IP_HDR_LEN (sizeof(struct ip))
+#define IP_RA_LEN (4)
+#define MTRACE_BUF_LEN (MTRACE_HDR_SIZE + (MTRACE_MAX_HOPS * MTRACE_RSP_SIZE))
+#define IP_AND_MTRACE_BUF_LEN (IP_HDR_LEN + IP_RA_LEN + MTRACE_BUF_LEN)
+
+static const char *progname;
+static void usage(void)
+{
+       fprintf(stderr, "Usage : %s <multicast source>\n", progname);
+}
+static void version(void)
+{
+       fprintf(stderr, "%s %s\n", progname, MTRACEBIS_VERSION);
+}
+
+static int send_query(int fd, struct in_addr to_addr,
+                     struct igmp_mtrace *mtrace)
+{
+       struct sockaddr_in to;
+       socklen_t tolen;
+       int sent;
+
+       memset(&to, 0, sizeof(to));
+       to.sin_family = AF_INET;
+       to.sin_addr = to_addr;
+       tolen = sizeof(to);
+
+       sent = sendto(fd, (char *)mtrace, sizeof(*mtrace), MSG_DONTWAIT,
+                     (struct sockaddr *)&to, tolen);
+
+       if (sent < 1)
+               return -1;
+       return 0;
+}
+
+static void print_query(struct igmp_mtrace *mtrace)
+{
+       char src_str[INET_ADDRSTRLEN];
+       char dst_str[INET_ADDRSTRLEN];
+       char grp_str[INET_ADDRSTRLEN];
+
+       printf("* Mtrace from %s to %s via group %s\n",
+              inet_ntop(AF_INET, &mtrace->src_addr, src_str, sizeof(src_str)),
+              inet_ntop(AF_INET, &mtrace->dst_addr, dst_str, sizeof(dst_str)),
+              inet_ntop(AF_INET, &mtrace->grp_addr, grp_str, sizeof(grp_str)));
+}
+
+static int recv_response(int fd, long msec, int *hops)
+{
+       int recvd;
+       char mtrace_buf[IP_AND_MTRACE_BUF_LEN];
+       struct ip *ip;
+       struct igmp_mtrace *mtrace;
+       int mtrace_len;
+       int responses;
+       int i;
+       u_short sum;
+
+       recvd = recvfrom(fd, mtrace_buf, IP_AND_MTRACE_BUF_LEN, 0, NULL, 0);
+
+       if (recvd < 1) {
+               fprintf(stderr, "recvfrom error: %s\n", strerror(errno));
+               return -1;
+       }
+
+       if (recvd < (int)sizeof(struct ip)) {
+               fprintf(stderr, "no ip header\n");
+               return -1;
+       }
+
+       ip = (struct ip *)mtrace_buf;
+
+       if (ip->ip_v != 4) {
+               fprintf(stderr, "IP not version 4\n");
+               return -1;
+       }
+
+       sum = ip->ip_sum;
+       ip->ip_sum = 0;
+
+       if (sum != in_cksum(ip, ip->ip_hl * 4))
+               return -1;
+
+       mtrace = (struct igmp_mtrace *)(mtrace_buf + (4 * ip->ip_hl));
+
+       mtrace_len = ntohs(ip->ip_len) - ip->ip_hl * 4;
+
+       if (mtrace_len < (int)MTRACE_HDR_SIZE)
+               return -1;
+
+       sum = mtrace->checksum;
+       mtrace->checksum = 0;
+       if (sum != in_cksum(mtrace, mtrace_len)) {
+               fprintf(stderr, "mtrace checksum wrong\n");
+               return -1;
+       }
+
+       if (mtrace->type != PIM_IGMP_MTRACE_RESPONSE)
+               return -1;
+
+
+       responses = mtrace_len - sizeof(struct igmp_mtrace);
+       responses /= sizeof(struct igmp_mtrace_rsp);
+
+       printf("%ld ms received responses from %d hops.\n", msec, responses);
+
+       if (hops)
+               *hops = responses;
+
+       for (i = 0; i < responses; i++) {
+               struct igmp_mtrace_rsp *rsp = &mtrace->rsp[i];
+
+               if (rsp->fwd_code != 0)
+                       printf("-%d fwd. code 0x%2x.\n", i, rsp->fwd_code);
+       }
+
+       return 0;
+}
+
+static int wait_for_response(int fd, int *hops)
+{
+       fd_set readfds;
+       struct timeval timeout;
+       int ret = -1;
+       long msec, rmsec, tmsec;
+
+       FD_ZERO(&readfds);
+       FD_SET(fd, &readfds);
+
+       memset(&timeout, 0, sizeof(timeout));
+
+       timeout.tv_sec = MTRACE_TIMEOUT;
+
+       tmsec = timeout.tv_sec * 1000 + timeout.tv_usec / 1000;
+       do {
+               ret = select(fd + 1, &readfds, NULL, NULL, &timeout);
+               if (ret <= 0)
+                       return ret;
+               rmsec = timeout.tv_sec * 1000 + timeout.tv_usec / 1000;
+               msec = tmsec - rmsec;
+       } while (recv_response(fd, msec, hops) != 0);
+
+       return ret;
+}
+
+int main(int argc, char *const argv[])
+{
+       struct in_addr mc_source;
+       struct in_addr iface_addr;
+       struct in_addr gw_addr;
+       struct in_addr mtrace_addr;
+       struct igmp_mtrace mtrace;
+       int hops = 255;
+       int rhops;
+       int maxhops = 255;
+       int perhop = 3;
+       int ifindex;
+       int unicast = 1;
+       int ttl = 64;
+       int fd = -1;
+       int ret = -1;
+       int c;
+       int i, j;
+       char ifname[IF_NAMESIZE];
+       char ip_str[INET_ADDRSTRLEN];
+
+       mtrace_addr.s_addr = inet_addr("224.0.1.32");
+
+       uid_t uid = getuid();
+
+       if (uid != 0) {
+               printf("must run as root\n");
+               exit(EXIT_FAILURE);
+       }
+
+       if (argc <= 0)
+               progname = "mtracebis";
+       else
+               progname = argv[0];
+
+       if (argc != 2) {
+               usage();
+               exit(EXIT_FAILURE);
+       }
+
+       while (1) {
+               static struct option long_options[] = {
+                       {"help", no_argument, 0, 'h'},
+                       {"version", no_argument, 0, 'v'},
+                       {0, 0, 0, 0} };
+               int option_index = 0;
+
+               c = getopt_long(argc, argv, "vh", long_options, &option_index);
+
+               if (c == -1)
+                       break;
+
+               switch (c) {
+               case 'h':
+                       usage();
+                       exit(0);
+               case 'v':
+                       version();
+                       exit(0);
+               default:
+                       usage();
+                       exit(EXIT_FAILURE);
+               }
+       }
+       if (inet_pton(AF_INET, argv[1], &mc_source) != 1) {
+               usage();
+               fprintf(stderr, "%s: %s not a valid IPv4 address\n", argv[0],
+                       argv[1]);
+               exit(EXIT_FAILURE);
+       }
+
+       ifindex = routeget(mc_source, &iface_addr, &gw_addr);
+       if (ifindex < 0) {
+               fprintf(stderr, "%s: failed to get route to source %s\n",
+                       argv[0], argv[1]);
+               exit(EXIT_FAILURE);
+       }
+
+       if (if_indextoname(ifindex, ifname) == NULL) {
+               fprintf(stderr, "%s: if_indextoname error: %s\n", argv[0],
+                       strerror(errno));
+               exit(EXIT_FAILURE);
+       }
+
+       /* zero mtrace struct */
+       memset((char *)&mtrace, 0, sizeof(mtrace));
+
+       /* set up query */
+       mtrace.type = PIM_IGMP_MTRACE_QUERY_REQUEST;
+       mtrace.hops = hops;
+       mtrace.checksum = 0;
+       mtrace.grp_addr.s_addr = 0;
+       mtrace.src_addr = mc_source;
+       mtrace.dst_addr = iface_addr;
+       mtrace.rsp_addr = unicast ? iface_addr : mtrace_addr;
+       mtrace.rsp_ttl = ttl;
+       mtrace.qry_id = 0xffffff & time(NULL);
+
+       mtrace.checksum = in_cksum(&mtrace, sizeof(mtrace));
+
+       fd = socket(AF_INET, SOCK_RAW, IPPROTO_IGMP);
+
+       if (fd < 1) {
+               fprintf(stderr, "%s: socket error: %s\n", argv[0],
+                       strerror(errno));
+               exit(EXIT_FAILURE);
+       }
+
+       ret = setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, ifname,
+                        strlen(ifname));
+
+       if (ret < 0) {
+               fprintf(stderr, "%s: setsockopt error: %s\n", argv[0],
+                       strerror(errno));
+               ret = EXIT_FAILURE;
+               goto close_fd;
+       }
+
+       print_query(&mtrace);
+       if (send_query(fd, gw_addr, &mtrace) < 0) {
+               fprintf(stderr, "%s: sendto error: %s\n", argv[0],
+                       strerror(errno));
+               ret = EXIT_FAILURE;
+               goto close_fd;
+       }
+       printf("Querying full reverse path...\n");
+       ret = wait_for_response(fd, NULL);
+       if (ret > 0) {
+               ret = 0;
+               goto close_fd;
+       }
+       if (ret < 0) {
+               fprintf(stderr, "%s: select error: %s\n", argv[0],
+                       strerror(errno));
+               ret = EXIT_FAILURE;
+               goto close_fd;
+       }
+       printf(" * ");
+       printf("switching to hop-by-hop:\n");
+       printf("%3d  ? (%s)\n", 0,
+              inet_ntop(AF_INET, &mtrace.dst_addr, ip_str, sizeof(ip_str)));
+       for (i = 1; i < maxhops; i++) {
+               printf("%3d ", -i);
+               mtrace.hops = i;
+               for (j = 0; j < perhop; j++) {
+                       mtrace.qry_id++;
+                       mtrace.checksum = 0;
+                       mtrace.checksum = in_cksum(&mtrace, sizeof(mtrace));
+                       if (send_query(fd, gw_addr, &mtrace) < 0) {
+                               fprintf(stderr, "%s: sendto error: %s\n",
+                                       argv[0], strerror(errno));
+                               ret = EXIT_FAILURE;
+                               goto close_fd;
+                       }
+                       ret = wait_for_response(fd, &rhops);
+                       if (ret > 0) {
+                               if (i > rhops) {
+                                       ret = 0;
+                                       goto close_fd;
+                               }
+                               break;
+                       }
+                       printf(" *");
+               }
+               if (ret <= 0)
+                       printf("\n");
+       }
+       ret = 0;
+close_fd:
+       close(fd);
+       exit(ret);
+}
+
+#else /* __linux__ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+int main(int argc, char *argv[])
+{
+       printf("%s implemented only for GNU/Linux\n", argv[0]);
+       exit(0);
+}
+
+#endif /* __linux__ */
diff --git a/pimd/mtracebis_netlink.c b/pimd/mtracebis_netlink.c
new file mode 100644 (file)
index 0000000..42b80b2
--- /dev/null
@@ -0,0 +1,700 @@
+/*
+ * libnetlink.c        RTnetlink service routines.
+ *
+ *             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.
+ *
+ * Authors:    Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
+ *
+ */
+
+#ifdef __linux__
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <fcntl.h>
+#include <net/if_arp.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <string.h>
+#include <errno.h>
+#include <time.h>
+#include <sys/uio.h>
+#include <assert.h>
+
+#include "mtracebis_netlink.h"
+
+int rcvbuf = 1024 * 1024;
+
+void rtnl_close(struct rtnl_handle *rth)
+{
+       if (rth->fd >= 0) {
+               close(rth->fd);
+               rth->fd = -1;
+       }
+}
+
+int rtnl_open_byproto(struct rtnl_handle *rth, unsigned subscriptions,
+                     int protocol)
+{
+       socklen_t addr_len;
+       int sndbuf = 32768;
+
+       memset(rth, 0, sizeof(*rth));
+
+       rth->fd = socket(AF_NETLINK, SOCK_RAW, protocol);
+       if (rth->fd < 0) {
+               perror("Cannot open netlink socket");
+               return -1;
+       }
+
+       if (setsockopt(rth->fd,SOL_SOCKET,SO_SNDBUF,&sndbuf,sizeof(sndbuf)) < 0) {
+               perror("SO_SNDBUF");
+               return -1;
+       }
+
+       if (setsockopt(rth->fd,SOL_SOCKET,SO_RCVBUF,&rcvbuf,sizeof(rcvbuf)) < 0) {
+               perror("SO_RCVBUF");
+               return -1;
+       }
+
+       memset(&rth->local, 0, sizeof(rth->local));
+       rth->local.nl_family = AF_NETLINK;
+       rth->local.nl_groups = subscriptions;
+
+       if (bind(rth->fd, (struct sockaddr*)&rth->local, sizeof(rth->local)) < 0) {
+               perror("Cannot bind netlink socket");
+               return -1;
+       }
+       addr_len = sizeof(rth->local);
+       if (getsockname(rth->fd, (struct sockaddr*)&rth->local, &addr_len) < 0) {
+               perror("Cannot getsockname");
+               return -1;
+       }
+       if (addr_len != sizeof(rth->local)) {
+               fprintf(stderr, "Wrong address length %d\n", addr_len);
+               return -1;
+       }
+       if (rth->local.nl_family != AF_NETLINK) {
+               fprintf(stderr, "Wrong address family %d\n", rth->local.nl_family);
+               return -1;
+       }
+       rth->seq = time(NULL);
+       return 0;
+}
+
+int rtnl_open(struct rtnl_handle *rth, unsigned subscriptions)
+{
+       return rtnl_open_byproto(rth, subscriptions, NETLINK_ROUTE);
+}
+
+int rtnl_wilddump_request(struct rtnl_handle *rth, int family, int type)
+{
+       struct {
+               struct nlmsghdr nlh;
+               struct rtgenmsg g;
+       } req;
+
+       memset(&req, 0, sizeof(req));
+       req.nlh.nlmsg_len = sizeof(req);
+       req.nlh.nlmsg_type = type;
+       req.nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST;
+       req.nlh.nlmsg_pid = 0;
+       req.nlh.nlmsg_seq = rth->dump = ++rth->seq;
+       req.g.rtgen_family = family;
+
+       return send(rth->fd, (void*)&req, sizeof(req), 0);
+}
+
+int rtnl_send(struct rtnl_handle *rth, const char *buf, int len)
+{
+       return send(rth->fd, buf, len, 0);
+}
+
+int rtnl_send_check(struct rtnl_handle *rth, const char *buf, int len)
+{
+       struct nlmsghdr *h;
+       int status;
+       char resp[1024];
+
+       status = send(rth->fd, buf, len, 0);
+       if (status < 0)
+               return status;
+
+       /* Check for immediate errors */
+       status = recv(rth->fd, resp, sizeof(resp), MSG_DONTWAIT|MSG_PEEK);
+       if (status < 0) {
+               if (errno == EAGAIN)
+                       return 0;
+               return -1;
+       }
+
+       for (h = (struct nlmsghdr *)resp; NLMSG_OK(h, (uint32_t)status);
+            h = NLMSG_NEXT(h, status)) {
+               if (h->nlmsg_type == NLMSG_ERROR) {
+                       struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h);
+                       if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr)))
+                               fprintf(stderr, "ERROR truncated\n");
+                       else
+                               errno = -err->error;
+                       return -1;
+               }
+       }
+
+       return 0;
+}
+
+int rtnl_dump_request(struct rtnl_handle *rth, int type, void *req, int len)
+{
+       struct nlmsghdr nlh;
+       struct sockaddr_nl nladdr;
+       struct iovec iov[2] = {
+               { .iov_base = &nlh, .iov_len = sizeof(nlh) },
+               { .iov_base = req, .iov_len = len }
+       };
+       struct msghdr msg = {
+               .msg_name = &nladdr,
+               .msg_namelen =  sizeof(nladdr),
+               .msg_iov = iov,
+               .msg_iovlen = 2,
+       };
+
+       memset(&nladdr, 0, sizeof(nladdr));
+       nladdr.nl_family = AF_NETLINK;
+
+       nlh.nlmsg_len = NLMSG_LENGTH(len);
+       nlh.nlmsg_type = type;
+       nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST;
+       nlh.nlmsg_pid = 0;
+       nlh.nlmsg_seq = rth->dump = ++rth->seq;
+
+       return sendmsg(rth->fd, &msg, 0);
+}
+
+int rtnl_dump_filter_l(struct rtnl_handle *rth,
+                      const struct rtnl_dump_filter_arg *arg)
+{
+       struct sockaddr_nl nladdr;
+       struct iovec iov;
+       struct msghdr msg = {
+               .msg_name = &nladdr,
+               .msg_namelen = sizeof(nladdr),
+               .msg_iov = &iov,
+               .msg_iovlen = 1,
+       };
+       char buf[16384];
+
+       iov.iov_base = buf;
+       while (1) {
+               int status;
+               const struct rtnl_dump_filter_arg *a;
+               int found_done = 0;
+               int msglen = 0;
+
+               iov.iov_len = sizeof(buf);
+               status = recvmsg(rth->fd, &msg, 0);
+
+               if (status < 0) {
+                       if (errno == EINTR || errno == EAGAIN)
+                               continue;
+                       fprintf(stderr, "netlink receive error %s (%d)\n",
+                               strerror(errno), errno);
+                       return -1;
+               }
+
+               if (status == 0) {
+                       fprintf(stderr, "EOF on netlink\n");
+                       return -1;
+               }
+
+               for (a = arg; a->filter; a++) {
+                       struct nlmsghdr *h = (struct nlmsghdr*)buf;
+                       msglen = status;
+
+                       while (NLMSG_OK(h, (uint32_t)msglen)) {
+                               int err;
+
+                               if (nladdr.nl_pid != 0 ||
+                                   h->nlmsg_pid != rth->local.nl_pid ||
+                                   h->nlmsg_seq != rth->dump) {
+                                       if (a->junk) {
+                                               err = a->junk(&nladdr, h,
+                                                             a->arg2);
+                                               if (err < 0)
+                                                       return err;
+                                       }
+                                       goto skip_it;
+                               }
+
+                               if (h->nlmsg_type == NLMSG_DONE) {
+                                       found_done = 1;
+                                       break; /* process next filter */
+                               }
+                               if (h->nlmsg_type == NLMSG_ERROR) {
+                                       struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h);
+                                       if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) {
+                                               fprintf(stderr,
+                                                       "ERROR truncated\n");
+                                       } else {
+                                               errno = -err->error;
+                                               perror("RTNETLINK answers");
+                                       }
+                                       return -1;
+                               }
+                               err = a->filter(&nladdr, h, a->arg1);
+                               if (err < 0)
+                                       return err;
+
+skip_it:
+                               h = NLMSG_NEXT(h, msglen);
+                       }
+               }
+
+               if (found_done)
+                       return 0;
+
+               if (msg.msg_flags & MSG_TRUNC) {
+                       fprintf(stderr, "Message truncated\n");
+                       continue;
+               }
+               if (msglen) {
+                       fprintf(stderr, "!!!Remnant of size %d\n", msglen);
+                       exit(1);
+               }
+       }
+}
+
+int rtnl_dump_filter(struct rtnl_handle *rth,
+                    rtnl_filter_t filter,
+                    void *arg1,
+                    rtnl_filter_t junk,
+                    void *arg2)
+{
+       const struct rtnl_dump_filter_arg a[2] = {
+               { .filter = filter, .arg1 = arg1, .junk = junk, .arg2 = arg2 },
+               { .filter = NULL,   .arg1 = NULL, .junk = NULL, .arg2 = NULL }
+       };
+
+       return rtnl_dump_filter_l(rth, a);
+}
+
+int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, pid_t peer,
+             unsigned groups, struct nlmsghdr *answer,
+             rtnl_filter_t junk,
+             void *jarg)
+{
+       int status;
+       unsigned seq;
+       struct nlmsghdr *h;
+       struct sockaddr_nl nladdr;
+       struct iovec iov = {
+               .iov_base = (void*) n,
+               .iov_len = n->nlmsg_len
+       };
+       struct msghdr msg = {
+               .msg_name = &nladdr,
+               .msg_namelen = sizeof(nladdr),
+               .msg_iov = &iov,
+               .msg_iovlen = 1,
+       };
+       char   buf[16384];
+
+       memset(&nladdr, 0, sizeof(nladdr));
+       nladdr.nl_family = AF_NETLINK;
+       nladdr.nl_pid = peer;
+       nladdr.nl_groups = groups;
+
+       n->nlmsg_seq = seq = ++rtnl->seq;
+
+       if (answer == NULL)
+               n->nlmsg_flags |= NLM_F_ACK;
+
+       status = sendmsg(rtnl->fd, &msg, 0);
+
+       if (status < 0) {
+               perror("Cannot talk to rtnetlink");
+               return -1;
+       }
+
+       memset(buf,0,sizeof(buf));
+
+       iov.iov_base = buf;
+
+       while (1) {
+               iov.iov_len = sizeof(buf);
+               status = recvmsg(rtnl->fd, &msg, 0);
+
+               if (status < 0) {
+                       if (errno == EINTR || errno == EAGAIN)
+                               continue;
+                       fprintf(stderr, "netlink receive error %s (%d)\n",
+                               strerror(errno), errno);
+                       return -1;
+               }
+               if (status == 0) {
+                       fprintf(stderr, "EOF on netlink\n");
+                       return -1;
+               }
+               if (msg.msg_namelen != sizeof(nladdr)) {
+                       fprintf(stderr, "sender address length == %d\n", msg.msg_namelen);
+                       exit(1);
+               }
+               for (h = (struct nlmsghdr*)buf; status >= (int)sizeof(*h); ) {
+                       int err;
+                       int len = h->nlmsg_len;
+                       int l = len - sizeof(*h);
+
+                       if (l<0 || len>status) {
+                               if (msg.msg_flags & MSG_TRUNC) {
+                                       fprintf(stderr, "Truncated message\n");
+                                       return -1;
+                               }
+                               fprintf(stderr, "!!!malformed message: len=%d\n", len);
+                               exit(1);
+                       }
+
+                       if ((int)nladdr.nl_pid != peer ||
+                           h->nlmsg_pid != rtnl->local.nl_pid ||
+                           h->nlmsg_seq != seq) {
+                               if (junk) {
+                                       err = junk(&nladdr, h, jarg);
+                                       if (err < 0)
+                                               return err;
+                               }
+                               /* Don't forget to skip that message. */
+                               status -= NLMSG_ALIGN(len);
+                               h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len));
+                               continue;
+                       }
+
+                       if (h->nlmsg_type == NLMSG_ERROR) {
+                               struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h);
+                               if (l < (int)sizeof(struct nlmsgerr)) {
+                                       fprintf(stderr, "ERROR truncated\n");
+                               } else {
+                                       errno = -err->error;
+                                       if (errno == 0) {
+                                               if (answer)
+                                                       memcpy(answer, h, h->nlmsg_len);
+                                               return 0;
+                                       }
+                                       perror("RTNETLINK answers");
+                               }
+                               return -1;
+                       }
+                       if (answer) {
+                               memcpy(answer, h, h->nlmsg_len);
+                               return 0;
+                       }
+
+                       fprintf(stderr, "Unexpected reply!!!\n");
+
+                       status -= NLMSG_ALIGN(len);
+                       h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len));
+               }
+               if (msg.msg_flags & MSG_TRUNC) {
+                       fprintf(stderr, "Message truncated\n");
+                       continue;
+               }
+               if (status) {
+                       fprintf(stderr, "!!!Remnant of size %d\n", status);
+                       exit(1);
+               }
+       }
+}
+
+int rtnl_listen(struct rtnl_handle *rtnl,
+               rtnl_filter_t handler,
+               void *jarg)
+{
+       int status;
+       struct nlmsghdr *h;
+       struct sockaddr_nl nladdr;
+       struct iovec iov;
+       struct msghdr msg = {
+               .msg_name = &nladdr,
+               .msg_namelen = sizeof(nladdr),
+               .msg_iov = &iov,
+               .msg_iovlen = 1,
+       };
+       char   buf[8192];
+
+       memset(&nladdr, 0, sizeof(nladdr));
+       nladdr.nl_family = AF_NETLINK;
+       nladdr.nl_pid = 0;
+       nladdr.nl_groups = 0;
+
+       iov.iov_base = buf;
+       while (1) {
+               iov.iov_len = sizeof(buf);
+               status = recvmsg(rtnl->fd, &msg, 0);
+
+               if (status < 0) {
+                       if (errno == EINTR || errno == EAGAIN)
+                               continue;
+                       fprintf(stderr, "netlink receive error %s (%d)\n",
+                               strerror(errno), errno);
+                       if (errno == ENOBUFS)
+                               continue;
+                       return -1;
+               }
+               if (status == 0) {
+                       fprintf(stderr, "EOF on netlink\n");
+                       return -1;
+               }
+               if (msg.msg_namelen != sizeof(nladdr)) {
+                       fprintf(stderr, "Sender address length == %d\n", msg.msg_namelen);
+                       exit(1);
+               }
+               for (h =(struct nlmsghdr*)buf; status >= (int)sizeof(*h); ) {
+                       int err;
+                       int len = h->nlmsg_len;
+                       int l = len - sizeof(*h);
+
+                       if (l<0 || len>status) {
+                               if (msg.msg_flags & MSG_TRUNC) {
+                                       fprintf(stderr, "Truncated message\n");
+                                       return -1;
+                               }
+                               fprintf(stderr, "!!!malformed message: len=%d\n", len);
+                               exit(1);
+                       }
+
+                       err = handler(&nladdr, h, jarg);
+                       if (err < 0)
+                               return err;
+
+                       status -= NLMSG_ALIGN(len);
+                       h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len));
+               }
+               if (msg.msg_flags & MSG_TRUNC) {
+                       fprintf(stderr, "Message truncated\n");
+                       continue;
+               }
+               if (status) {
+                       fprintf(stderr, "!!!Remnant of size %d\n", status);
+                       exit(1);
+               }
+       }
+}
+
+int rtnl_from_file(FILE *rtnl, rtnl_filter_t handler,
+                  void *jarg)
+{
+       int status;
+       struct sockaddr_nl nladdr;
+       char   buf[8192];
+       struct nlmsghdr *h = (void*)buf;
+
+       memset(&nladdr, 0, sizeof(nladdr));
+       nladdr.nl_family = AF_NETLINK;
+       nladdr.nl_pid = 0;
+       nladdr.nl_groups = 0;
+
+       while (1) {
+               int err, len;
+               int l;
+
+               status = fread(&buf, 1, sizeof(*h), rtnl);
+
+               if (status < 0) {
+                       if (errno == EINTR)
+                               continue;
+                       perror("rtnl_from_file: fread");
+                       return -1;
+               }
+               if (status == 0)
+                       return 0;
+
+               len = h->nlmsg_len;
+               l = len - sizeof(*h);
+
+               if (l<0 || len>(int)sizeof(buf)) {
+                       fprintf(stderr, "!!!malformed message: len=%d @%lu\n",
+                               len, ftell(rtnl));
+                       return -1;
+               }
+
+               status = fread(NLMSG_DATA(h), 1, NLMSG_ALIGN(l), rtnl);
+
+               if (status < 0) {
+                       perror("rtnl_from_file: fread");
+                       return -1;
+               }
+               if (status < l) {
+                       fprintf(stderr, "rtnl-from_file: truncated message\n");
+                       return -1;
+               }
+
+               err = handler(&nladdr, h, jarg);
+               if (err < 0)
+                       return err;
+       }
+}
+
+int addattr32(struct nlmsghdr *n, int maxlen, int type, __u32 data)
+{
+       int len = RTA_LENGTH(4);
+       struct rtattr *rta;
+       if ((int)(NLMSG_ALIGN(n->nlmsg_len) + len) > maxlen) {
+               fprintf(stderr,"addattr32: Error! max allowed bound %d exceeded\n",maxlen);
+               return -1;
+       }
+       rta = NLMSG_TAIL(n);
+       rta->rta_type = type;
+       rta->rta_len = len;
+       memcpy(RTA_DATA(rta), &data, 4);
+       n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + len;
+       return 0;
+}
+
+int addattr_l(struct nlmsghdr *n, int maxlen, int type, const void *data,
+             int alen)
+{
+       int len = RTA_LENGTH(alen);
+       struct rtattr *rta;
+
+       if ((int)(NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len)) > maxlen) {
+               fprintf(stderr, "addattr_l ERROR: message exceeded bound of %d\n",maxlen);
+               return -1;
+       }
+       rta = NLMSG_TAIL(n);
+       rta->rta_type = type;
+       rta->rta_len = len;
+
+       if (data)
+               memcpy(RTA_DATA(rta), data, alen);
+       else
+               assert(alen == 0);
+
+       n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len);
+       return 0;
+}
+
+int addraw_l(struct nlmsghdr *n, int maxlen, const void *data, int len)
+{
+       if ((int)(NLMSG_ALIGN(n->nlmsg_len) + NLMSG_ALIGN(len)) > maxlen) {
+               fprintf(stderr, "addraw_l ERROR: message exceeded bound of %d\n",maxlen);
+               return -1;
+       }
+
+       memcpy(NLMSG_TAIL(n), data, len);
+       memset((uint8_t *) NLMSG_TAIL(n) + len, 0, NLMSG_ALIGN(len) - len);
+       n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + NLMSG_ALIGN(len);
+       return 0;
+}
+
+struct rtattr *addattr_nest(struct nlmsghdr *n, int maxlen, int type)
+{
+       struct rtattr *nest = NLMSG_TAIL(n);
+
+       addattr_l(n, maxlen, type, NULL, 0);
+       return nest;
+}
+
+int addattr_nest_end(struct nlmsghdr *n, struct rtattr *nest)
+{
+       nest->rta_len = (uint8_t *)NLMSG_TAIL(n) - (uint8_t *)nest;
+       return n->nlmsg_len;
+}
+
+struct rtattr *addattr_nest_compat(struct nlmsghdr *n, int maxlen, int type,
+                                  const void *data, int len)
+{
+       struct rtattr *start = NLMSG_TAIL(n);
+
+       addattr_l(n, maxlen, type, data, len);
+       addattr_nest(n, maxlen, type);
+       return start;
+}
+
+int addattr_nest_compat_end(struct nlmsghdr *n, struct rtattr *start)
+{
+       struct rtattr *nest = start + NLMSG_ALIGN(start->rta_len);
+
+       start->rta_len = (uint8_t *)NLMSG_TAIL(n) - (uint8_t *)start;
+       addattr_nest_end(n, nest);
+       return n->nlmsg_len;
+}
+
+int rta_addattr32(struct rtattr *rta, int maxlen, int type, __u32 data)
+{
+       int len = RTA_LENGTH(4);
+       struct rtattr *subrta;
+
+       if ((int)(RTA_ALIGN(rta->rta_len) + len) > maxlen) {
+               fprintf(stderr,"rta_addattr32: Error! max allowed bound %d exceeded\n",maxlen);
+               return -1;
+       }
+       subrta = (struct rtattr*)(((char*)rta) + RTA_ALIGN(rta->rta_len));
+       subrta->rta_type = type;
+       subrta->rta_len = len;
+       memcpy(RTA_DATA(subrta), &data, 4);
+       rta->rta_len = NLMSG_ALIGN(rta->rta_len) + len;
+       return 0;
+}
+
+int rta_addattr_l(struct rtattr *rta, int maxlen, int type,
+                 const void *data, int alen)
+{
+       struct rtattr *subrta;
+       int len = RTA_LENGTH(alen);
+
+       if ((int)(RTA_ALIGN(rta->rta_len) + RTA_ALIGN(len)) > maxlen) {
+               fprintf(stderr,"rta_addattr_l: Error! max allowed bound %d exceeded\n",maxlen);
+               return -1;
+       }
+       subrta = (struct rtattr*)(((char*)rta) + RTA_ALIGN(rta->rta_len));
+       subrta->rta_type = type;
+       subrta->rta_len = len;
+       memcpy(RTA_DATA(subrta), data, alen);
+       rta->rta_len = NLMSG_ALIGN(rta->rta_len) + RTA_ALIGN(len);
+       return 0;
+}
+
+int parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len)
+{
+       memset(tb, 0, sizeof(struct rtattr *) * (max + 1));
+       while (RTA_OK(rta, len)) {
+               if ((rta->rta_type <= max) && (!tb[rta->rta_type]))
+                       tb[rta->rta_type] = rta;
+               rta = RTA_NEXT(rta,len);
+       }
+       if (len)
+               fprintf(stderr, "!!!Deficit %d, rta_len=%d\n", len, rta->rta_len);
+       return 0;
+}
+
+int parse_rtattr_byindex(struct rtattr *tb[], int max, struct rtattr *rta, int len)
+{
+       int i = 0;
+
+       memset(tb, 0, sizeof(struct rtattr *) * max);
+       while (RTA_OK(rta, len)) {
+               if (rta->rta_type <= max && i < max)
+                       tb[i++] = rta;
+               rta = RTA_NEXT(rta,len);
+       }
+       if (len)
+               fprintf(stderr, "!!!Deficit %d, rta_len=%d\n", len, rta->rta_len);
+       return i;
+}
+
+int __parse_rtattr_nested_compat(struct rtattr *tb[], int max, struct rtattr *rta,
+                                int len)
+{
+       if ((int)RTA_PAYLOAD(rta) < len)
+               return -1;
+       if (RTA_PAYLOAD(rta) >= RTA_ALIGN(len) + sizeof(struct rtattr)) {
+               rta = (struct rtattr *)(uint8_t *)RTA_DATA(rta)+RTA_ALIGN(len);
+               return parse_rtattr_nested(tb, max, rta);
+       }
+       memset(tb, 0, sizeof(struct rtattr *) * (max + 1));
+       return 0;
+}
+
+#endif /* __linux__ */
diff --git a/pimd/mtracebis_netlink.h b/pimd/mtracebis_netlink.h
new file mode 100644 (file)
index 0000000..7a60ead
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+ * libnetlink.c        RTnetlink service routines.
+ *
+ *             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.
+ *
+ * Authors:    Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
+ *
+ */
+
+#ifdef __linux__
+
+#ifndef __LIBNETLINK_H__
+#define __LIBNETLINK_H__ 1
+
+#include <asm/types.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/if_link.h>
+#include <linux/if_addr.h>
+#include <linux/neighbour.h>
+
+struct rtnl_handle
+{
+       int                     fd;
+       struct sockaddr_nl      local;
+       struct sockaddr_nl      peer;
+       __u32                   seq;
+       __u32                   dump;
+};
+
+extern int rcvbuf;
+
+extern int rtnl_open(struct rtnl_handle *rth, unsigned subscriptions);
+extern int rtnl_open_byproto(struct rtnl_handle *rth, unsigned subscriptions, int protocol);
+extern void rtnl_close(struct rtnl_handle *rth);
+extern int rtnl_wilddump_request(struct rtnl_handle *rth, int fam, int type);
+extern int rtnl_dump_request(struct rtnl_handle *rth, int type, void *req, int len);
+
+typedef int (*rtnl_filter_t)(const struct sockaddr_nl *,
+                            struct nlmsghdr *n, void *);
+
+struct rtnl_dump_filter_arg
+{
+       rtnl_filter_t filter;
+       void *arg1;
+       rtnl_filter_t junk;
+       void *arg2;
+};
+
+extern int rtnl_dump_filter_l(struct rtnl_handle *rth,
+                             const struct rtnl_dump_filter_arg *arg);
+extern int rtnl_dump_filter(struct rtnl_handle *rth, rtnl_filter_t filter,
+                           void *arg1,
+                           rtnl_filter_t junk,
+                           void *arg2);
+
+extern int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, pid_t peer,
+                    unsigned groups, struct nlmsghdr *answer,
+                    rtnl_filter_t junk,
+                    void *jarg);
+extern int rtnl_send(struct rtnl_handle *rth, const char *buf, int);
+extern int rtnl_send_check(struct rtnl_handle *rth, const char *buf, int);
+
+extern int addattr32(struct nlmsghdr *n, int maxlen, int type, __u32 data);
+extern int addattr_l(struct nlmsghdr *n, int maxlen, int type, const void *data, int alen);
+extern int addraw_l(struct nlmsghdr *n, int maxlen, const void *data, int len);
+extern struct rtattr *addattr_nest(struct nlmsghdr *n, int maxlen, int type);
+extern int addattr_nest_end(struct nlmsghdr *n, struct rtattr *nest);
+extern struct rtattr *addattr_nest_compat(struct nlmsghdr *n, int maxlen, int type, const void *data, int len);
+extern int addattr_nest_compat_end(struct nlmsghdr *n, struct rtattr *nest);
+extern int rta_addattr32(struct rtattr *rta, int maxlen, int type, __u32 data);
+extern int rta_addattr_l(struct rtattr *rta, int maxlen, int type, const void *data, int alen);
+
+extern int parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len);
+extern int parse_rtattr_byindex(struct rtattr *tb[], int max, struct rtattr *rta, int len);
+extern int __parse_rtattr_nested_compat(struct rtattr *tb[], int max, struct rtattr *rta, int len);
+
+#define parse_rtattr_nested(tb, max, rta) \
+       (parse_rtattr((tb), (max), RTA_DATA(rta), RTA_PAYLOAD(rta)))
+
+#define parse_rtattr_nested_compat(tb, max, rta, data, len) \
+({     data = RTA_PAYLOAD(rta) >= len ? RTA_DATA(rta) : NULL; \
+       __parse_rtattr_nested_compat(tb, max, rta, len); })
+
+extern int rtnl_listen(struct rtnl_handle *, rtnl_filter_t handler,
+                      void *jarg);
+extern int rtnl_from_file(FILE *, rtnl_filter_t handler,
+                      void *jarg);
+
+#define NLMSG_TAIL(nmsg) \
+       ((struct rtattr *) (((uint8_t *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len)))
+
+#ifndef IFA_RTA
+#define IFA_RTA(r) \
+       ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifaddrmsg))))
+#endif
+#ifndef IFA_PAYLOAD
+#define IFA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifaddrmsg))
+#endif
+
+#ifndef IFLA_RTA
+#define IFLA_RTA(r) \
+       ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifinfomsg))))
+#endif
+#ifndef IFLA_PAYLOAD
+#define IFLA_PAYLOAD(n)        NLMSG_PAYLOAD(n,sizeof(struct ifinfomsg))
+#endif
+
+#ifndef NDA_RTA
+#define NDA_RTA(r) \
+       ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ndmsg))))
+#endif
+#ifndef NDA_PAYLOAD
+#define NDA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ndmsg))
+#endif
+
+#ifndef NDTA_RTA
+#define NDTA_RTA(r) \
+       ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ndtmsg))))
+#endif
+#ifndef NDTA_PAYLOAD
+#define NDTA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ndtmsg))
+#endif
+
+#endif /* __LIBNETLINK_H__ */
+
+#endif /* __linux__ */
diff --git a/pimd/mtracebis_routeget.c b/pimd/mtracebis_routeget.c
new file mode 100644 (file)
index 0000000..d75aaa3
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * Multicast Traceroute for FRRouting
+ * Copyright (C) 2018  Mladen Sablic
+ *
+ * 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
+ */
+
+#ifdef __linux__
+
+#include <asm/types.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <sys/types.h>
+#include <stdio.h>
+#include <arpa/inet.h>
+#include <string.h>
+
+#include "mtracebis_netlink.h"
+#include "mtracebis_routeget.h"
+
+static int find_dst(struct nlmsghdr *n, struct in_addr *src, struct in_addr *gw)
+{
+       struct rtmsg *r = NLMSG_DATA(n);
+       int len = n->nlmsg_len;
+       struct rtattr *tb[RTA_MAX + 1];
+
+       len -= NLMSG_LENGTH(sizeof(*r));
+       if (len < 0) {
+               fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
+               return -1;
+       }
+
+       parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len);
+       if (tb[RTA_PREFSRC])
+               src->s_addr = *(uint32_t *)RTA_DATA(tb[RTA_PREFSRC]);
+       if (tb[RTA_GATEWAY])
+               gw->s_addr = *(uint32_t *)RTA_DATA(tb[RTA_GATEWAY]);
+       if (tb[RTA_OIF])
+               return *(int *)RTA_DATA(tb[RTA_OIF]);
+       return 0;
+}
+
+int routeget(struct in_addr dst, struct in_addr *src, struct in_addr *gw)
+{
+       struct {
+               struct nlmsghdr n;
+               struct rtmsg r;
+               char buf[1024];
+       } req;
+       int ret;
+       struct rtnl_handle rth = {.fd = -1};
+
+       memset(&req, 0, sizeof(req));
+
+       req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
+       req.n.nlmsg_flags = NLM_F_REQUEST;
+       req.n.nlmsg_type = RTM_GETROUTE;
+       req.r.rtm_family = AF_INET;
+       req.r.rtm_table = 0;
+       req.r.rtm_protocol = 0;
+       req.r.rtm_scope = 0;
+       req.r.rtm_type = 0;
+       req.r.rtm_src_len = 0;
+       req.r.rtm_dst_len = 0;
+       req.r.rtm_tos = 0;
+
+       addattr_l(&req.n, sizeof(req), RTA_DST, &dst.s_addr, 4);
+       req.r.rtm_dst_len = 32;
+
+       ret = rtnl_open(&rth, 0);
+
+       if (ret < 0)
+               return ret;
+
+       if (rtnl_talk(&rth, &req.n, 0, 0, &req.n, NULL, NULL) < 0) {
+               ret = -1;
+               goto close_rth;
+       }
+
+       ret = find_dst(&req.n, src, gw);
+close_rth:
+       rtnl_close(&rth);
+       return ret;
+}
+
+#endif /* __linux__ */
diff --git a/pimd/mtracebis_routeget.h b/pimd/mtracebis_routeget.h
new file mode 100644 (file)
index 0000000..18ecf6e
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Multicast Traceroute for FRRouting
+ * Copyright (C) 2018  Mladen Sablic
+ *
+ * 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
+ */
+
+#ifdef __linux__
+
+#ifndef ROUTEGET_H
+#define ROUTEGET_H
+
+#include <netinet/in.h>
+
+int routeget(struct in_addr dst, struct in_addr *src, struct in_addr *gw);
+
+#endif /* ROUTEGET */
+
+#endif /* __linux__ */
index 10b68ab73594f5242e44539b61b5ce235c1136ea..fc07b706a9797ce9560f8f95325f11ce484f2044 100644 (file)
 #include "pim_bfd.h"
 #include "bfd.h"
 
-static struct cmd_node pim_global_node = {
-       PIM_NODE, "", 1 /* vtysh ? yes */
-};
-
 static struct cmd_node interface_node = {
        INTERFACE_NODE, "%s(config-if)# ", 1 /* vtysh ? yes */
 };
@@ -7315,6 +7311,27 @@ DEFUN (no_debug_msdp_packets,
 ALIAS(no_debug_msdp_packets, undebug_msdp_packets_cmd, "undebug msdp packets",
       UNDEBUG_STR DEBUG_MSDP_STR DEBUG_MSDP_PACKETS_STR)
 
+DEFUN (debug_mtrace,
+       debug_mtrace_cmd,
+       "debug mtrace",
+       DEBUG_STR
+       DEBUG_MTRACE_STR)
+{
+       PIM_DO_DEBUG_MTRACE;
+       return CMD_SUCCESS;
+}
+
+DEFUN (no_debug_mtrace,
+       no_debug_mtrace_cmd,
+       "no debug mtrace",
+       NO_STR
+       DEBUG_STR
+       DEBUG_MTRACE_STR)
+{
+       PIM_DONT_DEBUG_MTRACE;
+       return CMD_SUCCESS;
+}
+
 DEFUN_NOSH (show_debugging_pim,
            show_debugging_pim_cmd,
            "show debugging [pim]",
@@ -7333,6 +7350,7 @@ static int interface_pim_use_src_cmd_worker(struct vty *vty, const char *source)
 {
        int result;
        struct in_addr source_addr;
+       int ret = CMD_SUCCESS;
        VTY_DECLVAR_CONTEXT(interface, ifp);
 
        result = inet_pton(AF_INET, source, &source_addr);
@@ -7347,16 +7365,19 @@ static int interface_pim_use_src_cmd_worker(struct vty *vty, const char *source)
        case PIM_SUCCESS:
                break;
        case PIM_IFACE_NOT_FOUND:
+               ret = CMD_WARNING_CONFIG_FAILED;
                vty_out(vty, "Pim not enabled on this interface\n");
                break;
        case PIM_UPDATE_SOURCE_DUP:
+               ret = CMD_WARNING;
                vty_out(vty, "%% Source already set to %s\n", source);
                break;
        default:
+               ret = CMD_WARNING_CONFIG_FAILED;
                vty_out(vty, "%% Source set failed\n");
        }
 
-       return result ? CMD_WARNING_CONFIG_FAILED : CMD_SUCCESS;
+       return ret;
 }
 
 DEFUN (interface_pim_use_source,
@@ -7485,6 +7506,7 @@ static int ip_msdp_peer_cmd_worker(struct pim_instance *pim, struct vty *vty,
        enum pim_msdp_err result;
        struct in_addr peer_addr;
        struct in_addr local_addr;
+       int ret = CMD_SUCCESS;
 
        result = inet_pton(AF_INET, peer, &peer_addr);
        if (result <= 0) {
@@ -7506,19 +7528,23 @@ static int ip_msdp_peer_cmd_worker(struct pim_instance *pim, struct vty *vty,
        case PIM_MSDP_ERR_NONE:
                break;
        case PIM_MSDP_ERR_OOM:
+               ret = CMD_WARNING_CONFIG_FAILED;
                vty_out(vty, "%% Out of memory\n");
                break;
        case PIM_MSDP_ERR_PEER_EXISTS:
+               ret = CMD_WARNING;
                vty_out(vty, "%% Peer exists\n");
                break;
        case PIM_MSDP_ERR_MAX_MESH_GROUPS:
+               ret = CMD_WARNING_CONFIG_FAILED;
                vty_out(vty, "%% Only one mesh-group allowed currently\n");
                break;
        default:
+               ret = CMD_WARNING_CONFIG_FAILED;
                vty_out(vty, "%% peer add failed\n");
        }
 
-       return result ? CMD_WARNING_CONFIG_FAILED : CMD_SUCCESS;
+       return ret;
 }
 
 DEFUN_HIDDEN (ip_msdp_peer,
@@ -7581,6 +7607,7 @@ static int ip_msdp_mesh_group_member_cmd_worker(struct pim_instance *pim,
 {
        enum pim_msdp_err result;
        struct in_addr mbr_ip;
+       int ret = CMD_SUCCESS;
 
        result = inet_pton(AF_INET, mbr, &mbr_ip);
        if (result <= 0) {
@@ -7594,19 +7621,23 @@ static int ip_msdp_mesh_group_member_cmd_worker(struct pim_instance *pim,
        case PIM_MSDP_ERR_NONE:
                break;
        case PIM_MSDP_ERR_OOM:
+               ret = CMD_WARNING_CONFIG_FAILED;
                vty_out(vty, "%% Out of memory\n");
                break;
        case PIM_MSDP_ERR_MG_MBR_EXISTS:
+               ret = CMD_WARNING;
                vty_out(vty, "%% mesh-group member exists\n");
                break;
        case PIM_MSDP_ERR_MAX_MESH_GROUPS:
+               ret = CMD_WARNING_CONFIG_FAILED;
                vty_out(vty, "%% Only one mesh-group allowed currently\n");
                break;
        default:
+               ret = CMD_WARNING_CONFIG_FAILED;
                vty_out(vty, "%% member add failed\n");
        }
 
-       return result ? CMD_WARNING_CONFIG_FAILED : CMD_SUCCESS;
+       return ret;
 }
 
 DEFUN (ip_msdp_mesh_group_member,
@@ -8509,7 +8540,6 @@ DEFUN (show_ip_msdp_sa_sg_vrf_all,
 
 void pim_cmd_init(void)
 {
-       install_node(&pim_global_node, pim_global_config_write); /* PIM_NODE */
        install_node(&interface_node,
                     pim_interface_config_write); /* INTERFACE_NODE */
        if_cmd_init();
@@ -8712,6 +8742,8 @@ void pim_cmd_init(void)
        install_element(ENABLE_NODE, &debug_msdp_packets_cmd);
        install_element(ENABLE_NODE, &no_debug_msdp_packets_cmd);
        install_element(ENABLE_NODE, &undebug_msdp_packets_cmd);
+       install_element(ENABLE_NODE, &debug_mtrace_cmd);
+       install_element(ENABLE_NODE, &no_debug_mtrace_cmd);
 
        install_element(CONFIG_NODE, &debug_igmp_cmd);
        install_element(CONFIG_NODE, &no_debug_igmp_cmd);
@@ -8754,6 +8786,8 @@ void pim_cmd_init(void)
        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, &debug_mtrace_cmd);
+       install_element(CONFIG_NODE, &no_debug_mtrace_cmd);
 
        install_element(CONFIG_NODE, &ip_msdp_mesh_group_member_cmd);
        install_element(VRF_NODE, &ip_msdp_mesh_group_member_cmd);
index 8867514876a8283a6d3622a8a40192d473e7a563..b58da30bdd64847fb9d873d783d34c8e5db86da0 100644 (file)
@@ -63,6 +63,7 @@
 #define DEBUG_MSDP_EVENTS_STR                       "MSDP protocol events\n"
 #define DEBUG_MSDP_INTERNAL_STR                     "MSDP protocol internal\n"
 #define DEBUG_MSDP_PACKETS_STR                      "MSDP protocol packets\n"
+#define DEBUG_MTRACE_STR                            "Mtrace protocol activity\n"
 
 void pim_cmd_init(void);
 
index 7524119e52ad92931e96ebf7cf23d22d9e65e16a..05224203649baeba21900ea0432e2e92f7025e9e 100644 (file)
@@ -29,6 +29,7 @@
 #include "pim_igmp.h"
 #include "pim_igmpv2.h"
 #include "pim_igmpv3.h"
+#include "pim_igmp_mtrace.h"
 #include "pim_iface.h"
 #include "pim_sock.h"
 #include "pim_mroute.h"
@@ -504,6 +505,16 @@ int pim_igmp_packet(struct igmp_sock *igmp, char *buf, size_t len)
        case PIM_IGMP_V2_LEAVE_GROUP:
                return igmp_v2_recv_leave(igmp, ip_hdr->ip_src, from_str,
                                          igmp_msg, igmp_msg_len);
+
+       case PIM_IGMP_MTRACE_RESPONSE:
+               return igmp_mtrace_recv_response(igmp, ip_hdr, ip_hdr->ip_src,
+                                                from_str, igmp_msg,
+                                                igmp_msg_len);
+               break;
+       case PIM_IGMP_MTRACE_QUERY_REQUEST:
+               return igmp_mtrace_recv_qry_req(igmp, ip_hdr, ip_hdr->ip_src,
+                                               from_str, igmp_msg,
+                                               igmp_msg_len);
        }
 
        zlog_warn("Ignoring unsupported IGMP message type: %d", msg_type);
index 275f25f63f21817a3a3b910c7ae9f954fa672456..962c50e76a66eb0f2d75d84d5c6f36d001d45762 100644 (file)
@@ -37,6 +37,8 @@
 #define PIM_IGMP_V1_MEMBERSHIP_REPORT (0x12)
 #define PIM_IGMP_V2_MEMBERSHIP_REPORT (0x16)
 #define PIM_IGMP_V2_LEAVE_GROUP       (0x17)
+#define PIM_IGMP_MTRACE_RESPONSE      (0x1E)
+#define PIM_IGMP_MTRACE_QUERY_REQUEST (0x1F)
 #define PIM_IGMP_V3_MEMBERSHIP_REPORT (0x22)
 
 #define IGMP_V3_REPORT_HEADER_SIZE    (8)
diff --git a/pimd/pim_igmp_mtrace.c b/pimd/pim_igmp_mtrace.c
new file mode 100644 (file)
index 0000000..629e10c
--- /dev/null
@@ -0,0 +1,727 @@
+/*
+ * Multicast traceroute for FRRouting
+ * Copyright (C) 2017  Mladen Sablic
+ *
+ * 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 "pimd.h"
+#include "pim_util.h"
+#include "pim_sock.h"
+#include "pim_rp.h"
+#include "pim_oil.h"
+#include "pim_ifchannel.h"
+#include "pim_macro.h"
+#include "pim_igmp_mtrace.h"
+
+static void mtrace_rsp_init(struct igmp_mtrace_rsp *mtrace_rspp)
+{
+       mtrace_rspp->arrival = 0;
+       mtrace_rspp->incoming.s_addr = 0;
+       mtrace_rspp->outgoing.s_addr = 0;
+       mtrace_rspp->prev_hop.s_addr = 0;
+       mtrace_rspp->in_count = MTRACE_UNKNOWN_COUNT;
+       mtrace_rspp->out_count = MTRACE_UNKNOWN_COUNT;
+       mtrace_rspp->total = MTRACE_UNKNOWN_COUNT;
+       mtrace_rspp->rtg_proto = 0;
+       mtrace_rspp->fwd_ttl = 0;
+       mtrace_rspp->mbz = 0;
+       mtrace_rspp->s = 0;
+       mtrace_rspp->src_mask = 0;
+       mtrace_rspp->fwd_code = MTRACE_FWD_CODE_NO_ERROR;
+}
+
+static void mtrace_rsp_debug(uint32_t qry_id, int rsp,
+                            struct igmp_mtrace_rsp *mrspp)
+{
+       char inc_str[INET_ADDRSTRLEN];
+       char out_str[INET_ADDRSTRLEN];
+       char prv_str[INET_ADDRSTRLEN];
+
+       zlog_debug(
+               "Rx mt(%d) qid=%ud arr=%x in=%s out=%s prev=%s proto=%d fwd=%d",
+               rsp, ntohl(qry_id), mrspp->arrival,
+               inet_ntop(AF_INET, &(mrspp->incoming), inc_str,
+                         sizeof(inc_str)),
+               inet_ntop(AF_INET, &(mrspp->outgoing), out_str,
+                         sizeof(out_str)),
+               inet_ntop(AF_INET, &(mrspp->prev_hop), prv_str,
+                         sizeof(prv_str)),
+               mrspp->rtg_proto, mrspp->fwd_code);
+}
+
+static void mtrace_debug(struct pim_interface *pim_ifp,
+                        struct igmp_mtrace *mtracep, int mtrace_len)
+{
+       char inc_str[INET_ADDRSTRLEN];
+       char grp_str[INET_ADDRSTRLEN];
+       char src_str[INET_ADDRSTRLEN];
+       char dst_str[INET_ADDRSTRLEN];
+       char rsp_str[INET_ADDRSTRLEN];
+
+       zlog_debug(
+               "Rx mtrace packet incoming on %s: "
+               "hops=%d type=%d size=%d, grp=%s, src=%s,"
+               " dst=%s rsp=%s ttl=%d qid=%ud",
+               inet_ntop(AF_INET, &(pim_ifp->primary_address), inc_str,
+                         sizeof(inc_str)),
+               mtracep->hops, mtracep->type, mtrace_len,
+               inet_ntop(AF_INET, &(mtracep->grp_addr), grp_str,
+                         sizeof(grp_str)),
+               inet_ntop(AF_INET, &(mtracep->src_addr), src_str,
+                         sizeof(src_str)),
+               inet_ntop(AF_INET, &(mtracep->dst_addr), dst_str,
+                         sizeof(dst_str)),
+               inet_ntop(AF_INET, &(mtracep->rsp_addr), rsp_str,
+                         sizeof(rsp_str)),
+               mtracep->rsp_ttl, ntohl(mtracep->qry_id));
+       if (mtrace_len > (int)sizeof(struct igmp_mtrace)) {
+
+               int i;
+
+               int responses = mtrace_len - sizeof(struct igmp_mtrace);
+
+               if ((responses % sizeof(struct igmp_mtrace_rsp)) != 0)
+                       if (PIM_DEBUG_MTRACE)
+                               zlog_debug(
+                                       "Mtrace response block of wrong"
+                                        " length");
+
+               responses = responses / sizeof(struct igmp_mtrace_rsp);
+
+               for (i = 0; i < responses; i++)
+                       mtrace_rsp_debug(mtracep->qry_id, i, &mtracep->rsp[i]);
+       }
+}
+
+/* 5.1 Query Arrival Time */
+static uint32_t query_arrival_time(void)
+{
+       struct timeval tv;
+       uint32_t qat;
+
+       char m_qat[] = "Query arrival time lookup failed: errno=%d: %s";
+
+       if (gettimeofday(&tv, NULL) < 0) {
+               if (PIM_DEBUG_MTRACE)
+                       zlog_warn(m_qat, errno, safe_strerror(errno));
+               return 0;
+       }
+       /* not sure second offset correct, as I get different value */
+       qat = ((tv.tv_sec + 32384) << 16) + ((tv.tv_usec << 10) / 15625);
+
+       return qat;
+}
+
+static int mtrace_send_packet(struct interface *ifp,
+                             struct igmp_mtrace *mtracep,
+                             size_t mtrace_buf_len, struct in_addr dst_addr,
+                             struct in_addr group_addr)
+{
+       struct sockaddr_in to;
+       struct pim_interface *pim_ifp;
+       socklen_t tolen;
+       ssize_t sent;
+       int ret;
+       int fd;
+       char pim_str[INET_ADDRSTRLEN];
+       char rsp_str[INET_ADDRSTRLEN];
+       u_char ttl;
+
+       pim_ifp = ifp->info;
+
+       memset(&to, 0, sizeof(to));
+       to.sin_family = AF_INET;
+       to.sin_addr = dst_addr;
+       tolen = sizeof(to);
+
+       if (PIM_DEBUG_MTRACE)
+               zlog_debug("Sending mtrace packet to %s on %s",
+                          inet_ntop(AF_INET, &mtracep->rsp_addr, rsp_str,
+                                    sizeof(rsp_str)),
+                          inet_ntop(AF_INET, &pim_ifp->primary_address,
+                                    pim_str, sizeof(pim_str)));
+
+       fd = pim_socket_raw(IPPROTO_IGMP);
+
+       if (fd < 0)
+               return -1;
+
+       ret = pim_socket_bind(fd, ifp);
+
+       if (ret < 0) {
+               ret = -1;
+               goto close_fd;
+       }
+
+       if (IPV4_CLASS_DE(ntohl(dst_addr.s_addr))) {
+               if (IPV4_MC_LINKLOCAL(ntohl(dst_addr.s_addr))) {
+                       ttl = 1;
+               } else {
+                       if (mtracep->type == PIM_IGMP_MTRACE_RESPONSE)
+                               ttl = mtracep->rsp_ttl;
+                       else
+                               ttl = 64;
+               }
+               ret = setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl,
+                                sizeof(ttl));
+
+               if (ret < 0) {
+                       if (PIM_DEBUG_MTRACE)
+                               zlog_warn("Failed to set socket multicast TTL");
+                       ret = -1;
+                       goto close_fd;
+               }
+       }
+
+       sent = sendto(fd, (char *)mtracep, mtrace_buf_len, MSG_DONTWAIT,
+                     (struct sockaddr *)&to, tolen);
+
+       if (sent != (ssize_t)mtrace_buf_len) {
+               char dst_str[INET_ADDRSTRLEN];
+               char group_str[INET_ADDRSTRLEN];
+
+               pim_inet4_dump("<dst?>", dst_addr, dst_str, sizeof(dst_str));
+               pim_inet4_dump("<group?>", group_addr, group_str,
+                              sizeof(group_str));
+               if (sent < 0) {
+                       if (PIM_DEBUG_MTRACE)
+                               zlog_warn(
+                                       "Send mtrace request failed for %s on"
+                                       "%s: group=%s msg_size=%zd: errno=%d: "
+                                       " %s",
+                                       dst_str, ifp->name, group_str,
+                                       mtrace_buf_len, errno,
+                                       safe_strerror(errno));
+               } else {
+                       if (PIM_DEBUG_MTRACE)
+                               zlog_warn(
+                                       "Send mtrace request failed for %s on"
+                                       " %s: group=%s msg_size=%zd: sent=%zd",
+                                       dst_str, ifp->name, group_str,
+                                       mtrace_buf_len, sent);
+               }
+               ret = -1;
+               goto close_fd;
+       }
+       ret = 0;
+close_fd:
+       close(fd);
+       return ret;
+}
+
+static int mtrace_un_forward_packet(struct pim_instance *pim, struct ip *ip_hdr,
+                                   struct interface *interface)
+{
+       struct pim_nexthop nexthop;
+       struct sockaddr_in to;
+       struct interface *if_out;
+       socklen_t tolen;
+       int ret;
+       int fd;
+       int sent;
+       uint16_t checksum;
+
+       checksum = ip_hdr->ip_sum;
+
+       ip_hdr->ip_sum = 0;
+
+       if (checksum != in_cksum(ip_hdr, ip_hdr->ip_hl * 4))
+               return -1;
+
+       if (ip_hdr->ip_ttl-- <= 1)
+               return -1;
+
+       ip_hdr->ip_sum = in_cksum(ip_hdr, ip_hdr->ip_hl * 4);
+
+       fd = pim_socket_raw(IPPROTO_RAW);
+
+       if (fd < 0)
+               return -1;
+
+       pim_socket_ip_hdr(fd);
+
+       if (interface == NULL) {
+               ret = pim_nexthop_lookup(pim, &nexthop, ip_hdr->ip_dst, 0);
+
+               if (ret != 0) {
+                       if (PIM_DEBUG_MTRACE)
+                               zlog_warn(
+                                       "Dropping mtrace packet, "
+                                       "no route to destination");
+                       return -1;
+               }
+
+               if_out = nexthop.interface;
+       } else {
+               if_out = interface;
+       }
+
+       ret = pim_socket_bind(fd, if_out);
+
+       if (ret < 0) {
+               close(fd);
+               return -1;
+       }
+
+       memset(&to, 0, sizeof(to));
+       to.sin_family = AF_INET;
+       to.sin_addr = ip_hdr->ip_dst;
+       tolen = sizeof(to);
+
+       sent = sendto(fd, ip_hdr, ntohs(ip_hdr->ip_len), 0,
+                     (struct sockaddr *)&to, tolen);
+
+       close(fd);
+
+       if (sent < 0) {
+               if (PIM_DEBUG_MTRACE)
+                       zlog_warn(
+                               "Failed to forward mtrace packet:"
+                               " sendto errno=%d, %s",
+                               errno, safe_strerror(errno));
+               return -1;
+       }
+
+       if (PIM_DEBUG_MTRACE) {
+               zlog_debug("Fwd mtrace packet len=%u to %s ttl=%u",
+                          ntohs(ip_hdr->ip_len), inet_ntoa(ip_hdr->ip_dst),
+                          ip_hdr->ip_ttl);
+       }
+
+       return 0;
+}
+
+static int mtrace_mc_forward_packet(struct pim_instance *pim, struct ip *ip_hdr)
+{
+       struct prefix_sg sg;
+       struct channel_oil *c_oil;
+       struct listnode *chnode;
+       struct listnode *chnextnode;
+       struct pim_ifchannel *ch = NULL;
+       int ret = -1;
+
+       memset(&sg, 0, sizeof(struct prefix_sg));
+       sg.grp = ip_hdr->ip_dst;
+
+       c_oil = pim_find_channel_oil(pim, &sg);
+
+       if (c_oil == NULL) {
+               if (PIM_DEBUG_MTRACE) {
+                       zlog_debug(
+                               "Dropping mtrace multicast packet "
+                               "len=%u to %s ttl=%u",
+                               ntohs(ip_hdr->ip_len),
+                               inet_ntoa(ip_hdr->ip_dst), ip_hdr->ip_ttl);
+               }
+               return -1;
+       }
+       if (c_oil->up == NULL)
+               return -1;
+       if (c_oil->up->ifchannels == NULL)
+               return -1;
+       for (ALL_LIST_ELEMENTS(c_oil->up->ifchannels, chnode, chnextnode, ch)) {
+               if (pim_macro_chisin_oiflist(ch)) {
+                       int r;
+
+                       r = mtrace_un_forward_packet(pim, ip_hdr,
+                                                    ch->interface);
+                       if (r == 0)
+                               ret = 0;
+               }
+       }
+       return ret;
+}
+
+
+static int mtrace_forward_packet(struct pim_instance *pim, struct ip *ip_hdr)
+{
+       if (IPV4_CLASS_DE(ntohl(ip_hdr->ip_dst.s_addr)))
+               return mtrace_mc_forward_packet(pim, ip_hdr);
+       else
+               return mtrace_un_forward_packet(pim, ip_hdr, NULL);
+}
+
+/* 6.5 Sending Traceroute Responses */
+static int mtrace_send_mc_response(struct pim_instance *pim,
+                                  struct igmp_mtrace *mtracep,
+                                  size_t mtrace_len)
+{
+       struct prefix_sg sg;
+       struct channel_oil *c_oil;
+       struct listnode *chnode;
+       struct listnode *chnextnode;
+       struct pim_ifchannel *ch = NULL;
+       int ret = -1;
+
+       memset(&sg, 0, sizeof(struct prefix_sg));
+       sg.grp = mtracep->rsp_addr;
+
+       c_oil = pim_find_channel_oil(pim, &sg);
+
+       if (c_oil == NULL) {
+               if (PIM_DEBUG_MTRACE) {
+                       zlog_debug(
+                               "Dropping mtrace multicast response packet "
+                               "len=%u to %s",
+                               (unsigned int)mtrace_len,
+                               inet_ntoa(mtracep->rsp_addr));
+               }
+               return -1;
+       }
+       if (c_oil->up == NULL)
+               return -1;
+       if (c_oil->up->ifchannels == NULL)
+               return -1;
+       for (ALL_LIST_ELEMENTS(c_oil->up->ifchannels, chnode, chnextnode, ch)) {
+               if (pim_macro_chisin_oiflist(ch)) {
+                       int r;
+
+                       r = mtrace_send_packet(ch->interface, mtracep,
+                                              mtrace_len, mtracep->rsp_addr,
+                                              mtracep->grp_addr);
+                       if (r == 0)
+                               ret = 0;
+               }
+       }
+       return ret;
+}
+
+static int mtrace_send_response(struct pim_instance *pim,
+                               struct igmp_mtrace *mtracep, size_t mtrace_len)
+{
+       struct pim_nexthop nexthop;
+       int ret;
+
+       mtracep->type = PIM_IGMP_MTRACE_RESPONSE;
+
+       mtracep->checksum = 0;
+       mtracep->checksum = in_cksum((char *)mtracep, mtrace_len);
+
+       if (IPV4_CLASS_DE(ntohl(mtracep->rsp_addr.s_addr))) {
+               struct pim_rpf *p_rpf;
+               char grp_str[INET_ADDRSTRLEN];
+
+               if (pim_rp_i_am_rp(pim, mtracep->rsp_addr))
+                       return mtrace_send_mc_response(pim, mtracep,
+                                                      mtrace_len);
+
+               p_rpf = pim_rp_g(pim, mtracep->rsp_addr);
+
+               if (p_rpf == NULL) {
+                       if (PIM_DEBUG_MTRACE)
+                               zlog_warn("mtrace no RP for %s",
+                                         inet_ntop(AF_INET,
+                                                   &(mtracep->rsp_addr),
+                                                   grp_str, sizeof(grp_str)));
+                       return -1;
+               }
+               nexthop = p_rpf->source_nexthop;
+               if (PIM_DEBUG_MTRACE)
+                       zlog_debug("mtrace response to RP");
+       } else {
+               /* TODO: should use unicast rib lookup */
+               ret = pim_nexthop_lookup(pim, &nexthop, mtracep->rsp_addr, 1);
+
+               if (ret != 0) {
+                       if (PIM_DEBUG_MTRACE)
+                               zlog_warn(
+                                       "Dropped response qid=%ud, no route to "
+                                       "response address",
+                                       mtracep->qry_id);
+                       return -1;
+               }
+       }
+
+       return mtrace_send_packet(nexthop.interface, mtracep, mtrace_len,
+                                 mtracep->rsp_addr, mtracep->grp_addr);
+}
+
+int igmp_mtrace_recv_qry_req(struct igmp_sock *igmp, struct ip *ip_hdr,
+                            struct in_addr from, const char *from_str,
+                            char *igmp_msg, int igmp_msg_len)
+{
+       static uint32_t qry_id, qry_src;
+       char mtrace_buf[MTRACE_HDR_SIZE + MTRACE_MAX_HOPS * MTRACE_RSP_SIZE];
+       struct pim_nexthop nexthop;
+       struct interface *ifp;
+       struct interface *out_ifp;
+       struct pim_interface *pim_ifp;
+       struct pim_interface *pim_out_ifp;
+       struct pim_instance *pim;
+       struct igmp_mtrace *mtracep;
+       struct igmp_mtrace_rsp *rspp;
+       struct in_addr nh_addr;
+       enum mtrace_fwd_code fwd_code = MTRACE_FWD_CODE_NO_ERROR;
+       int ret;
+       size_t r_len;
+       int last_rsp_ind = 0;
+       size_t mtrace_len;
+       uint16_t recv_checksum;
+       uint16_t checksum;
+
+       ifp = igmp->interface;
+       pim_ifp = ifp->info;
+       pim = pim_ifp->pim;
+
+       /*
+        * 6. Router Behaviour
+        * Check if mtrace packet is addressed elsewhere and forward,
+        * if applicable
+        */
+       if (!IPV4_CLASS_DE(ntohl(ip_hdr->ip_dst.s_addr)))
+               if (!if_lookup_exact_address(&ip_hdr->ip_dst, AF_INET,
+                                            pim->vrf_id))
+                       return mtrace_forward_packet(pim, ip_hdr);
+
+       if (igmp_msg_len < (int)sizeof(struct igmp_mtrace)) {
+               if (PIM_DEBUG_MTRACE)
+                       zlog_warn(
+                               "Recv mtrace packet from %s on %s: too short,"
+                               " len=%d, min=%lu",
+                               from_str, ifp->name, igmp_msg_len,
+                               sizeof(struct igmp_mtrace));
+               return -1;
+       }
+
+       mtracep = (struct igmp_mtrace *)igmp_msg;
+
+       recv_checksum = mtracep->checksum;
+
+       mtracep->checksum = 0;
+
+       checksum = in_cksum(igmp_msg, igmp_msg_len);
+
+       if (recv_checksum != checksum) {
+               if (PIM_DEBUG_MTRACE)
+                       zlog_warn(
+                               "Recv mtrace packet from %s on %s: checksum"
+                               " mismatch: received=%x computed=%x",
+                               from_str, ifp->name, recv_checksum, checksum);
+               return -1;
+       }
+
+       if (PIM_DEBUG_MTRACE)
+               mtrace_debug(pim_ifp, mtracep, igmp_msg_len);
+
+       /* subtract header from message length */
+       r_len = igmp_msg_len - sizeof(struct igmp_mtrace);
+
+       /* Classify mtrace packet, check if it is a query */
+       if (!r_len) {
+               if (PIM_DEBUG_MTRACE)
+                       zlog_debug("Received IGMP multicast traceroute query");
+
+               /* 6.1.1  Packet verification */
+               if (!pim_if_connected_to_source(ifp, mtracep->dst_addr)) {
+                       if (IPV4_CLASS_DE(ntohl(ip_hdr->ip_dst.s_addr))) {
+                               if (PIM_DEBUG_MTRACE)
+                                       zlog_debug(
+                                               "Dropping multicast query "
+                                               "on wrong interface");
+                               return -1;
+                       }
+                       /* Unicast query on wrong interface */
+                       fwd_code = MTRACE_FWD_CODE_WRONG_IF;
+               }
+               if (qry_id == mtracep->qry_id && qry_src == from.s_addr) {
+                       if (PIM_DEBUG_MTRACE)
+                               zlog_debug(
+                                       "Dropping multicast query with "
+                                       "duplicate source and id");
+                       return -1;
+               }
+               qry_id = mtracep->qry_id;
+               qry_src = from.s_addr;
+       }
+       /* if response fields length is equal to a whole number of responses */
+       else if ((r_len % sizeof(struct igmp_mtrace_rsp)) == 0) {
+               r_len = igmp_msg_len - sizeof(struct igmp_mtrace);
+
+               if (r_len != 0)
+                       last_rsp_ind = r_len / sizeof(struct igmp_mtrace_rsp);
+               if (last_rsp_ind > MTRACE_MAX_HOPS) {
+                       if (PIM_DEBUG_MTRACE)
+                               zlog_warn("Mtrace request of excessive size");
+                       return -1;
+               }
+       } else {
+               if (PIM_DEBUG_MTRACE)
+                       zlog_warn(
+                               "Recv mtrace packet from %s on %s: "
+                               "invalid length %d",
+                               from_str, ifp->name, igmp_msg_len);
+               return -1;
+       }
+
+       /* 6.2.1 Packet Verification - drop not link-local multicast */
+       if (IPV4_CLASS_DE(ntohl(ip_hdr->ip_dst.s_addr))
+           && !IPV4_MC_LINKLOCAL(ntohl(ip_hdr->ip_dst.s_addr))) {
+               if (PIM_DEBUG_MTRACE)
+                       zlog_warn(
+                               "Recv mtrace packet from %s on %s:"
+                               " not link-local multicast %s",
+                               from_str, ifp->name, inet_ntoa(ip_hdr->ip_dst));
+               return -1;
+       }
+
+       /* 6.2.2. Normal Processing */
+
+       /* 6.2.2. 1. */
+
+       if (last_rsp_ind == MTRACE_MAX_HOPS) {
+               mtracep->rsp[MTRACE_MAX_HOPS - 1].fwd_code =
+                       MTRACE_FWD_CODE_NO_SPACE;
+               return mtrace_send_response(pim_ifp->pim, mtracep,
+                                           igmp_msg_len);
+       }
+
+       /* calculate new mtrace mtrace lenght with extra response */
+       mtrace_len = igmp_msg_len + sizeof(struct igmp_mtrace_rsp);
+
+       /* copy received query/request */
+       memcpy(mtrace_buf, igmp_msg, igmp_msg_len);
+
+       /* repoint mtracep pointer to copy */
+       mtracep = (struct igmp_mtrace *)mtrace_buf;
+
+       /* pointer for extra response field to be filled in */
+       rspp = &mtracep->rsp[last_rsp_ind];
+
+       /* initialize extra response field */
+       mtrace_rsp_init(rspp);
+
+       rspp->arrival = htonl(query_arrival_time());
+       rspp->outgoing = pim_ifp->primary_address;
+       rspp->out_count = htonl(MTRACE_UNKNOWN_COUNT);
+
+       /* 6.2.2. 2. Attempt to determine forwarding information */
+
+       nh_addr.s_addr = 0;
+
+       ret = pim_nexthop_lookup(pim, &nexthop, mtracep->src_addr, 1);
+
+       if (ret == 0) {
+               char nexthop_str[INET_ADDRSTRLEN];
+
+               if (PIM_DEBUG_MTRACE)
+                       zlog_debug("mtrace pim_nexthop_lookup OK");
+
+               if (PIM_DEBUG_MTRACE)
+                       zlog_warn("mtrace next_hop=%s",
+                                 inet_ntop(nexthop.mrib_nexthop_addr.family,
+                                           &nexthop.mrib_nexthop_addr.u.prefix,
+                                           nexthop_str, sizeof(nexthop_str)));
+
+               if (nexthop.mrib_nexthop_addr.family == AF_INET)
+                       nh_addr = nexthop.mrib_nexthop_addr.u.prefix4;
+       }
+       /* 6.4 Forwarding Traceroute Requests: ... Otherwise, ... */
+       else {
+               if (PIM_DEBUG_MTRACE)
+                       zlog_debug("mtrace not found neighbor");
+               if (!fwd_code)
+                       rspp->fwd_code = MTRACE_FWD_CODE_NO_ROUTE;
+               else
+                       rspp->fwd_code = fwd_code;
+               /* 6.5 Sending Traceroute Responses */
+               return mtrace_send_response(pim, mtracep, mtrace_len);
+       }
+
+       out_ifp = nexthop.interface;
+       pim_out_ifp = out_ifp->info;
+
+       rspp->incoming = pim_out_ifp->primary_address;
+       rspp->prev_hop = nh_addr;
+       rspp->in_count = htonl(MTRACE_UNKNOWN_COUNT);
+       rspp->total = htonl(MTRACE_UNKNOWN_COUNT);
+       rspp->rtg_proto = MTRACE_RTG_PROTO_PIM;
+       rspp->s = 1;
+       rspp->src_mask = 32;
+
+       if (nh_addr.s_addr == 0) {
+               /* reached source? */
+               if (pim_if_connected_to_source(out_ifp, mtracep->src_addr))
+                       return mtrace_send_response(pim, mtracep, mtrace_len);
+               /*
+                * 6.4 Forwarding Traceroute Requests:
+                * Previous-hop router not known
+                */
+               inet_aton(MCAST_ALL_ROUTERS, &nh_addr);
+       }
+
+       if (mtracep->hops <= (last_rsp_ind + 1))
+               return mtrace_send_response(pim, mtracep, mtrace_len);
+
+       mtracep->checksum = 0;
+
+       mtracep->checksum = in_cksum(mtrace_buf, mtrace_len);
+
+       return mtrace_send_packet(out_ifp, mtracep, mtrace_len, nh_addr,
+                                 mtracep->grp_addr);
+}
+
+int igmp_mtrace_recv_response(struct igmp_sock *igmp, struct ip *ip_hdr,
+                             struct in_addr from, const char *from_str,
+                             char *igmp_msg, int igmp_msg_len)
+{
+       static uint32_t qry_id, rsp_dst;
+       struct interface *ifp;
+       struct pim_interface *pim_ifp;
+       struct pim_instance *pim;
+       struct igmp_mtrace *mtracep;
+       uint16_t recv_checksum;
+       uint16_t checksum;
+
+       ifp = igmp->interface;
+       pim_ifp = ifp->info;
+       pim = pim_ifp->pim;
+
+       mtracep = (struct igmp_mtrace *)igmp_msg;
+
+       recv_checksum = mtracep->checksum;
+
+       mtracep->checksum = 0;
+
+       checksum = in_cksum(igmp_msg, igmp_msg_len);
+
+       if (recv_checksum != checksum) {
+               if (PIM_DEBUG_MTRACE)
+                       zlog_warn(
+                               "Recv mtrace response from %s on %s: checksum"
+                               " mismatch: received=%x computed=%x",
+                               from_str, ifp->name, recv_checksum, checksum);
+               return -1;
+       }
+
+       mtracep->checksum = checksum;
+
+       if (PIM_DEBUG_MTRACE)
+               mtrace_debug(pim_ifp, mtracep, igmp_msg_len);
+
+       /* Drop duplicate packets */
+       if (qry_id == mtracep->qry_id && rsp_dst == ip_hdr->ip_dst.s_addr) {
+               if (PIM_DEBUG_MTRACE)
+                       zlog_debug("duplicate mtrace response packet dropped");
+               return -1;
+       }
+
+       qry_id = mtracep->qry_id;
+       rsp_dst = ip_hdr->ip_dst.s_addr;
+
+       return mtrace_forward_packet(pim, ip_hdr);
+}
diff --git a/pimd/pim_igmp_mtrace.h b/pimd/pim_igmp_mtrace.h
new file mode 100644 (file)
index 0000000..b5c1008
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * Multicast traceroute for FRRouting
+ * Copyright (C) 2017  Mladen Sablic
+ *
+ * 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_IGMP_MTRACE_H
+#define PIM_IGMP_MTRACE_H
+
+#include <zebra.h>
+
+#include "pim_igmp.h"
+
+#define MTRACE_MAX_HOPS (255)
+#define MTRACE_UNKNOWN_COUNT (0xffffffff)
+
+enum mtrace_fwd_code {
+       MTRACE_FWD_CODE_NO_ERROR        = 0x00,
+       MTRACE_FWD_CODE_WRONG_IF        = 0x01,
+       MTRACE_FWD_CODE_PRUNE_SENT      = 0x02,
+       MTRACE_FWD_CODE_PRUNE_RCVD      = 0x03,
+       MTRACE_FWD_CODE_SCOPED          = 0x04,
+       MTRACE_FWD_CODE_NO_ROUTE        = 0x05,
+       MTRACE_FWD_CODE_WRONG_LAST_HOP  = 0x06,
+       MTRACE_FWD_CODE_NOT_FORWARDING  = 0x07,
+       MTRACE_FWD_CODE_REACHED_RP      = 0x08,
+       MTRACE_FWD_CODE_RPF_IF          = 0x09,
+       MTRACE_FWD_CODE_NO_MULTICAST    = 0x0A,
+       MTRACE_FWD_CODE_INFO_HIDDEN     = 0x0B,
+       MTRACE_FWD_CODE_NO_SPACE        = 0x81,
+       MTRACE_FWD_CODE_OLD_ROUTER      = 0x82,
+       MTRACE_FWD_CODE_ADMIN_PROHIB    = 0x83
+};
+
+enum mtrace_rtg_proto {
+       MTRACE_RTG_PROTO_DVMRP          = 1,
+       MTRACE_RTG_PROTO_MOSPF          = 2,
+       MTRACE_RTG_PROTO_PIM            = 3,
+       MTRACE_RTG_PROTO_CBT            = 4,
+       MTRACE_RTG_PROTO_PIM_SPECIAL    = 5,
+       MTRACE_RTG_PROTO_PIM_STATIC     = 6,
+       MTRACE_RTG_PROTO_DVMRP_STATIC   = 7,
+       MTRACE_RTG_PROTO_PIM_MBGP       = 8,
+       MTRACE_RTG_PROTO_CBT_SPECIAL    = 9,
+       MTRACE_RTG_PROTO_CBT_STATIC     = 10,
+       MTRACE_RTG_PROTO_PIM_ASSERT     = 11,
+};
+
+struct igmp_mtrace_rsp {
+       uint32_t arrival;
+       struct in_addr incoming;
+       struct in_addr outgoing;
+       struct in_addr prev_hop;
+       uint32_t in_count;
+       uint32_t out_count;
+       uint32_t total;
+       uint32_t rtg_proto : 8;
+       uint32_t fwd_ttl : 8;
+       /* little endian order for next three fields */
+       uint32_t src_mask : 6;
+       uint32_t s : 1;
+       uint32_t mbz : 1;
+       uint32_t fwd_code : 8;
+} __attribute__((packed));
+
+struct igmp_mtrace {
+       uint8_t type;
+       uint8_t hops;
+       uint16_t checksum;
+       struct in_addr grp_addr;
+       struct in_addr src_addr;
+       struct in_addr dst_addr;
+       struct in_addr rsp_addr;
+       uint32_t rsp_ttl : 8;
+       uint32_t qry_id : 24;
+       struct igmp_mtrace_rsp rsp[0];
+} __attribute__((packed));
+
+#define MTRACE_HDR_SIZE (sizeof(struct igmp_mtrace))
+#define MTRACE_RSP_SIZE (sizeof(struct igmp_mtrace_rsp))
+
+int igmp_mtrace_recv_qry_req(struct igmp_sock *igmp, struct ip *ip_hdr,
+                            struct in_addr from, const char *from_str,
+                            char *igmp_msg, int igmp_msg_len);
+
+int igmp_mtrace_recv_response(struct igmp_sock *igmp, struct ip *ip_hdr,
+                             struct in_addr from, const char *from_str,
+                             char *igmp_msg, int igmp_msg_len);
+
+#endif /* PIM_IGMP_MTRACE_H */
index 1fccbaeafa3be332a308d95837ae03eb9bcf2e09..9b7ef2e073a14e06b4849239b4495764e4f54110 100644 (file)
@@ -136,7 +136,7 @@ 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);
+       zlog_debug("VRF Created: %s(%u)", vrf->name, vrf->vrf_id);
        if (pim == NULL) {
                zlog_err("%s %s: pim class init failure ", __FILE__,
                         __PRETTY_FUNCTION__);
@@ -159,7 +159,7 @@ 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);
+       zlog_debug("VRF Deletion: %s(%u)", vrf->name, vrf->vrf_id);
 
        pim_ssmpingd_destroy(pim);
        pim_instance_terminate(pim);
@@ -198,12 +198,13 @@ static int pim_vrf_config_write(struct vty *vty)
                if (!pim)
                        continue;
 
-               if (vrf->vrf_id == VRF_DEFAULT)
-                       continue;
+               if (vrf->vrf_id != VRF_DEFAULT)
+                       vty_frame(vty, "vrf %s\n", vrf->name);
 
-               vty_frame(vty, "vrf %s\n", vrf->name);
                pim_global_config_write_worker(pim, vty);
-               vty_endframe(vty, "!\n");
+
+               if (vrf->vrf_id != VRF_DEFAULT)
+                       vty_endframe(vty, "!\n");
        }
 
        return 0;
index e2984e1d131233292657c09d6b521065de395699..5b297253b2fbb2ce73639625f0136e96937e058d 100644 (file)
 void pim_sendmsg_zebra_rnh(struct pim_instance *pim, struct zclient *zclient,
                           struct pim_nexthop_cache *pnc, int command)
 {
-       struct stream *s;
        struct prefix *p;
        int ret;
 
-       /* Check socket. */
-       if (!zclient || zclient->sock < 0)
-               return;
-
        p = &(pnc->rpf.rpf_addr);
-       s = zclient->obuf;
-       stream_reset(s);
-       zclient_create_header(s, command, pim->vrf_id);
-       /* get update for all routes for a prefix */
-       stream_putc(s, 0);
-
-       stream_putw(s, PREFIX_FAMILY(p));
-       stream_putc(s, p->prefixlen);
-       switch (PREFIX_FAMILY(p)) {
-       case AF_INET:
-               stream_put_in_addr(s, &p->u.prefix4);
-               break;
-       case AF_INET6:
-               stream_put(s, &(p->u.prefix6), 16);
-               break;
-       default:
-               break;
-       }
-       stream_putw_at(s, 0, stream_get_endp(s));
-
-       ret = zclient_send_message(zclient);
+       ret = zclient_send_rnh(zclient, command, p, false, pim->vrf_id);
        if (ret < 0)
                zlog_warn("sendmsg_nexthop: zclient_send_message() failed");
 
-
        if (PIM_DEBUG_PIM_NHT) {
                char buf[PREFIX2STR_BUFFER];
                prefix2str(p, buf, sizeof(buf));
@@ -634,13 +608,9 @@ int pim_ecmp_nexthop_search(struct pim_instance *pim,
 int pim_parse_nexthop_update(int command, struct zclient *zclient,
                             zebra_size_t length, vrf_id_t vrf_id)
 {
-       struct stream *s;
-       struct prefix p;
        struct nexthop *nexthop;
        struct nexthop *nhlist_head = NULL;
        struct nexthop *nhlist_tail = NULL;
-       uint32_t metric, distance;
-       u_char nexthop_num = 0;
        int i;
        struct pim_rpf rpf;
        struct pim_nexthop_cache *pnc = NULL;
@@ -649,30 +619,21 @@ int pim_parse_nexthop_update(int command, struct zclient *zclient,
        struct interface *ifp1 = NULL;
        struct vrf *vrf = vrf_lookup_by_id(vrf_id);
        struct pim_instance *pim;
+       struct zapi_route nhr;
 
        if (!vrf)
                return 0;
        pim = vrf->info;
 
-       s = zclient->ibuf;
-       memset(&p, 0, sizeof(struct prefix));
-       p.family = stream_getw(s);
-       p.prefixlen = stream_getc(s);
-       switch (p.family) {
-       case AF_INET:
-               p.u.prefix4.s_addr = stream_get_ipv4(s);
-               break;
-       case AF_INET6:
-               stream_get(&p.u.prefix6, s, 16);
-               break;
-       default:
-               break;
+       if (!zapi_nexthop_update_decode(zclient->ibuf, &nhr)) {
+               if (PIM_DEBUG_PIM_NHT)
+                       zlog_debug("%s: Decode of nexthop update from zebra failed",
+                                  __PRETTY_FUNCTION__);
+               return 0;
        }
 
        if (command == ZEBRA_NEXTHOP_UPDATE) {
-               rpf.rpf_addr.family = p.family;
-               rpf.rpf_addr.prefixlen = p.prefixlen;
-               rpf.rpf_addr.u.prefix4.s_addr = p.u.prefix4.s_addr;
+               prefix_copy(&rpf.rpf_addr, &nhr.prefix);
                pnc = pim_nexthop_cache_find(pim, &rpf);
                if (!pnc) {
                        if (PIM_DEBUG_PIM_NHT) {
@@ -692,34 +653,20 @@ int pim_parse_nexthop_update(int command, struct zclient *zclient,
        }
 
        pnc->last_update = pim_time_monotonic_usec();
-       distance = stream_getc(s);
-       metric = stream_getl(s);
-       nexthop_num = stream_getc(s);
 
-       if (nexthop_num) {
+       if (nhr.nexthop_num) {
                pnc->nexthop_num = 0; // Only increment for pim enabled rpf.
 
-               for (i = 0; i < nexthop_num; i++) {
-                       nexthop = nexthop_new();
-                       nexthop->type = stream_getc(s);
+               for (i = 0; i < nhr.nexthop_num; i++) {
+                       nexthop = nexthop_from_zapi_nexthop(&nhr.nexthops[i]);
                        switch (nexthop->type) {
                        case NEXTHOP_TYPE_IPV4:
-                               nexthop->gate.ipv4.s_addr = stream_get_ipv4(s);
-                               nexthop->ifindex = stream_getl(s);
-                               break;
                        case NEXTHOP_TYPE_IFINDEX:
-                               nexthop->ifindex = stream_getl(s);
-                               break;
                        case NEXTHOP_TYPE_IPV4_IFINDEX:
-                               nexthop->gate.ipv4.s_addr = stream_get_ipv4(s);
-                               nexthop->ifindex = stream_getl(s);
-                               break;
                        case NEXTHOP_TYPE_IPV6:
-                               stream_get(&nexthop->gate.ipv6, s, 16);
+                       case NEXTHOP_TYPE_BLACKHOLE:
                                break;
                        case NEXTHOP_TYPE_IPV6_IFINDEX:
-                               stream_get(&nexthop->gate.ipv6, s, 16);
-                               nexthop->ifindex = stream_getl(s);
                                ifp1 = if_lookup_by_index(nexthop->ifindex,
                                                          pim->vrf_id);
                                nbr = pim_neighbor_find_if(ifp1);
@@ -733,9 +680,6 @@ int pim_parse_nexthop_update(int command, struct zclient *zclient,
                                                PIM_NET_INADDR_ANY;
                                }
 
-                               break;
-                       default:
-                               /* do nothing */
                                break;
                        }
 
@@ -757,19 +701,21 @@ int pim_parse_nexthop_update(int command, struct zclient *zclient,
 
                        if (PIM_DEBUG_PIM_NHT) {
                                char p_str[PREFIX2STR_BUFFER];
-                               prefix2str(&p, p_str, sizeof(p_str));
+
+                               prefix2str(&nhr.prefix, 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);
+                                       ifp->name, nexthop->type, nhr.distance,
+                                       nhr.metric);
                        }
 
                        if (!ifp->info) {
                                if (PIM_DEBUG_PIM_NHT) {
                                        char buf[NEXTHOP_STRLEN];
+
                                        zlog_debug(
                                                "%s: multicast not enabled on input interface %s(%s) (ifindex=%d, addr %s)",
                                                __PRETTY_FUNCTION__, ifp->name,
@@ -797,23 +743,24 @@ int pim_parse_nexthop_update(int command, struct zclient *zclient,
                pnc->nexthop = nhlist_head;
                if (pnc->nexthop_num) {
                        pnc->flags |= PIM_NEXTHOP_VALID;
-                       pnc->distance = distance;
-                       pnc->metric = metric;
+                       pnc->distance = nhr.distance;
+                       pnc->metric = nhr.metric;
                }
        } else {
                pnc->flags &= ~PIM_NEXTHOP_VALID;
-               pnc->nexthop_num = nexthop_num;
+               pnc->nexthop_num = nhr.nexthop_num;
                nexthops_free(pnc->nexthop);
                pnc->nexthop = NULL;
        }
 
        if (PIM_DEBUG_PIM_NHT) {
                char buf[PREFIX2STR_BUFFER];
-               prefix2str(&p, buf, sizeof(buf));
+               prefix2str(&nhr.prefix, buf, sizeof(buf));
                zlog_debug(
-                       "%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,
+                       "%s: NHT Update for %s(%s) num_nh %d num_pim_nh %d vrf:%u up %ld rp %d",
+                       __PRETTY_FUNCTION__, buf, pim->vrf->name,
+                       nhr.nexthop_num, pnc->nexthop_num, vrf_id,
+                       pnc->upstream_hash->count,
                        listcount(pnc->rp_list));
        }
 
index c45b0ce14c34ca46e327f62811870db55b8bb864..53bbf54f3e3f36897645db0bd7d77682fdff5493 100644 (file)
@@ -135,8 +135,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 pim_instance *pim,
-                                               struct prefix_sg *sg)
+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;
index 1168ba0a8fe9b8a5c3520a4dc00649e3c4027501..94d3840e98db72aafa561e706620cac66f0ed399 100644 (file)
@@ -86,6 +86,8 @@ 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_find_channel_oil(struct pim_instance *pim,
+                                        struct prefix_sg *sg);
 struct channel_oil *pim_channel_oil_add(struct pim_instance *pim,
                                        struct prefix_sg *sg,
                                        int input_vif_index);
index 450faf75bbc1138894ab49ff618e92c7f1cc17be..688bc42c3dddf3c8682bf4e7b6c8920bba00278b 100644 (file)
@@ -78,6 +78,11 @@ int pim_debug_config_write(struct vty *vty)
                ++writes;
        }
 
+       if (PIM_DEBUG_MTRACE) {
+               vty_out(vty, "debug mtrace\n");
+               ++writes;
+       }
+
        if (PIM_DEBUG_MROUTE_DETAIL) {
                vty_out(vty, "debug mroute detail\n");
                ++writes;
@@ -232,11 +237,6 @@ int pim_global_config_write_worker(struct pim_instance *pim, 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)
 {
        struct pim_instance *pim;
index aef90cacc39a0061d57e74546a8aef59b2b3db62..22ac3333e4d9a8b41d25ca1ab1e1b8398b4574c2 100644 (file)
@@ -23,7 +23,6 @@
 #include "vty.h"
 
 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);
 
index 689e9a744987341ad4a968c073b9c4aeec4218f4..2970dcee5e292847fec582a85d6991d13ea4a01e 100644 (file)
@@ -80,7 +80,7 @@ static int pim_zebra_if_add(int command, struct zclient *zclient,
 
        if (PIM_DEBUG_ZEBRA) {
                zlog_debug(
-                       "%s: %s index %d(%d) flags %ld metric %d mtu %d operative %d",
+                       "%s: %s index %d(%u) 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));
@@ -130,7 +130,7 @@ static int pim_zebra_if_del(int command, struct zclient *zclient,
 
        if (PIM_DEBUG_ZEBRA) {
                zlog_debug(
-                       "%s: %s index %d(%d) flags %ld metric %d mtu %d operative %d",
+                       "%s: %s index %d(%u) 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));
@@ -158,7 +158,7 @@ static int pim_zebra_if_state_up(int command, struct zclient *zclient,
 
        if (PIM_DEBUG_ZEBRA) {
                zlog_debug(
-                       "%s: %s index %d(%d) flags %ld metric %d mtu %d operative %d",
+                       "%s: %s index %d(%u) 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));
@@ -213,7 +213,7 @@ static int pim_zebra_if_state_down(int command, struct zclient *zclient,
 
        if (PIM_DEBUG_ZEBRA) {
                zlog_debug(
-                       "%s: %s index %d(%d) flags %ld metric %d mtu %d operative %d",
+                       "%s: %s index %d(%u) 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));
@@ -293,7 +293,7 @@ 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(%d) connected IP address %s flags %u %s",
+               zlog_debug("%s: %s(%u) 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"
@@ -372,7 +372,7 @@ static int pim_zebra_if_address_del(int command, struct zclient *client,
                        char buf[BUFSIZ];
                        prefix2str(p, buf, BUFSIZ);
                        zlog_debug(
-                               "%s: %s(%d) disconnected IP address %s flags %u %s",
+                               "%s: %s(%u) disconnected IP address %s flags %u %s",
                                __PRETTY_FUNCTION__, c->ifp->name, vrf_id, buf,
                                c->flags,
                                CHECK_FLAG(c->flags, ZEBRA_IFA_SECONDARY)
@@ -765,8 +765,6 @@ void pim_zebra_init(void)
                zlog_info("zclient_init cleared redistribution request");
        }
 
-       zassert(zclient->redist_default == ZEBRA_ROUTE_PIM);
-
        /* Request all redistribution */
        for (i = 0; i < ZEBRA_ROUTE_MAX; i++) {
                if (i == zclient->redist_default)
index cd00a2df46b96a61f9a2babd4eb5cdab44340fb0..de7f2593196ce07ec621aa127376c7939412e2d0 100644 (file)
 #define PIM_MASK_PIM_NHT             (1 << 22)
 #define PIM_MASK_PIM_NHT_DETAIL      (1 << 23)
 #define PIM_MASK_PIM_NHT_RP          (1 << 24)
+#define PIM_MASK_MTRACE              (1 << 25)
 /* Remember 32 bits!!! */
 
 /* PIM error codes */
@@ -188,6 +189,7 @@ extern int32_t qpim_register_probe_time;
 #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_PIM_NHT_RP          (qpim_debugs & PIM_MASK_PIM_NHT_RP)
+#define PIM_DEBUG_MTRACE              (qpim_debugs & PIM_MASK_MTRACE)
 
 #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))
@@ -216,6 +218,7 @@ extern int32_t qpim_register_probe_time;
 #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_DO_DEBUG_PIM_NHT_RP          (qpim_debugs |= PIM_MASK_PIM_NHT_RP)
+#define PIM_DO_DEBUG_MTRACE              (qpim_debugs |= PIM_MASK_MTRACE)
 
 #define PIM_DONT_DEBUG_PIM_EVENTS          (qpim_debugs &= ~PIM_MASK_PIM_EVENTS)
 #define PIM_DONT_DEBUG_PIM_PACKETS         (qpim_debugs &= ~PIM_MASK_PIM_PACKETS)
@@ -240,6 +243,7 @@ extern int32_t qpim_register_probe_time;
 #define PIM_DONT_DEBUG_MSDP_INTERNAL       (qpim_debugs &= ~PIM_MASK_MSDP_INTERNAL)
 #define PIM_DONT_DEBUG_PIM_NHT             (qpim_debugs &= ~PIM_MASK_PIM_NHT)
 #define PIM_DONT_DEBUG_PIM_NHT_RP          (qpim_debugs &= ~PIM_MASK_PIM_NHT_RP)
+#define PIM_DONT_DEBUG_MTRACE              (qpim_debugs &= ~PIM_MASK_MTRACE)
 
 void pim_init(void);
 void pim_terminate(void);
index 2fcb06157656d6bff33da1efe22c8e966a83924e..2254362221bfa9bd98a1d7499f3775d28f5ba1fa 100644 (file)
@@ -5,6 +5,7 @@
 if PIMD
 noinst_LIBRARIES += pimd/libpim.a
 sbin_PROGRAMS += pimd/pimd
+bin_PROGRAMS += pimd/mtracebis
 noinst_PROGRAMS += pimd/test_igmpv3_join
 dist_examples_DATA += pimd/pimd.conf.sample
 endif
@@ -18,6 +19,7 @@ pimd_libpim_a_SOURCES = \
        pimd/pim_iface.c \
        pimd/pim_ifchannel.c \
        pimd/pim_igmp.c \
+       pimd/pim_igmp_mtrace.c \
        pimd/pim_igmpv2.c \
        pimd/pim_igmpv3.c \
        pimd/pim_instance.c \
@@ -66,6 +68,7 @@ noinst_HEADERS += \
        pimd/pim_ifchannel.h \
        pimd/pim_igmp.h \
        pimd/pim_igmp_join.h \
+       pimd/pim_igmp_mtrace.h \
        pimd/pim_igmpv2.h \
        pimd/pim_igmpv3.h \
        pimd/pim_instance.h \
@@ -101,6 +104,8 @@ noinst_HEADERS += \
        pimd/pim_zebra.h \
        pimd/pim_zlookup.h \
        pimd/pimd.h \
+       pimd/mtracebis_netlink.h \
+       pimd/mtracebis_routeget.h \
        # end
 
 pimd_pimd_LDADD = pimd/libpim.a lib/libfrr.la @LIBCAP@
@@ -108,3 +113,9 @@ pimd_pimd_SOURCES = pimd/pim_main.c
 
 pimd_test_igmpv3_join_LDADD = lib/libfrr.la
 pimd_test_igmpv3_join_SOURCES = pimd/test_igmpv3_join.c
+
+pimd_mtracebis_LDADD =  lib/libfrr.la
+pimd_mtracebis_SOURCES = pimd/mtracebis.c \
+                        pimd/mtracebis_netlink.c \
+                        pimd/mtracebis_routeget.c \
+                        # end
index 13ec449a1f54eca54da507244a31fadd6519a751..b70bb3fc1d6a5b55aa21fdc48947cd92a1736951 100644 (file)
@@ -1,5 +1,3 @@
-$Id: README.txt,v 1.1 2004/08/27 15:57:35 gdt Exp $
-
 This directory contains files for use with the pkgsrc framework
 (http://www.pkgsrc.org) used with NetBSD and other operating systems.
 Eventually it will be hooked into automake such that they can be
index 4e05f7828c847ce0047f8c9bf0977ffc1580464a..20b96bb76ff6cf16d6e3fdf42a0ceb7c5e5d4128 100644 (file)
@@ -22,7 +22,7 @@
 %{!?with_multipath:     %global  with_multipath     256 }
 %{!?frr_user:           %global  frr_user           frr }
 %{!?vty_group:          %global  vty_group          frrvty }
-%{!?with_fpm:           %global  with_fpm           0 }
+%{!?with_fpm:           %global  with_fpm           1 }
 %{!?with_watchfrr:      %global  with_watchfrr      1 }
 %{!?with_bgp_vnc:       %global  with_bgp_vnc       0 }
 %{!?with_pimd:          %global  with_pimd          1 }
@@ -554,6 +554,9 @@ rm -rf %{buildroot}
 %{_libdir}/lib*.so.0
 %attr(755,root,root) %{_libdir}/lib*.so.0.*
 %endif
+%if %{with_fpm}
+%attr(755,root,root) %{_libdir}/frr/modules/zebra_fpm.so
+%endif
 %attr(755,root,root) %{_libdir}/frr/modules/zebra_irdp.so
 %{_bindir}/*
 %config(noreplace) /etc/frr/[!v]*.conf*
index 041635e1533d315ac329b0dffdddd8ba09e6d49c..4f02daed421c05d65372e46320a0c7516a345e9f 100644 (file)
@@ -56,6 +56,7 @@ static void rip_zebra_ipv4_send(struct route_node *rp, u_char cmd)
                if (count >= MULTIPATH_NUM)
                        break;
                api_nh = &api.nexthops[count];
+               api_nh->vrf_id = VRF_DEFAULT;
                api_nh->gate = rinfo->nh.gate;
                api_nh->type = NEXTHOP_TYPE_IPV4;
                if (cmd == ZEBRA_ROUTE_ADD)
index b5cbc96bc35bb595f4c5cbf0f2c972ca309f2e54..9a132504286e4b8e3627b6a4800efcc3ce5bcba4 100644 (file)
@@ -2319,13 +2319,15 @@ void rip_output_process(struct connected *ifc, struct sockaddr_in *to,
                                                          tmp_rinfo))
                                        if (tmp_rinfo->type == ZEBRA_ROUTE_RIP
                                            && tmp_rinfo->nh.ifindex
-                                                      == ifc->ifp->ifindex)
-                                               rinfo->metric_out =
+                                           == ifc->ifp->ifindex)
+                                               tmp_rinfo->metric_out =
                                                        RIP_METRIC_INFINITY;
-                               if (tmp_rinfo->type == ZEBRA_ROUTE_CONNECT
+
+                               if (rinfo->type == ZEBRA_ROUTE_CONNECT
                                    && prefix_match((struct prefix *)p,
                                                    ifc->address))
-                                       rinfo->metric_out = RIP_METRIC_INFINITY;
+                                       rinfo->metric_out =
+                                               RIP_METRIC_INFINITY;
                        }
 
                        /* Prepare preamble, auth headers, if needs be */
index 2902ff9cca1556103e0352d1903fab50f23bac35..e11bf0bb2362bbf5d5d8b75d61a22aaa6cbb07d7 100644 (file)
@@ -2,8 +2,6 @@
 !
 ! RIPd sample configuration file
 !
-! $Id: ripd.conf.sample,v 1.1 2002/12/13 20:15:30 paul Exp $
-!
 hostname ripd
 password zebra
 !
index 18a8d14f093e90c398ea8d86855c757a00f84220..6c9d911a6a3f392829c571c7d55680ef671b697b 100644 (file)
@@ -57,6 +57,7 @@ static void ripng_zebra_ipv6_send(struct route_node *rp, u_char cmd)
                if (count >= MULTIPATH_NUM)
                        break;
                api_nh = &api.nexthops[count];
+               api_nh->vrf_id = VRF_DEFAULT;
                api_nh->gate.ipv6 = rinfo->nexthop;
                api_nh->ifindex = rinfo->ifindex;
                api_nh->type = NEXTHOP_TYPE_IPV6_IFINDEX;
index ad673e57e0ba7d64c2d94e81b452510ceb82771a..28f08c399a674959c189e02889f8eeddf0b65bc4 100644 (file)
@@ -2,8 +2,6 @@
 !
 ! RIPngd sample configuration file
 !
-! $Id: ripngd.conf.sample,v 1.1 2002/12/13 20:15:30 paul Exp $
-!
 hostname ripngd
 password zebra
 !
diff --git a/sharpd/.gitignore b/sharpd/.gitignore
new file mode 100644 (file)
index 0000000..c396f3e
--- /dev/null
@@ -0,0 +1,18 @@
+Makefile
+Makefile.in
+*.o
+tags
+TAGS
+.deps
+.nfs*
+*.lo
+*.la
+*.a
+*.libs
+.arch-inventory
+.arch-ids
+*~
+*.loT
+*clippy.c
+sharpd
+sharpd.conf
index a35157faa19ef82dce174acb2a15b7b9ddeaa8f4..0e7d1f2c29758f4529f4cd051a690480a25b41f4 100644 (file)
@@ -26,6 +26,8 @@
 #include "prefix.h"
 #include "nexthop.h"
 #include "log.h"
+#include "vrf.h"
+#include "zclient.h"
 
 #include "sharpd/sharp_zebra.h"
 #include "sharpd/sharp_vty.h"
@@ -39,7 +41,8 @@ extern uint32_t removed_routes;
 
 DEFPY (install_routes,
        install_routes_cmd,
-       "install routes A.B.C.D$start nexthop A.B.C.D$nexthop (1-1000000)$routes",
+       "sharp install routes A.B.C.D$start nexthop A.B.C.D$nexthop (1-1000000)$routes",
+       "Sharp routing Protocol\n"
        "install some routes\n"
        "Routes to install\n"
        "Address to start /32 generation at\n"
@@ -76,9 +79,40 @@ DEFPY (install_routes,
        return CMD_SUCCESS;
 }
 
+DEFPY(vrf_label, vrf_label_cmd,
+      "sharp label <ip$ipv4|ipv6$ipv6> vrf NAME$name label (0-100000)$label",
+      "Sharp Routing Protocol\n"
+      "Give a vrf a label\n"
+      "Pop and forward for IPv4\n"
+      "Pop and forward for IPv6\n"
+      VRF_CMD_HELP_STR
+      "The label to use, 0 specifies remove the label installed from previous\n"
+      "Specified range to use\n")
+{
+       struct vrf *vrf;
+       afi_t afi = (ipv4) ? AFI_IP : AFI_IP6;
+
+       if (strcmp(name, "default") == 0)
+               vrf = vrf_lookup_by_id(VRF_DEFAULT);
+       else
+               vrf = vrf_lookup_by_name(name);
+
+       if (!vrf) {
+               vty_out(vty, "Unable to find vrf you silly head");
+               return CMD_WARNING_CONFIG_FAILED;
+       }
+
+       if (label == 0)
+               label = MPLS_LABEL_NONE;
+
+       vrf_label_add(vrf->vrf_id, afi, label);
+       return CMD_SUCCESS;
+}
+
 DEFPY (remove_routes,
        remove_routes_cmd,
-       "remove routes A.B.C.D$start (1-1000000)$routes",
+       "sharp remove routes A.B.C.D$start (1-1000000)$routes",
+       "Sharp Routing Protocol\n"
        "Remove some routes\n"
        "Routes to remove\n"
        "Starting spot\n"
@@ -112,5 +146,6 @@ void sharp_vty_init(void)
 {
        install_element(ENABLE_NODE, &install_routes_cmd);
        install_element(ENABLE_NODE, &remove_routes_cmd);
+       install_element(ENABLE_NODE, &vrf_label_cmd);
        return;
 }
index 4a5ae13c43415326eb761902f31956ca0c1187fe..78e8cf0adca4dd1363fc3f3c0d1e25662f51eb7a 100644 (file)
@@ -152,6 +152,11 @@ static void zebra_connected(struct zclient *zclient)
        zclient_send_reg_requests(zclient, VRF_DEFAULT);
 }
 
+void vrf_label_add(vrf_id_t vrf_id, afi_t afi, mpls_label_t label)
+{
+       zclient_send_vrf_label(zclient, vrf_id, afi, label, ZEBRA_LSP_SHARP);
+}
+
 void route_add(struct prefix *p, struct nexthop *nh)
 {
        struct zapi_route api;
@@ -166,6 +171,7 @@ void route_add(struct prefix *p, struct nexthop *nh)
        SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP);
 
        api_nh = &api.nexthops[0];
+       api_nh->vrf_id = VRF_DEFAULT;
        api_nh->gate.ipv4 = nh->gate.ipv4;
        api_nh->type = nh->type;
        api_nh->ifindex = nh->ifindex;
index 97100f61a64a47509462a25e7357ce763e8b1a72..0bba443bd48c43c6ee6c6f12069bd576f10f4b5e 100644 (file)
@@ -24,6 +24,7 @@
 
 extern void sharp_zebra_init(void);
 
+extern void vrf_label_add(vrf_id_t vrf_id, afi_t afi, mpls_label_t label);
 extern void route_add(struct prefix *p, struct nexthop *nh);
 extern void route_delete(struct prefix *p);
 #endif
index da7d68e0bca88b37790c7b90fcc798b6ea4c47cb..490a2ba787ebc3c1c936c4bc4a2364f735d99a0b 100644 (file)
@@ -13,6 +13,11 @@ sharpd_libsharp_a_SOURCES = \
        sharpd/sharp_vty.c \
        # end
 
+noinst_HEADERS += \
+       sharpd/sharp_vty.h \
+       sharpd/sharp_zebra.h \
+       # end
+
 sharpd/sharp_vty_clippy.c: $(CLIPPY_DEPS)
 sharpd/sharp_vty.$(OBJEXT): sharpd/sharp_vty_clippy.c
 
index 2ee05fa93549b35dacefe577e9d7f4c8f9140a87..f4ab2a126a2903d1bc186f61b71598399d56761b 100644 (file)
@@ -64,6 +64,7 @@ check_PROGRAMS = \
        lib/test_memory \
        lib/test_nexthop_iter \
        lib/test_privs \
+       lib/test_ringbuf \
        lib/test_srcdest_table \
        lib/test_segv \
        lib/test_sig \
@@ -116,6 +117,7 @@ lib_test_nexthop_iter_SOURCES = lib/test_nexthop_iter.c helpers/c/prng.c
 lib_test_privs_SOURCES = lib/test_privs.c
 lib_test_srcdest_table_SOURCES = lib/test_srcdest_table.c \
                                  helpers/c/prng.c
+lib_test_ringbuf_SOURCES = lib/test_ringbuf.c
 lib_test_segv_SOURCES = lib/test_segv.c
 lib_test_sig_SOURCES = lib/test_sig.c
 lib_test_stream_SOURCES = lib/test_stream.c
@@ -156,6 +158,7 @@ lib_test_heavy_LDADD = $(ALL_TESTS_LDADD) -lm
 lib_test_memory_LDADD = $(ALL_TESTS_LDADD)
 lib_test_nexthop_iter_LDADD = $(ALL_TESTS_LDADD)
 lib_test_privs_LDADD = $(ALL_TESTS_LDADD)
+lib_test_ringbuf_LDADD = $(ALL_TESTS_LDADD)
 lib_test_srcdest_table_LDADD = $(ALL_TESTS_LDADD)
 lib_test_segv_LDADD = $(ALL_TESTS_LDADD)
 lib_test_sig_LDADD = $(ALL_TESTS_LDADD)
@@ -196,6 +199,7 @@ EXTRA_DIST = \
     lib/cli/test_cli.py \
     lib/cli/test_cli.refout \
     lib/test_nexthop_iter.py \
+    lib/test_ringbuf.py \
     lib/test_srcdest_table.py \
     lib/test_stream.py \
     lib/test_stream.refout \
index 56808bc8ad05feeb40273450dbc2736486f1483b..9e5cb7fe54f4801db5e9d96bbbbea1a44de084b7 100644 (file)
@@ -25,8 +25,9 @@
 #include "privs.h"
 #include "queue.h"
 #include "filter.h"
+#include "frr_pthread.h"
 
-#include "bgpd/bgpd.h"
+#include "bgpd/bgpd.c"
 #include "bgpd/bgp_aspath.h"
 #include "bgpd/bgp_attr.h"
 #include "bgpd/bgp_packet.h"
@@ -1272,6 +1273,9 @@ static int handle_attr_test(struct aspath_tests *t)
        struct aspath *asp;
        size_t datalen;
 
+       bgp_pthreads_init();
+       frr_pthread_get(PTHREAD_KEEPALIVES)->running = true;
+
        asp = make_aspath(t->segment->asdata, t->segment->len, 0);
 
        peer.curr = stream_new(BGP_MAX_PACKET_SIZE);
index a5092708e2e03dca6ddb9b23d0102c3059383250..69f5afb992b077c75b3eca72717c77fdac0df42f 100644 (file)
@@ -27,8 +27,9 @@
 #include "memory.h"
 #include "queue.h"
 #include "filter.h"
+#include "frr_pthread.h"
 
-#include "bgpd/bgpd.h"
+#include "bgpd/bgpd.c"
 #include "bgpd/bgp_open.h"
 #include "bgpd/bgp_debug.h"
 #include "bgpd/bgp_packet.h"
@@ -62,8 +63,8 @@ static struct test_segment {
 
        /* AFI/SAFI validation */
        int validate_afi;
-       afi_t afi;
-       safi_t safi;
+       iana_afi_t afi;
+       iana_safi_t safi;
 #define VALID_AFI 1
 #define INVALID_AFI 0
        int afi_valid;
@@ -112,8 +113,8 @@ static struct test_segment mp_segments[] = {
                SHOULD_PARSE,
                0,
                1,
-               AFI_IP,
-               SAFI_UNICAST,
+               IANA_AFI_IPV4,
+               IANA_SAFI_UNICAST,
                VALID_AFI,
        },
        {
@@ -124,8 +125,8 @@ static struct test_segment mp_segments[] = {
                SHOULD_PARSE,
                0,
                1,
-               AFI_IP6,
-               SAFI_UNICAST,
+               IANA_AFI_IPV6,
+               IANA_SAFI_UNICAST,
                VALID_AFI,
        },
        /* 5 */
@@ -137,8 +138,8 @@ static struct test_segment mp_segments[] = {
                SHOULD_PARSE,
                0,
                1,
-               AFI_IP,
-               SAFI_MULTICAST,
+               IANA_AFI_IPV4,
+               IANA_SAFI_MULTICAST,
                VALID_AFI,
        },
        /* 6 */
@@ -150,7 +151,7 @@ static struct test_segment mp_segments[] = {
                SHOULD_PARSE,
                0,
                1,
-               AFI_IP6,
+               IANA_AFI_IPV6,
                IANA_SAFI_MPLS_VPN,
                VALID_AFI,
        },
@@ -163,7 +164,7 @@ static struct test_segment mp_segments[] = {
                SHOULD_PARSE,
                0,
                1,
-               AFI_IP6,
+               IANA_AFI_IPV6,
                IANA_SAFI_MPLS_VPN,
                VALID_AFI,
        },
@@ -176,7 +177,7 @@ static struct test_segment mp_segments[] = {
                SHOULD_PARSE,
                0,
                1,
-               AFI_IP,
+               IANA_AFI_IPV4,
                IANA_SAFI_MPLS_VPN,
                VALID_AFI,
        },
@@ -210,8 +211,8 @@ static struct test_segment mp_segments[] = {
                SHOULD_ERR,
                0,
                1,
-               AFI_IP,
-               SAFI_UNICAST,
+               IANA_AFI_IPV4,
+               IANA_SAFI_UNICAST,
                VALID_AFI,
        },
        {NULL, NULL, {0}, 0, 0}};
@@ -843,8 +844,7 @@ static void parse_test(struct peer *peer, struct test_segment *t, int type)
                safi_t safi;
 
                /* Convert AFI, SAFI to internal values, check. */
-               if (bgp_map_afi_safi_iana2int(afi_int2iana(t->afi), t->safi,
-                                             &afi, &safi)) {
+               if (bgp_map_afi_safi_iana2int(t->afi, t->safi, &afi, &safi)) {
                        if (t->afi_valid == VALID_AFI)
                                failed++;
                }
@@ -915,6 +915,9 @@ int main(void)
        vrf_init(NULL, NULL, NULL, NULL);
        bgp_option_set(BGP_OPT_NO_LISTEN);
 
+       bgp_pthreads_init();
+       frr_pthread_get(PTHREAD_KEEPALIVES)->running = true;
+
        if (fileno(stdout) >= 0)
                tty = isatty(fileno(stdout));
 
index 6df784b9848730498761f61d4f45a629d8df63bc..8acb280ed350ee8bb05fab25ed1733b1a9730103 100644 (file)
@@ -63,13 +63,6 @@ static struct test_segment {
 #define SHOULD_PARSE   0
 #define SHOULD_ERR     -1
        int parses; /* whether it should parse or not */
-
-       /* AFI/SAFI validation */
-       afi_t afi;
-       safi_t safi;
-#define VALID_AFI 1
-#define INVALID_AFI 0
-       int afi_valid;
 } mp_reach_segments[] = {
        {
                "IPv6",
@@ -104,9 +97,6 @@ static struct test_segment {
                },
                (4 + 16 + 1 + 5),
                SHOULD_PARSE,
-               AFI_IP6,
-               SAFI_UNICAST,
-               VALID_AFI,
        },
        {
                "IPv6-2",
@@ -150,9 +140,6 @@ static struct test_segment {
                },
                (4 + 16 + 1 + 5 + 9),
                SHOULD_PARSE,
-               AFI_IP6,
-               SAFI_UNICAST,
-               VALID_AFI,
        },
        {
                "IPv6-default",
@@ -197,9 +184,6 @@ static struct test_segment {
                },
                (4 + 16 + 1 + 5 + 9 + 1),
                SHOULD_PARSE,
-               AFI_IP6,
-               SAFI_UNICAST,
-               VALID_AFI,
        },
        {
                "IPv6-lnh",
@@ -260,9 +244,6 @@ static struct test_segment {
                },
                (4 + 32 + 1 + 5 + 9 + 1),
                SHOULD_PARSE,
-               AFI_IP6,
-               SAFI_UNICAST,
-               VALID_AFI,
        },
        {
                "IPv6-nhlen",
@@ -323,9 +304,6 @@ static struct test_segment {
                },
                (4 + 32 + 1 + 5 + 9 + 1),
                SHOULD_ERR,
-               AFI_IP6,
-               SAFI_UNICAST,
-               VALID_AFI,
        },
        {
                "IPv6-nhlen2",
@@ -386,9 +364,6 @@ static struct test_segment {
                },
                (4 + 32 + 1 + 5 + 9 + 1),
                SHOULD_ERR,
-               AFI_IP6,
-               SAFI_UNICAST,
-               VALID_AFI,
        },
        {
                "IPv6-nhlen3",
@@ -417,9 +392,6 @@ static struct test_segment {
                },
                (4 + 16),
                SHOULD_ERR,
-               AFI_IP6,
-               SAFI_UNICAST,
-               VALID_AFI,
        },
        {
                "IPv6-nhlen4",
@@ -480,9 +452,6 @@ static struct test_segment {
                },
                (4 + 32 + 1 + 5 + 9 + 1),
                SHOULD_ERR,
-               AFI_IP6,
-               SAFI_UNICAST,
-               VALID_AFI,
        },
        {
                "IPv6-nlri",
@@ -543,9 +512,6 @@ static struct test_segment {
                },
                (4 + 32 + 1 + 5 + 9 + 1),
                SHOULD_ERR,
-               AFI_IP6,
-               SAFI_UNICAST,
-               VALID_AFI,
        },
        {
                "IPv4",
@@ -561,9 +527,6 @@ static struct test_segment {
                },
                (4 + 4 + 1 + 3 + 4 + 1),
                SHOULD_PARSE,
-               AFI_IP,
-               SAFI_UNICAST,
-               VALID_AFI,
        },
        {
                "IPv4-nhlen",
@@ -579,9 +542,6 @@ static struct test_segment {
                },
                (4 + 4 + 1 + 3 + 4 + 1),
                SHOULD_ERR,
-               AFI_IP,
-               SAFI_UNICAST,
-               VALID_AFI,
        },
        {
                "IPv4-nlrilen",
@@ -596,9 +556,6 @@ static struct test_segment {
                },
                (4 + 4 + 1 + 3 + 2 + 1),
                SHOULD_ERR,
-               AFI_IP,
-               SAFI_UNICAST,
-               VALID_AFI,
        },
        {
                "IPv4-VPNv4",
@@ -623,9 +580,6 @@ static struct test_segment {
                },
                (4 + 12 + 1 + (1 + 3 + 8 + 2) + (1 + 3 + 8 + 3)),
                SHOULD_PARSE,
-               AFI_IP,
-               IANA_SAFI_MPLS_VPN,
-               VALID_AFI,
        },
        {
                "IPv4-VPNv4-bogus-plen",
@@ -659,9 +613,6 @@ static struct test_segment {
                },
                (3 + 1 + 3 * 4 + 1 + 3 + 4 + 1),
                SHOULD_ERR,
-               AFI_IP,
-               IANA_SAFI_MPLS_VPN,
-               VALID_AFI,
        },
        {
                "IPv4-VPNv4-plen1-short",
@@ -686,9 +637,6 @@ static struct test_segment {
                },
                (4 + 12 + 1 + (1 + 3 + 8 + 2) + (1 + 3 + 8 + 3)),
                SHOULD_ERR,
-               AFI_IP,
-               IANA_SAFI_MPLS_VPN,
-               VALID_AFI,
        },
        {
                "IPv4-VPNv4-plen1-long",
@@ -713,9 +661,6 @@ static struct test_segment {
                },
                (4 + 12 + 1 + (1 + 3 + 8 + 2) + (1 + 3 + 8 + 3)),
                SHOULD_ERR,
-               AFI_IP,
-               IANA_SAFI_MPLS_VPN,
-               VALID_AFI,
        },
        {
                "IPv4-VPNv4-plenn-long",
@@ -741,9 +686,6 @@ static struct test_segment {
                },
                (4 + 12 + 1 + (1 + 3 + 8 + 2) + (1 + 3 + 8 + 3) + 1),
                SHOULD_ERR,
-               AFI_IP,
-               IANA_SAFI_MPLS_VPN,
-               VALID_AFI,
        },
        {
                "IPv4-VPNv4-plenn-short",
@@ -768,9 +710,6 @@ static struct test_segment {
                },
                (4 + 12 + 1 + (1 + 3 + 8 + 2) + (1 + 3 + 8 + 3)),
                SHOULD_ERR,
-               AFI_IP,
-               IANA_SAFI_MPLS_VPN,
-               VALID_AFI,
        },
        {
                "IPv4-VPNv4-bogus-rd-type",
@@ -795,9 +734,6 @@ static struct test_segment {
                },
                (4 + 12 + 1 + (1 + 3 + 8 + 2) + (1 + 3 + 8 + 3)),
                SHOULD_PARSE,
-               AFI_IP,
-               IANA_SAFI_MPLS_VPN,
-               VALID_AFI,
        },
        {
                "IPv4-VPNv4-0-nlri",
@@ -823,9 +759,6 @@ static struct test_segment {
                },
                (4 + 12 + 1 + (1 + 3 + 8 + 2) + (1 + 3 + 8 + 3) + 1),
                SHOULD_ERR,
-               AFI_IP,
-               IANA_SAFI_MPLS_VPN,
-               VALID_AFI,
        },
 
        /* From bug #385 */
@@ -875,9 +808,6 @@ static struct test_segment {
                },
                37,
                SHOULD_ERR,
-               AFI_IP6,
-               SAFI_UNICAST,
-               VALID_AFI,
        },
 
        {NULL, NULL, {0}, 0, 0}};
@@ -894,9 +824,6 @@ static struct test_segment mp_unreach_segments[] = {
                },
                (3 + 5),
                SHOULD_PARSE,
-               AFI_IP6,
-               SAFI_UNICAST,
-               VALID_AFI,
        },
        {
                "IPv6-unreach2",
@@ -910,9 +837,6 @@ static struct test_segment mp_unreach_segments[] = {
                },
                (3 + 5 + 9),
                SHOULD_PARSE,
-               AFI_IP6,
-               SAFI_UNICAST,
-               VALID_AFI,
        },
        {
                "IPv6-unreach-default",
@@ -926,9 +850,6 @@ static struct test_segment mp_unreach_segments[] = {
                },
                (3 + 5 + 9 + 1),
                SHOULD_PARSE,
-               AFI_IP6,
-               SAFI_UNICAST,
-               VALID_AFI,
        },
        {
                "IPv6-unreach-nlri",
@@ -942,9 +863,6 @@ static struct test_segment mp_unreach_segments[] = {
                },
                (3 + 5 + 9 + 1),
                SHOULD_ERR,
-               AFI_IP6,
-               SAFI_UNICAST,
-               VALID_AFI,
        },
        {
                "IPv4-unreach",
@@ -957,9 +875,6 @@ static struct test_segment mp_unreach_segments[] = {
                },
                (3 + 3 + 4 + 1),
                SHOULD_PARSE,
-               AFI_IP,
-               SAFI_UNICAST,
-               VALID_AFI,
        },
        {
                "IPv4-unreach-nlrilen",
@@ -971,9 +886,6 @@ static struct test_segment mp_unreach_segments[] = {
                },
                (3 + 3 + 2 + 1),
                SHOULD_ERR,
-               AFI_IP,
-               SAFI_UNICAST,
-               VALID_AFI,
        },
        {
                "IPv4-unreach-VPNv4",
@@ -993,9 +905,6 @@ static struct test_segment mp_unreach_segments[] = {
                },
                (3 + (1 + 3 + 8 + 2) + (1 + 3 + 8 + 3)),
                SHOULD_PARSE,
-               AFI_IP,
-               IANA_SAFI_MPLS_VPN,
-               VALID_AFI,
        },
        {NULL, NULL, {0}, 0, 0}};
 
index 9bf56dde14d5dcccf6c9c72225a92c97751aa55b..fed1d5a53735f306cce0dcf0569459e4014184a7 100644 (file)
@@ -1,6 +1,4 @@
 /*
- * $Id: main.c,v 1.1 2005/04/25 16:42:24 paul Exp $
- *
  * This file is part of Quagga.
  *
  * Quagga is free software; you can redistribute it and/or modify it
index 604a5733cab493bb5181e4070db94a836d2005b8..e2a0a2d49a1e1c9c0c4c1d554d738db09a7ab682 100644 (file)
@@ -1,6 +1,4 @@
 /*
- * $Id: heavy.c,v 1.3 2005/04/25 16:42:24 paul Exp $
- *
  * This file is part of Quagga.
  *
  * Quagga is free software; you can redistribute it and/or modify it
index 9a75780060cdf391f83221eba1dafb3e7ac434f0..075bcb6daf7b5c6c2abca54f4a2738a3684a4dad 100644 (file)
@@ -1,6 +1,4 @@
 /*
- * $Id: heavy-thread.c,v 1.2 2005/04/25 16:42:24 paul Exp $
- *
  * This file is part of Quagga.
  *
  * Quagga is free software; you can redistribute it and/or modify it
index 1984f28e635d2a7dab84f15932cfaf2b38c44c3d..421c3454365761f7ec24a66662f3c7862f236148 100644 (file)
@@ -1,6 +1,4 @@
 /*
- * $Id: test-privs.c,v 1.1 2005/10/11 03:48:28 paul Exp $
- *
  * This file is part of Quagga.
  *
  * Quagga is free software; you can redistribute it and/or modify it
diff --git a/tests/lib/test_ringbuf.c b/tests/lib/test_ringbuf.c
new file mode 100644 (file)
index 0000000..7ba5a29
--- /dev/null
@@ -0,0 +1,190 @@
+/*
+ * Circular buffer tests.
+ * Copyright (C) 2017  Cumulus Networks
+ * Quentin Young
+ *
+ * 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 <memory.h>
+#include "ringbuf.h"
+
+static void validate_state(struct ringbuf *buf, size_t size, size_t contains)
+{
+       assert(buf->size == size);
+       assert(ringbuf_remain(buf) == contains);
+       assert(ringbuf_space(buf) == buf->size - contains);
+       assert(buf->empty != (bool)contains);
+}
+
+int main(int argc, char **argv)
+{
+       struct ringbuf *soil = ringbuf_new(BUFSIZ);
+
+       validate_state(soil, BUFSIZ, 0);
+
+       /* verify reset functionality on clean buffer */
+       printf("Validating reset on empty buffer...\n");
+       ringbuf_reset(soil);
+
+       validate_state(soil, BUFSIZ, 0);
+
+       /* put one byte */
+       printf("Validating write...\n");
+       uint8_t walnut = 47;
+       assert(ringbuf_put(soil, &walnut, sizeof(walnut)) == 1);
+
+       validate_state(soil, BUFSIZ, 1);
+
+       /* validate read limitations */
+       printf("Validating read limits...\n");
+       uint8_t nuts[2];
+       assert(ringbuf_get(soil, &nuts, sizeof(nuts)) == 1);
+
+       /* reset */
+       printf("Validating reset on full buffer...\n");
+       ringbuf_reset(soil);
+       validate_state(soil, BUFSIZ, 0);
+
+       /* copy stack garbage to buffer */
+       printf("Validating big write...\n");
+       uint8_t compost[BUFSIZ];
+       assert(ringbuf_put(soil, &compost, sizeof(compost)) == BUFSIZ);
+
+       validate_state(soil, BUFSIZ, BUFSIZ);
+       assert(soil->start == 0);
+       assert(soil->end == 0);
+
+       /* read 15 bytes of garbage */
+       printf("Validating read...\n");
+       assert(ringbuf_get(soil, &compost, 15) == 15);
+
+       validate_state(soil, BUFSIZ, BUFSIZ - 15);
+       assert(soil->start == 15);
+       assert(soil->end == 0);
+
+       /* put another 10 bytes and validate wraparound */
+       printf("Validating wraparound...\n");
+       assert(ringbuf_put(soil, &compost[BUFSIZ/2], 10) == 10);
+
+       validate_state(soil, BUFSIZ, BUFSIZ - 15 + 10);
+       assert(soil->start == 15);
+       assert(soil->end == 10);
+
+       /* put another 15 bytes and validate state */
+       printf("Validating size limits...\n");
+       assert(ringbuf_put(soil, &compost, 15) == 5);
+       validate_state(soil, BUFSIZ, BUFSIZ);
+
+       /* read entire buffer */
+       printf("Validating big read...\n");
+       assert(ringbuf_get(soil, &compost, BUFSIZ) == BUFSIZ);
+
+       validate_state(soil, BUFSIZ, 0);
+       assert(soil->empty = true);
+       assert(soil->start == soil->end);
+       assert(soil->start == 15);
+
+       /* read empty buffer */
+       printf("Validating empty read...\n");
+       assert(ringbuf_get(soil, &compost, 1) == 0);
+       validate_state(soil, BUFSIZ, 0);
+
+       /* reset, validate state */
+       printf("Validating reset...\n");
+       ringbuf_reset(soil);
+       validate_state(soil, BUFSIZ, 0);
+       assert(soil->start == 0);
+       assert(soil->end == 0);
+
+       /* wipe, validate state */
+       printf("Validating wipe...\n");
+       memset(&compost, 0x00, sizeof(compost));
+       ringbuf_wipe(soil);
+       assert(memcmp(&compost, soil->data, sizeof(compost)) == 0);
+
+       /* validate maximum write */
+       printf("Validating very big write...\n");
+       const char flower[BUFSIZ * 2];
+       assert(ringbuf_put(soil, &flower, sizeof(flower)) == BUFSIZ);
+
+       validate_state(soil, BUFSIZ, BUFSIZ);
+
+       /* wipe, validate state */
+       printf("Validating wipe...\n");
+       memset(&compost, 0x00, sizeof(compost));
+       ringbuf_wipe(soil);
+       assert(memcmp(&compost, soil->data, sizeof(compost)) == 0);
+
+       /* validate simple data encode / decode */
+       const char *organ = "seed";
+       printf("Encoding: '%s'\n", organ);
+       assert(ringbuf_put(soil, organ, strlen(organ)) == 4);
+       char water[strlen(organ) + 1];
+       assert(ringbuf_get(soil, &water, strlen(organ)) == 4);
+       water[strlen(organ)] = '\0';
+       printf("Retrieved: '%s'\n", water);
+
+       validate_state(soil, BUFSIZ, 0);
+
+       /* validate simple data encode / decode across ring boundary */
+       soil->start = soil->size - 2;
+       soil->end = soil->start;
+       const char *phloem = "root";
+       printf("Encoding: '%s'\n", phloem);
+       assert(ringbuf_put(soil, phloem, strlen(phloem)) == 4);
+       char xylem[strlen(phloem) + 1];
+       assert(ringbuf_get(soil, &xylem, 100) == 4);
+       xylem[strlen(phloem)] = '\0';
+       printf("Retrieved: '%s'\n", xylem);
+
+       ringbuf_wipe(soil);
+
+       /* validate simple data peek across ring boundary */
+       soil->start = soil->size - 2;
+       soil->end = soil->start;
+       const char *cytoplasm = "tree";
+       printf("Encoding: '%s'\n", cytoplasm);
+       assert(ringbuf_put(soil, cytoplasm, strlen(cytoplasm)) == 4);
+       char chloroplast[strlen(cytoplasm) + 1];
+       assert(ringbuf_peek(soil, 2, &chloroplast[0], 100) == 2);
+       assert(ringbuf_peek(soil, 0, &chloroplast[2], 2) == 2);
+       chloroplast[strlen(cytoplasm)] = '\0';
+       assert(!strcmp(chloroplast, "eetr"));
+       printf("Retrieved: '%s'\n", chloroplast);
+
+       printf("Deleting...\n");
+       ringbuf_del(soil);
+
+       printf("Creating new buffer...\n");
+       soil = ringbuf_new(15);
+       soil->start = soil->end = 7;
+
+       /* validate data encode of excessive data */
+       const char *twenty = "vascular plants----";
+       char sixteen[16];
+       printf("Encoding: %s\n", twenty);
+       assert(ringbuf_put(soil, twenty, strlen(twenty)) == 15);
+       assert(ringbuf_get(soil, sixteen, 20));
+       sixteen[15] = '\0';
+       printf("Retrieved: %s\n", sixteen);
+       assert(!strcmp(sixteen, "vascular plants"));
+
+       printf("Deleting...\n");
+       ringbuf_del(soil);
+
+       printf("Done.\n");
+       return 0;
+}
diff --git a/tests/lib/test_ringbuf.py b/tests/lib/test_ringbuf.py
new file mode 100644 (file)
index 0000000..860d872
--- /dev/null
@@ -0,0 +1,4 @@
+import frrtest
+
+class TestRingbuf(frrtest.TestExitNonzero):
+    program = './test_ringbuf'
index 2c651ffbd52c410ee0b6105fb50859ed5fdb2659..0b7e80962cbd6e582bce5b929d1e307014691591 100755 (executable)
@@ -434,7 +434,14 @@ end
                 new_ctx = False
                 log.debug('LINE %-50s: entering new context, %-50s', line, ctx_keys)
 
-            elif "vni " in line:
+            # The 'vni' keyword under 'router bgp X/address-family l2vpn evpn' creates
+            # a sub-context but the 'vni' keyword in other places (such as 'vrf BLUE')
+            # does not.
+            elif ("vni " in line and
+                len(ctx_keys) == 2 and
+                ctx_keys[0].startswith('router bgp') and
+                ctx_keys[1] == 'address-family l2vpn evpn'):
+
                 main_ctx_key = []
 
                 # Save old context first
index 8dc16f420922be9ebca533e846393a1720350423..6bf55b77405661decbe488af5c3006f4ac705b1a 100644 (file)
@@ -396,7 +396,7 @@ static void parse_schedule_item(const char *string, struct schedule_item *item)
 
        if (!strcmp(string, "forever")) {
                item->type = sched_forever;
-       } else if (isdigit(string[0])) {
+       } else if (isdigit((int)string[0])) {
                item->type = sched_timeout;
                if (parse_integer(string, &item->value) != 0)
                        badusage("invalid timeout value in schedule");
index 3ddb6aba54092765a4caea729beed5ad00d83047..c9b6f501606416c9c1207e6c8ef8ee190e45c9bc 100644 (file)
@@ -75,6 +75,7 @@ vtysh_scan += $(top_srcdir)/ospfd/ospf_opaque.c
 vtysh_scan += $(top_srcdir)/ospfd/ospf_ri.c
 vtysh_scan += $(top_srcdir)/ospfd/ospf_routemap.c
 vtysh_scan += $(top_srcdir)/ospfd/ospf_te.c
+vtysh_scan += $(top_srcdir)/ospfd/ospf_sr.c
 vtysh_scan += $(top_srcdir)/ospfd/ospf_vty.c
 endif
 
index 76343ded602cc0e6f053ddfa1642b75eee732316..65e9c9f8c51f107b398fc4079a22510b0599d4ca 100644 (file)
@@ -46,6 +46,9 @@
 
 DEFINE_MTYPE_STATIC(MVTYSH, VTYSH_CMD, "Vtysh cmd copy")
 
+/* Destination for vtysh output */
+FILE *outputfile;
+
 /* Struct VTY. */
 struct vty *vty;
 
@@ -138,16 +141,25 @@ static int vtysh_client_run(struct vtysh_client *vclient, const char *line,
 
                bufvalid += nread;
 
-               end = memmem(buf, bufvalid - buf, terminator,
-                            sizeof(terminator));
-               if (end + sizeof(terminator) + 1 > bufvalid)
+               if (bufvalid - buf >= 4)
+                       end = memmem(bufvalid - 4, 4, terminator,
+                                    sizeof(terminator));
+
+               if (end && end + sizeof(terminator) + 1 > bufvalid)
                        /* found \0\0\0 but return code hasn't been read yet */
                        end = NULL;
                if (end)
                        ret = end[sizeof(terminator)];
 
-               while (bufvalid > buf && (end > buf || !end)) {
-                       size_t textlen = (end ? end : bufvalid) - buf;
+               /*
+                * calculate # bytes we have, up to & not including the
+                * terminator if present
+                */
+               size_t textlen = (end ? end : bufvalid) - buf;
+
+               /* feed line processing callback if present */
+               while (callback && bufvalid > buf && (end > buf || !end)) {
+                       textlen = (end ? end : bufvalid) - buf;
                        char *eol = memchr(buf, '\n', textlen);
                        if (eol)
                                /* line break */
@@ -165,8 +177,7 @@ static int vtysh_client_run(struct vtysh_client *vclient, const char *line,
                                /* continue reading */
                                break;
 
-                       /* eol is at a line end now, either \n => \0 or \0\0\0
-                        */
+                       /* eol is at line end now, either \n => \0 or \0\0\0 */
                        assert(eol && eol <= bufvalid);
 
                        if (fp) {
@@ -186,6 +197,14 @@ static int vtysh_client_run(struct vtysh_client *vclient, const char *line,
                                end -= eol - buf;
                }
 
+               /* else if no callback, dump raw */
+               if (!callback) {
+                       if (fp)
+                               fwrite(buf, 1, textlen, fp);
+                       memmove(buf, buf + textlen, bufvalid - buf - textlen);
+                       bufvalid -= textlen;
+               }
+
                if (bufvalid == buf + bufsz) {
                        char *new;
                        bufsz *= 2;
@@ -375,21 +394,21 @@ static int vtysh_execute_func(const char *line, int pager)
                fprintf(stdout, "%% Command incomplete.\n");
                break;
        case CMD_SUCCESS_DAEMON: {
-               /* FIXME: Don't open pager for exit commands. popen() causes
-                * problems
-                * if exited from vtysh at all. This hack shouldn't cause any
-                * problem
-                * but is really ugly. */
-               if (pager && vtysh_pager_name
+               /*
+                * FIXME: Don't open pager for exit commands. popen() causes
+                * problems if exited from vtysh at all. This hack shouldn't
+                * cause any problem but is really ugly.
+                */
+               fp = outputfile;
+               if (pager && vtysh_pager_name && outputfile == stdout
                    && (strncmp(line, "exit", 4) != 0)) {
                        fp = popen(vtysh_pager_name, "w");
                        if (fp == NULL) {
                                perror("popen failed for pager");
-                               fp = stdout;
+                               fp = outputfile;
                        } else
                                closepager = 1;
-               } else
-                       fp = stdout;
+               }
 
                if (!strcmp(cmd->string, "configure terminal")) {
                        for (i = 0; i < array_size(vtysh_client); i++) {
@@ -405,7 +424,7 @@ static int vtysh_execute_func(const char *line, int pager)
 
                                if (vline == NULL) {
                                        if (pager && vtysh_pager_name && fp
-                                           && closepager) {
+                                           && fp != outputfile && closepager) {
                                                if (pclose(fp) == -1) {
                                                        perror("pclose failed for pager");
                                                }
@@ -455,7 +474,7 @@ static int vtysh_execute_func(const char *line, int pager)
                        (*cmd->func)(cmd, vty, 0, NULL);
        }
        }
-       if (pager && vtysh_pager_name && fp && closepager) {
+       if (pager && vtysh_pager_name && fp && closepager && fp != outputfile) {
                if (pclose(fp) == -1) {
                        perror("pclose failed for pager");
                }
@@ -485,11 +504,11 @@ static char *trim(char *s)
                return s;
 
        end = s + size - 1;
-       while (end >= s && isspace(*end))
+       while (end >= s && isspace((int)*end))
                end--;
        *(end + 1) = '\0';
 
-       while (*s && isspace(*s))
+       while (*s && isspace((int)*s))
                s++;
 
        return s;
@@ -537,19 +556,19 @@ int vtysh_mark_file(const char *filename)
                switch (vty->node) {
                case LDP_IPV4_IFACE_NODE:
                        if (strncmp(vty_buf_copy, "   ", 3)) {
-                               fprintf(stdout, "  end\n");
+                               fprintf(outputfile, "  end\n");
                                vty->node = LDP_IPV4_NODE;
                        }
                        break;
                case LDP_IPV6_IFACE_NODE:
                        if (strncmp(vty_buf_copy, "   ", 3)) {
-                               fprintf(stdout, "  end\n");
+                               fprintf(outputfile, "  end\n");
                                vty->node = LDP_IPV6_NODE;
                        }
                        break;
                case LDP_PSEUDOWIRE_NODE:
                        if (strncmp(vty_buf_copy, "  ", 2)) {
-                               fprintf(stdout, " end\n");
+                               fprintf(outputfile, " end\n");
                                vty->node = LDP_L2VPN_NODE;
                        }
                        break;
@@ -558,7 +577,7 @@ int vtysh_mark_file(const char *filename)
                }
 
                if (vty_buf_trimmed[0] == '!' || vty_buf_trimmed[0] == '#') {
-                       fprintf(stdout, "%s", vty->buf);
+                       fprintf(outputfile, "%s", vty->buf);
                        continue;
                }
 
@@ -566,7 +585,7 @@ int vtysh_mark_file(const char *filename)
                vline = cmd_make_strvec(vty->buf);
 
                if (vline == NULL) {
-                       fprintf(stdout, "%s", vty->buf);
+                       fprintf(outputfile, "%s", vty->buf);
                        continue;
                }
 
@@ -609,15 +628,15 @@ int vtysh_mark_file(const char *filename)
                             || prev_node == BGP_IPV6M_NODE
                             || prev_node == BGP_EVPN_NODE)
                            && (tried == 1)) {
-                               fprintf(stdout, "exit-address-family\n");
+                               fprintf(outputfile, "exit-address-family\n");
                        } else if ((prev_node == BGP_EVPN_VNI_NODE)
                                   && (tried == 1)) {
-                               fprintf(stdout, "exit-vni\n");
+                               fprintf(outputfile, "exit-vni\n");
                        } else if ((prev_node == KEYCHAIN_KEY_NODE)
                                   && (tried == 1)) {
-                               fprintf(stdout, "exit\n");
+                               fprintf(outputfile, "exit\n");
                        } else if (tried) {
-                               fprintf(stdout, "end\n");
+                               fprintf(outputfile, "end\n");
                        }
                }
                /* If command didn't succeed in any node, continue with return
@@ -667,12 +686,12 @@ int vtysh_mark_file(const char *filename)
                        u_int i;
                        int cmd_stat = CMD_SUCCESS;
 
-                       fprintf(stdout, "%s", vty->buf);
+                       fprintf(outputfile, "%s", vty->buf);
                        for (i = 0; i < array_size(vtysh_client); i++) {
                                if (cmd->daemon & vtysh_client[i].flag) {
                                        cmd_stat = vtysh_client_execute(
                                                &vtysh_client[i], vty->buf,
-                                               stdout);
+                                               outputfile);
                                        if (cmd_stat != CMD_SUCCESS)
                                                break;
                                }
@@ -686,7 +705,7 @@ int vtysh_mark_file(const char *filename)
                }
        }
        /* This is the end */
-       fprintf(stdout, "\nend\n");
+       fprintf(outputfile, "\nend\n");
        vty_close(vty);
        XFREE(MTYPE_VTYSH_CMD, vty_buf_copy);
 
@@ -749,7 +768,7 @@ int vtysh_config_from_file(struct vty *vty, FILE *fp)
                                if (cmd->daemon & vtysh_client[i].flag) {
                                        cmd_stat = vtysh_client_execute(
                                                &vtysh_client[i], vty->buf,
-                                               stdout);
+                                               outputfile);
                                        /*
                                         * CMD_WARNING - Can mean that the
                                         * command was
@@ -1854,7 +1873,7 @@ DEFUN (vtysh_show_thread,
                        fprintf(stdout, "Thread statistics for %s:\n",
                                vtysh_client[i].name);
                        ret = vtysh_client_execute(&vtysh_client[i], line,
-                                                  stdout);
+                                                  outputfile);
                        fprintf(stdout, "\n");
                }
        return ret;
@@ -1875,7 +1894,7 @@ DEFUN (vtysh_show_work_queues,
                        fprintf(stdout, "Work queue statistics for %s:\n",
                                vtysh_client[i].name);
                        ret = vtysh_client_execute(&vtysh_client[i], line,
-                                                  stdout);
+                                                  outputfile);
                        fprintf(stdout, "\n");
                }
 
@@ -1905,7 +1924,7 @@ DEFUN (vtysh_show_work_queues_daemon,
        }
 
        ret = vtysh_client_execute(&vtysh_client[i], "show work-queues\n",
-                                  stdout);
+                                  outputfile);
 
        return ret;
 }
@@ -1932,9 +1951,9 @@ static int show_per_daemon(const char *line, const char *headline)
 
        for (i = 0; i < array_size(vtysh_client); i++)
                if (vtysh_client[i].fd >= 0) {
-                       fprintf(stdout, headline, vtysh_client[i].name);
+                       fprintf(outputfile, headline, vtysh_client[i].name);
                        ret = vtysh_client_execute(&vtysh_client[i], line,
-                                                  stdout);
+                                                  outputfile);
                        fprintf(stdout, "\n");
                }
 
@@ -2226,20 +2245,19 @@ DEFUN (vtysh_write_terminal,
 {
        u_int i;
        char line[] = "do write terminal\n";
-       FILE *fp = NULL;
+       FILE *fp = outputfile;
 
-       if (vtysh_pager_name) {
+       if (fp == stdout && vtysh_pager_name) {
                fp = popen(vtysh_pager_name, "w");
                if (fp == NULL) {
                        perror("popen");
                        exit(1);
                }
-       } else
-               fp = stdout;
+       }
 
-       vty_out(vty, "Building configuration...\n");
-       vty_out(vty, "\nCurrent configuration:\n");
-       vty_out(vty, "!\n");
+       fprintf(outputfile, "Building configuration...\n");
+       fprintf(outputfile, "\nCurrent configuration:\n");
+       fprintf(outputfile, "!\n");
 
        for (i = 0; i < array_size(vtysh_client); i++)
                if ((argc < 3)
@@ -2251,7 +2269,7 @@ DEFUN (vtysh_write_terminal,
 
        vtysh_config_dump(fp);
 
-       if (vtysh_pager_name && fp) {
+       if (vtysh_pager_name && fp && fp != outputfile) {
                fflush(fp);
                if (pclose(fp) == -1) {
                        perror("pclose");
@@ -2260,7 +2278,7 @@ DEFUN (vtysh_write_terminal,
                fp = NULL;
        }
 
-       vty_out(vty, "end\n");
+       fprintf(outputfile, "end\n");
        return CMD_SUCCESS;
 }
 
@@ -2429,7 +2447,7 @@ DEFUN (vtysh_write_memory,
        char line[] = "do write memory\n";
        u_int i;
 
-       fprintf(stdout,
+       fprintf(outputfile,
                "Note: this version of vtysh never writes vtysh.conf\n");
 
        /* If integrated frr.conf explicitely set. */
@@ -2441,7 +2459,7 @@ DEFUN (vtysh_write_memory,
                if (i < array_size(vtysh_client) && vtysh_client[i].fd != -1)
                        ret = vtysh_client_execute(&vtysh_client[i],
                                                   "do write integrated",
-                                                  stdout);
+                                                  outputfile);
 
                if (ret != CMD_SUCCESS) {
                        printf("\nWarning: attempting direct configuration write without "
@@ -2452,10 +2470,10 @@ DEFUN (vtysh_write_memory,
                return ret;
        }
 
-       fprintf(stdout, "Building Configuration...\n");
+       fprintf(outputfile, "Building Configuration...\n");
 
        for (i = 0; i < array_size(vtysh_client); i++)
-               ret = vtysh_client_execute(&vtysh_client[i], line, stdout);
+               ret = vtysh_client_execute(&vtysh_client[i], line, outputfile);
 
        return ret;
 }
@@ -2484,7 +2502,7 @@ DEFUN (vtysh_terminal_length,
 
        lines = strtol(argv[idx_number]->arg, &endptr, 10);
        if (lines < 0 || lines > 512 || *endptr != '\0') {
-               vty_out(vty, "length is malformed\n");
+               fprintf(outputfile, "length is malformed\n");
                return CMD_WARNING;
        }
 
@@ -2527,8 +2545,8 @@ DEFUN (vtysh_show_daemons,
 
        for (i = 0; i < array_size(vtysh_client); i++)
                if (vtysh_client[i].fd >= 0)
-                       vty_out(vty, " %s", vtysh_client[i].name);
-       vty_out(vty, "\n");
+                       fprintf(outputfile, " %s", vtysh_client[i].name);
+       fprintf(outputfile, "\n");
 
        return CMD_SUCCESS;
 }
@@ -2610,6 +2628,19 @@ ALIAS(vtysh_traceroute, vtysh_traceroute_ip_cmd, "traceroute ip WORD",
       "IP trace\n"
       "Trace route to destination address or hostname\n")
 
+DEFUN (vtysh_mtrace,
+       vtysh_mtrace_cmd,
+       "mtrace WORD",
+       "Multicast trace route to multicast source\n"
+       "Multicast trace route to multicast source address\n")
+{
+       int idx = 1;
+
+       argv_find(argv, argc, "WORD", &idx);
+       execute_command("mtracebis", 1, argv[idx]->arg, NULL);
+       return CMD_SUCCESS;
+}
+
 DEFUN (vtysh_ping6,
        vtysh_ping6_cmd,
        "ping ipv6 WORD",
@@ -2703,6 +2734,38 @@ DEFUN (config_list,
        return cmd_list_cmds(vty, argc == 2);
 }
 
+DEFUN (vtysh_output_file,
+       vtysh_output_file_cmd,
+       "output file FILE",
+       "Direct vtysh output to file\n"
+       "Direct vtysh output to file\n"
+       "Path to dump output to\n")
+{
+       const char *path = argv[argc - 1]->arg;
+       outputfile = fopen(path, "a");
+       if (!outputfile) {
+               fprintf(stdout, "Failed to open file '%s': %s\n", path,
+                       safe_strerror(errno));
+               outputfile = stdout;
+       }
+       return CMD_SUCCESS;
+}
+
+DEFUN (no_vtysh_output_file,
+       no_vtysh_output_file_cmd,
+       "no output file [FILE]",
+       NO_STR
+       "Direct vtysh output to file\n"
+       "Direct vtysh output to file\n"
+       "Path to dump output to\n")
+{
+       if (outputfile != stdout) {
+               fclose(outputfile);
+               outputfile = stdout;
+       }
+       return CMD_SUCCESS;
+}
+
 DEFUN(find,
       find_cmd,
       "find COMMAND...",
@@ -2736,6 +2799,8 @@ static void vtysh_install_default(enum node_type node)
 {
        install_element(node, &config_list_cmd);
        install_element(node, &find_cmd);
+       install_element(node, &vtysh_output_file_cmd);
+       install_element(node, &no_vtysh_output_file_cmd);
 }
 
 /* Making connection to protocol daemon. */
@@ -2964,6 +3029,12 @@ static const struct cmd_variable_handler vtysh_var_handler[] = {
         .completions = vtysh_autocomplete},
        {.completions = NULL}};
 
+void vtysh_uninit()
+{
+       if (outputfile != stdout)
+               fclose(outputfile);
+}
+
 void vtysh_init_vty(void)
 {
        /* Make vty structure. */
@@ -2971,6 +3042,9 @@ void vtysh_init_vty(void)
        vty->type = VTY_SHELL;
        vty->node = VIEW_NODE;
 
+       /* set default output */
+       outputfile = stdout;
+
        /* Initialize commands. */
        cmd_init(0);
        cmd_variable_handler_register(vtysh_var_handler);
@@ -3266,6 +3340,7 @@ void vtysh_init_vty(void)
        install_element(VIEW_NODE, &vtysh_ping_ip_cmd);
        install_element(VIEW_NODE, &vtysh_traceroute_cmd);
        install_element(VIEW_NODE, &vtysh_traceroute_ip_cmd);
+       install_element(VIEW_NODE, &vtysh_mtrace_cmd);
        install_element(VIEW_NODE, &vtysh_ping6_cmd);
        install_element(VIEW_NODE, &vtysh_traceroute6_cmd);
 #if defined(HAVE_SHELL_ACCESS)
index c584d7a9058ff70c915fa35f90c1aefcaf42f5bc..ab13182094bff30a4dd33d5e2cca41c7b3b8327b 100644 (file)
@@ -63,6 +63,7 @@ extern char frr_config[];
 extern char vtydir[];
 
 void vtysh_init_vty(void);
+void vtysh_uninit(void);
 void vtysh_init_cmd(void);
 extern int vtysh_connect_all(const char *optional_daemon_name);
 void vtysh_readline_init(void);
index 138a4463212d684b91b44ebad3bc2c520caf363b..967f855fbc45fff1c96df49aea448196457a721f 100644 (file)
@@ -352,13 +352,15 @@ void vtysh_config_dump(FILE *fp)
        for (i = 0; i < vector_active(configvec); i++)
                if ((master = vector_slot(configvec, i)) != NULL) {
                        for (ALL_LIST_ELEMENTS(master, node, nnode, config)) {
-                               /* Don't print empty sections for interface/vrf.
+                               /* Don't print empty sections for interface.
                                 * Route maps on the
                                 * other hand could have a legitimate empty
                                 * section at the end.
+                                * VRF is handled in the backend, we could have
+                                * "configured" VRFs with static routes which
+                                * are not under the VRF node.
                                 */
-                               if ((config->index == INTERFACE_NODE
-                                    || config->index == VRF_NODE)
+                               if (config->index == INTERFACE_NODE
                                    && list_isempty(config->line))
                                        continue;
 
index 57042f8e620949a788f2ec65ccbe446d9861bcc4..a4985c423ca36aca279c5a84b02fdd925e5f9c0a 100644 (file)
@@ -644,6 +644,8 @@ int main(int argc, char **argv, char **env)
        while (vtysh_rl_gets())
                vtysh_execute(line_read);
 
+       vtysh_uninit();
+
        history_truncate_file(history_file, 1000);
        printf("\n");
 
index 18dc6a970b5427d7374cc6a79665fdc500cce680..e28ec8d09b6e401f1446736ef8b97b38b5420acd 100644 (file)
@@ -203,7 +203,9 @@ void connected_up(struct interface *ifp, struct connected *ifc)
        afi_t afi;
        struct prefix p;
        struct nexthop nh = {
-               .type = NEXTHOP_TYPE_IFINDEX, .ifindex = ifp->ifindex,
+               .type = NEXTHOP_TYPE_IFINDEX,
+               .ifindex = ifp->ifindex,
+               .vrf_id = ifp->vrf_id,
        };
 
        if (!CHECK_FLAG(ifc->conf, ZEBRA_IFC_REAL))
@@ -238,11 +240,11 @@ void connected_up(struct interface *ifp, struct connected *ifc)
                break;
        }
 
-       rib_add(afi, SAFI_UNICAST, ifp->vrf_id, ZEBRA_ROUTE_CONNECT, 0, 0,
-               &p, NULL, &nh, RT_TABLE_MAIN, ifp->metric, 0, 0);
+       rib_add(afi, SAFI_UNICAST, ifp->vrf_id, ZEBRA_ROUTE_CONNECT, 0, 0, &p,
+               NULL, &nh, RT_TABLE_MAIN, ifp->metric, 0, 0, 0);
 
-       rib_add(afi, SAFI_MULTICAST, ifp->vrf_id, ZEBRA_ROUTE_CONNECT, 0, 0,
-               &p, NULL, &nh, RT_TABLE_MAIN, ifp->metric, 0, 0);
+       rib_add(afi, SAFI_MULTICAST, ifp->vrf_id, ZEBRA_ROUTE_CONNECT, 0, 0, &p,
+               NULL, &nh, RT_TABLE_MAIN, ifp->metric, 0, 0, 0);
 
        if (IS_ZEBRA_DEBUG_RIB_DETAILED) {
                char buf[PREFIX_STRLEN];
@@ -360,7 +362,9 @@ void connected_down(struct interface *ifp, struct connected *ifc)
        afi_t afi;
        struct prefix p;
        struct nexthop nh = {
-               .type = NEXTHOP_TYPE_IFINDEX, .ifindex = ifp->ifindex,
+               .type = NEXTHOP_TYPE_IFINDEX,
+               .ifindex = ifp->ifindex,
+               .vrf_id = ifp->vrf_id,
        };
 
        if (!CHECK_FLAG(ifc->conf, ZEBRA_IFC_REAL))
@@ -396,10 +400,10 @@ void connected_down(struct interface *ifp, struct connected *ifc)
         * head.
         */
        rib_delete(afi, SAFI_UNICAST, ifp->vrf_id, ZEBRA_ROUTE_CONNECT, 0, 0,
-                  &p, NULL, &nh, 0, 0, false);
+                  &p, NULL, &nh, 0, 0, false, NULL);
 
        rib_delete(afi, SAFI_MULTICAST, ifp->vrf_id, ZEBRA_ROUTE_CONNECT, 0,
-                  0, &p, NULL, &nh, 0, 0, false);
+                  0, &p, NULL, &nh, 0, 0, false, NULL);
 
        if (IS_ZEBRA_DEBUG_RIB_DETAILED) {
                char buf[PREFIX_STRLEN];
index f73506bf9195a6abf3434517cd67c4d48c16aa2b..14905b738bf537929eb5ebb1944472dabd19b833 100644 (file)
@@ -387,6 +387,11 @@ static int get_iflink_speed(const char *ifname)
        return (ecmd.speed_hi << 16) | ecmd.speed;
 }
 
+uint32_t kernel_get_speed(struct interface *ifp)
+{
+       return get_iflink_speed(ifp->name);
+}
+
 static int netlink_extract_bridge_info(struct rtattr *link_data,
                                       struct zebra_l2info_bridge *bridge_info)
 {
index 18588ee52cfd2154f296d731f1ab36a4dffb3402..07570e64bfc2c32f5d045aee3396cd587fdd8a43 100644 (file)
@@ -57,8 +57,29 @@ DEFINE_HOOK(zebra_if_extra_info, (struct vty *vty, struct interface *ifp),
 DEFINE_HOOK(zebra_if_config_wr, (struct vty *vty, struct interface *ifp),
                                (vty, ifp))
 
+
 static void if_down_del_nbr_connected(struct interface *ifp);
 
+static int if_zebra_speed_update(struct thread *thread)
+{
+       struct interface *ifp = THREAD_ARG(thread);
+       struct zebra_if *zif = ifp->info;
+       uint32_t new_speed;
+
+       zif->speed_update = NULL;
+
+       new_speed = kernel_get_speed(ifp);
+       if (new_speed != ifp->speed) {
+               zlog_info("%s: %s old speed: %u new speed: %u",
+                         __PRETTY_FUNCTION__, ifp->name,
+                         ifp->speed, new_speed);
+               ifp->speed = new_speed;
+               if_add_update(ifp);
+       }
+
+       return 1;
+}
+
 static void zebra_if_node_destroy(route_table_delegate_t *delegate,
                                  struct route_table *table,
                                  struct route_node *node)
@@ -119,6 +140,16 @@ static int if_zebra_new_hook(struct interface *ifp)
                route_table_init_with_delegate(&zebra_if_table_delegate);
 
        ifp->info = zebra_if;
+
+       /*
+        * Some platforms are telling us that the interface is
+        * up and ready to go.  When we check the speed we
+        * sometimes get the wrong value.  Wait a couple
+        * of seconds and ask again.  Hopefully it's all settled
+        * down upon startup.
+        */
+       thread_add_timer(zebrad.master, if_zebra_speed_update,
+                        ifp, 15, &zebra_if->speed_update);
        return 0;
 }
 
@@ -141,6 +172,8 @@ static int if_zebra_delete_hook(struct interface *ifp)
                list_delete_and_null(&rtadv->AdvPrefixList);
 #endif /* HAVE_RTADV */
 
+               THREAD_OFF(zebra_if->speed_update);
+
                XFREE(MTYPE_TMP, zebra_if);
        }
 
@@ -735,7 +768,8 @@ void if_handle_vrf_change(struct interface *ifp, vrf_id_t vrf_id)
        zebra_interface_vrf_update_add(ifp, old_vrf_id);
 
        /* Install connected routes (in new VRF). */
-       if_install_connected(ifp);
+       if (if_is_operative(ifp))
+               if_install_connected(ifp);
 
        static_ifindex_update(ifp, true);
 
index 61c3359f3b32c3e488360a5865113711671a4acd..e13721448c680f446960cec8332c6e18a788fd05 100644 (file)
@@ -273,6 +273,8 @@ struct zebra_if {
        /* Link fields - for sub-interfaces. */
        ifindex_t link_ifindex;
        struct interface *link;
+
+       struct thread *speed_update;
 };
 
 DECLARE_HOOK(zebra_if_extra_info, (struct vty *vty, struct interface *ifp),
index 36212a0132826c7082ba727a46b356ec10d29d7b..cdf426b9b8ff268f21e59e04fd5f5da361c6e56d 100644 (file)
@@ -87,11 +87,11 @@ int ipforward_off(void)
 
 /* IPv6 forwarding control MIB. */
 int mib_ipv6[MIB_SIZ] = {CTL_NET, PF_INET6,
-#if defined(KAME)
+#if defined(BSD_V6_SYSCTL)
                         IPPROTO_IPV6, IPV6CTL_FORWARDING
-#else  /* NOT KAME */
+#else  /* NOT BSD_V6_SYSCTL */
                         IPPROTO_IP, IP6CTL_FORWARDING
-#endif /* KAME */
+#endif /* BSD_V6_SYSCTL */
 };
 
 int ipforward_ipv6(void)
index 89c933f90ff53f8d40e953bccfda264b81eb2d63..4d888d80695ceb576a912c76dfc2e3d45f7a263a 100644 (file)
@@ -40,6 +40,7 @@
 #include "privs.h"
 #include "vrf.h"
 
+#include "zebra/rt.h"
 #include "zebra/interface.h"
 #include "zebra/zserv.h"
 #include "zebra/debug.h"
@@ -906,6 +907,8 @@ void rtm_read(struct rt_msghdr *rtm)
                SET_FLAG(zebra_flags, ZEBRA_FLAG_STATIC);
 
        memset(&nh, 0, sizeof(nh));
+
+       nh.vrf_id = VRF_DEFAULT;
        /* This is a reject or blackhole route */
        if (flags & RTF_REJECT) {
                nh.type = NEXTHOP_TYPE_BLACKHOLE;
@@ -1039,7 +1042,7 @@ void rtm_read(struct rt_msghdr *rtm)
                if (rtm->rtm_type == RTM_CHANGE)
                        rib_delete(AFI_IP, SAFI_UNICAST, VRF_DEFAULT,
                                   ZEBRA_ROUTE_KERNEL, 0, zebra_flags, &p, NULL,
-                                  NULL, 0, 0, true);
+                                  NULL, 0, 0, true, NULL);
 
                if (!nh.type) {
                        nh.type = NEXTHOP_TYPE_IPV4;
@@ -1050,11 +1053,11 @@ void rtm_read(struct rt_msghdr *rtm)
                    || rtm->rtm_type == RTM_CHANGE)
                        rib_add(AFI_IP, SAFI_UNICAST, VRF_DEFAULT,
                                ZEBRA_ROUTE_KERNEL, 0, zebra_flags, &p, NULL,
-                               &nh, 0, 0, 0, 0);
+                               &nh, 0, 0, 0, 0, 0);
                else
                        rib_delete(AFI_IP, SAFI_UNICAST, VRF_DEFAULT,
                                   ZEBRA_ROUTE_KERNEL, 0, zebra_flags, &p, NULL,
-                                  &nh, 0, 0, true);
+                                  &nh, 0, 0, true, NULL);
        }
        if (dest.sa.sa_family == AF_INET6) {
                /* One day we might have a debug section here like one in the
@@ -1085,7 +1088,7 @@ void rtm_read(struct rt_msghdr *rtm)
                if (rtm->rtm_type == RTM_CHANGE)
                        rib_delete(AFI_IP6, SAFI_UNICAST, VRF_DEFAULT,
                                   ZEBRA_ROUTE_KERNEL, 0, zebra_flags, &p, NULL,
-                                  NULL, 0, 0, true);
+                                  NULL, 0, 0, true, NULL);
 
                if (!nh.type) {
                        nh.type = ifindex ? NEXTHOP_TYPE_IPV6_IFINDEX
@@ -1098,11 +1101,11 @@ void rtm_read(struct rt_msghdr *rtm)
                    || rtm->rtm_type == RTM_CHANGE)
                        rib_add(AFI_IP6, SAFI_UNICAST, VRF_DEFAULT,
                                ZEBRA_ROUTE_KERNEL, 0, zebra_flags, &p, NULL,
-                               &nh, 0, 0, 0, 0);
+                               &nh, 0, 0, 0, 0, 0);
                else
                        rib_delete(AFI_IP6, SAFI_UNICAST, VRF_DEFAULT,
                                   ZEBRA_ROUTE_KERNEL, 0, zebra_flags, &p, NULL,
-                                  &nh, 0, 0, true);
+                                  &nh, 0, 0, true, NULL);
        }
 }
 
@@ -1194,7 +1197,7 @@ int rtm_write(int message, union sockunion *dest, union sockunion *mask,
                msg.rtm.rtm_flags |= RTF_MPLS;
 
                if (mpls->smpls.smpls_label
-                   != htonl(MPLS_IMP_NULL_LABEL << MPLS_LABEL_OFFSET))
+                   != htonl(MPLS_LABEL_IMPLICIT_NULL << MPLS_LABEL_OFFSET))
                        msg.rtm.rtm_mpls = MPLS_OP_PUSH;
        }
 #endif
index bf4522b70f52dcf2354866ec97921b9a7fd73b77..5bf0fce0947d582196d419f3e1bc78614005126f 100644 (file)
@@ -41,6 +41,8 @@
 
 struct label_manager lbl_mgr;
 
+extern struct zebra_privs_t zserv_privs;
+
 DEFINE_MGROUP(LBL_MGR, "Label Manager");
 DEFINE_MTYPE_STATIC(LBL_MGR, LM_CHUNK, "Label Manager Chunk");
 
@@ -119,7 +121,7 @@ static int reply_error(int cmd, struct zserv *zserv, vrf_id_t vrf_id)
        s = zserv->obuf;
        stream_reset(s);
 
-       zserv_create_header(s, cmd, vrf_id);
+       zclient_create_header(s, cmd, vrf_id);
 
        /* result */
        stream_putc(s, 1);
@@ -222,6 +224,7 @@ static void lm_zclient_init(char *lm_zserv_path)
 
        /* Set default values. */
        zclient = zclient_new_notify(zebrad.master, &zclient_options_default);
+       zclient->privs = &zserv_privs;
        zclient->sock = -1;
        zclient->t_connect = NULL;
        lm_zclient_connect(NULL);
@@ -280,13 +283,13 @@ struct label_manager_chunk *assign_label_chunk(u_char proto, u_short instance,
                return NULL;
 
        if (list_isempty(lbl_mgr.lc_list))
-               lmc->start = MPLS_MIN_UNRESERVED_LABEL;
+               lmc->start = MPLS_LABEL_UNRESERVED_MIN;
        else
                lmc->start = ((struct label_manager_chunk *)listgetdata(
                                      listtail(lbl_mgr.lc_list)))
                                     ->end
                             + 1;
-       if (lmc->start > MPLS_MAX_UNRESERVED_LABEL - size + 1) {
+       if (lmc->start > MPLS_LABEL_UNRESERVED_MAX - size + 1) {
                zlog_err("Reached max labels. Start: %u, size: %u", lmc->start,
                         size);
                XFREE(MTYPE_LM_CHUNK, lmc);
index 5eb8e75b87e1f85c7eb9b123c692a828e10e9a8d..19b16936d9e08900f00351249b8f5dc2eac4f568 100644 (file)
@@ -300,6 +300,12 @@ int main(int argc, char **argv)
        zebra_if_init();
        zebra_debug_init();
        router_id_cmd_init();
+
+       /*
+        * Initialize NS( and implicitly the VRF module), and make kernel
+        * routing socket. */
+       zebra_ns_init();
+
        zebra_vty_init();
        access_list_init();
        prefix_list_init();
@@ -318,10 +324,6 @@ int main(int argc, char **argv)
        /* For debug purpose. */
        /* SET_FLAG (zebra_debug_event, ZEBRA_DEBUG_EVENT); */
 
-       /* Initialize NS( and implicitly the VRF module), and make kernel
-        * routing socket. */
-       zebra_ns_init();
-
 #if defined(HANDLE_ZAPI_FUZZING)
        if (fuzzing) {
                zserv_read_file(fuzzing);
index cbf77765a3f68502be0d788a940dfc517d0fbac6..3c6a2a7daf8cd0529d3e4e09fd3ac4daa2e16835 100644 (file)
@@ -570,7 +570,7 @@ int zebra_del_import_table_entry(struct route_node *rn, struct route_entry *re)
 
        rib_delete(afi, SAFI_UNICAST, re->vrf_id, ZEBRA_ROUTE_TABLE,
                   re->table, re->flags, &p, NULL, re->nexthop,
-                  zebrad.rtm_table_default, re->metric, false);
+                  zebrad.rtm_table_default, re->metric, false, NULL);
 
        return 0;
 }
index 4b82e8d8d5b9aaabe45109ae41d04c3f2d63aff3..9a5d88ed156d2c6bec0616f978a8c50284cc401f 100644 (file)
@@ -85,8 +85,7 @@ struct route_entry {
 /* to simplify NHT logic when NHs change, instead of doing a NH by NH cmp */
 #define ROUTE_ENTRY_NEXTHOPS_CHANGED 0x2
 #define ROUTE_ENTRY_CHANGED          0x4
-#define ROUTE_ENTRY_SELECTED_FIB     0x8
-#define ROUTE_ENTRY_LABELS_CHANGED   0x10
+#define ROUTE_ENTRY_LABELS_CHANGED   0x8
 
        /* Nexthop information. */
        u_char nexthop_num;
@@ -122,6 +121,8 @@ typedef struct rib_dest_t_ {
         */
        struct route_entry *routes;
 
+       struct route_entry *selected_fib;
+
        /*
         * Flags, see below.
         */
@@ -229,22 +230,27 @@ typedef enum {
 } rib_update_event_t;
 
 extern struct nexthop *route_entry_nexthop_ifindex_add(struct route_entry *,
-                                                      ifindex_t);
+                                                      ifindex_t,
+                                                      vrf_id_t nh_vrf_id);
 extern struct nexthop *route_entry_nexthop_blackhole_add(struct route_entry *,
                                                         enum blackhole_type);
 extern struct nexthop *route_entry_nexthop_ipv4_add(struct route_entry *,
                                                    struct in_addr *,
-                                                   struct in_addr *);
+                                                   struct in_addr *,
+                                                   vrf_id_t nh_vrf_id);
 extern struct nexthop *
 route_entry_nexthop_ipv4_ifindex_add(struct route_entry *, struct in_addr *,
-                                    struct in_addr *, ifindex_t);
+                                    struct in_addr *, ifindex_t,
+                                    vrf_id_t nh_vrf_id);
 extern void route_entry_nexthop_delete(struct route_entry *re,
                                       struct nexthop *nexthop);
 extern struct nexthop *route_entry_nexthop_ipv6_add(struct route_entry *,
-                                                   struct in6_addr *);
+                                                   struct in6_addr *,
+                                                   vrf_id_t nh_vrf_id);
 extern struct nexthop *
 route_entry_nexthop_ipv6_ifindex_add(struct route_entry *re,
-                                    struct in6_addr *ipv6, ifindex_t ifindex);
+                                    struct in6_addr *ipv6, ifindex_t ifindex,
+                                    vrf_id_t nh_vrf_id);
 extern void route_entry_nexthop_add(struct route_entry *re,
                                    struct nexthop *nexthop);
 extern void route_entry_copy_nexthops(struct route_entry *re,
@@ -296,7 +302,7 @@ extern int rib_add(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type,
                   u_short instance, int flags, struct prefix *p,
                   struct prefix_ipv6 *src_p, const struct nexthop *nh,
                   u_int32_t table_id, u_int32_t metric, u_int32_t mtu,
-                  uint8_t distance);
+                  uint8_t distance, route_tag_t tag);
 
 extern int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *,
                             struct prefix_ipv6 *src_p, struct route_entry *);
@@ -304,7 +310,8 @@ extern int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *,
 extern void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type,
                       u_short instance, int flags, struct prefix *p,
                       struct prefix_ipv6 *src_p, const struct nexthop *nh,
-                      u_int32_t table_id, u_int32_t metric, bool fromkernel);
+                      u_int32_t table_id, u_int32_t metric, bool fromkernel,
+                      struct ethaddr *rmac);
 
 extern struct route_entry *rib_match(afi_t afi, safi_t safi, vrf_id_t,
                                     union g_addr *,
@@ -437,6 +444,8 @@ DECLARE_HOOK(rib_update, (struct route_node * rn, const char *reason),
 
 
 extern void zebra_vty_init(void);
+extern int static_config(struct vty *vty, struct zebra_vrf *zvrf,
+                        afi_t afi, safi_t safi, const char *cmd);
 extern pid_t pid;
 
 #endif /*_ZEBRA_RIB_H */
index 7f5bb4dd3491ac173ffebfd632147bb9753bf7aa..54d45b889a303a9f4c9b014340bb7257b8c869a1 100644 (file)
@@ -60,15 +60,17 @@ enum southbound_results {
  * semantics so we will end up with a delete than
  * a re-add.
  */
-extern void kernel_route_rib(struct prefix *p, struct prefix *src_p,
-                            struct route_entry *old, struct route_entry *new);
+extern void kernel_route_rib(struct route_node *rn, struct prefix *p,
+                            struct prefix *src_p, struct route_entry *old,
+                            struct route_entry *new);
 
 /*
  * So route install/failure may not be immediately known
  * so let's separate it out and allow the result to
  * be passed back up.
  */
-extern void kernel_route_rib_pass_fail(struct prefix *p,
+extern void kernel_route_rib_pass_fail(struct route_node *rn,
+                                      struct prefix *p,
                                       struct route_entry *re,
                                       enum southbound_results res);
 
@@ -98,6 +100,7 @@ extern void kernel_lsp_pass_fail(zebra_lsp_t *lsp,
 
 extern int mpls_kernel_init(void);
 
+extern uint32_t kernel_get_speed(struct interface *ifp);
 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);
index cbe736e00cc1c06bd3ce98b9c01c5603d8bd18b8..a80ab9d83494305679108440afb9ca09d6389bab 100644 (file)
@@ -230,6 +230,7 @@ static int netlink_route_change_read_unicast(struct sockaddr_nl *snl,
        int metric = 0;
        u_int32_t mtu = 0;
        uint8_t distance = 0;
+       route_tag_t tag = 0;
 
        void *dest = NULL;
        void *gate = NULL;
@@ -321,6 +322,11 @@ static int netlink_route_change_read_unicast(struct sockaddr_nl *snl,
        if (tb[RTA_PRIORITY])
                metric = *(int *)RTA_DATA(tb[RTA_PRIORITY]);
 
+#if defined(SUPPORT_REALMS)
+       if (tb[RTA_FLOW])
+               tag = *(uint32_t *)RTA_DATA(tb[RTA_FLOW]);
+#endif
+
        if (tb[RTA_METRICS]) {
                struct rtattr *mxrta[RTAX_MAX + 1];
 
@@ -397,6 +403,9 @@ static int netlink_route_change_read_unicast(struct sockaddr_nl *snl,
                afi = AFI_IP6;
 
        if (h->nlmsg_type == RTM_NEWROUTE) {
+               struct interface *ifp;
+               vrf_id_t nh_vrf_id = vrf_id;
+
                if (!tb[RTA_MULTIPATH]) {
                        struct nexthop nh;
                        size_t sz = (afi == AFI_IP) ? 4 : 16;
@@ -428,8 +437,16 @@ static int netlink_route_change_read_unicast(struct sockaddr_nl *snl,
                        if (gate)
                                memcpy(&nh.gate, gate, sz);
 
-                       rib_add(afi, SAFI_UNICAST, vrf_id, proto,
-                               0, flags, &p, NULL, &nh, table, metric, mtu, distance);
+                       if (index) {
+                               ifp = if_lookup_by_index(index,
+                                                        VRF_UNKNOWN);
+                               if (ifp)
+                                       nh_vrf_id = ifp->vrf_id;
+                       }
+                       nh.vrf_id = nh_vrf_id;
+
+                       rib_add(afi, SAFI_UNICAST, vrf_id, proto, 0, flags, &p,
+                               NULL, &nh, table, metric, mtu, distance, tag);
                } else {
                        /* This is a multipath route */
 
@@ -449,13 +466,36 @@ static int netlink_route_change_read_unicast(struct sockaddr_nl *snl,
                        re->table = table;
                        re->nexthop_num = 0;
                        re->uptime = time(NULL);
+                       re->tag = tag;
 
                        for (;;) {
+                               vrf_id_t nh_vrf_id;
                                if (len < (int)sizeof(*rtnh)
                                    || rtnh->rtnh_len > len)
                                        break;
 
                                index = rtnh->rtnh_ifindex;
+                               if (index) {
+                                       /*
+                                        * Yes we are looking this up
+                                        * for every nexthop and just
+                                        * using the last one looked
+                                        * up right now
+                                        */
+                                       ifp = if_lookup_by_index(index,
+                                                                VRF_UNKNOWN);
+                                       if (ifp)
+                                               nh_vrf_id = ifp->vrf_id;
+                                       else {
+                                               zlog_warn(
+                                                       "%s: Unknown interface %u specified, defaulting to VRF_DEFAULT",
+                                                       __PRETTY_FUNCTION__,
+                                                       index);
+                                               nh_vrf_id = VRF_DEFAULT;
+                                       }
+                               } else
+                                       nh_vrf_id = vrf_id;
+
                                gate = 0;
                                if (rtnh->rtnh_len > sizeof(*rtnh)) {
                                        memset(tb, 0, sizeof(tb));
@@ -472,24 +512,27 @@ static int netlink_route_change_read_unicast(struct sockaddr_nl *snl,
                                                if (index)
                                                        route_entry_nexthop_ipv4_ifindex_add(
                                                                re, gate,
-                                                               prefsrc, index);
+                                                               prefsrc, index,
+                                                               nh_vrf_id);
                                                else
                                                        route_entry_nexthop_ipv4_add(
                                                                re, gate,
-                                                               prefsrc);
+                                                               prefsrc,
+                                                               nh_vrf_id);
                                        } else if (rtm->rtm_family
                                                   == AF_INET6) {
                                                if (index)
                                                        route_entry_nexthop_ipv6_ifindex_add(
-                                                               re, gate,
-                                                               index);
+                                                               re, gate, index,
+                                                               nh_vrf_id);
                                                else
                                                        route_entry_nexthop_ipv6_add(
-                                                               re, gate);
+                                                               re, gate,
+                                                               nh_vrf_id);
                                        }
                                } else
-                                       route_entry_nexthop_ifindex_add(re,
-                                                                       index);
+                                       route_entry_nexthop_ifindex_add(
+                                               re, index, nh_vrf_id);
 
                                len -= NLMSG_ALIGN(rtnh->rtnh_len);
                                rtnh = RTNH_NEXT(rtnh);
@@ -535,13 +578,13 @@ static int netlink_route_change_read_unicast(struct sockaddr_nl *snl,
                                memcpy(&nh.gate, gate, sz);
                        rib_delete(afi, SAFI_UNICAST, vrf_id,
                                   proto, 0, flags, &p, NULL, &nh,
-                                  table, metric, true);
+                                  table, metric, true, NULL);
                } else {
                        /* XXX: need to compare the entire list of nexthops
                         * here for NLM_F_APPEND stupidity */
                        rib_delete(afi, SAFI_UNICAST, vrf_id,
                                   proto, 0, flags, &p, NULL, NULL,
-                                  table, metric, true);
+                                  table, metric, true, NULL);
                }
        }
 
@@ -795,8 +838,9 @@ static void _netlink_route_build_singlepath(const char *routedesc, int bytelen,
                                            struct rtmsg *rtmsg,
                                            size_t req_size, int cmd)
 {
-       struct nexthop_label *nh_label;
+       struct mpls_label_stack *nh_label;
        mpls_lse_t out_lse[MPLS_MAX_LABELS];
+       int num_labels = 0;
        char label_buf[256];
 
        /*
@@ -806,56 +850,54 @@ static void _netlink_route_build_singlepath(const char *routedesc, int bytelen,
         * you fix this assumption
         */
        label_buf[0] = '\0';
-       /* outgoing label - either as NEWDST (in the case of LSR) or as ENCAP
-        * (in the case of LER)
-        */
-       nh_label = nexthop->nh_label;
-       if (rtmsg->rtm_family == AF_MPLS) {
-               assert(nh_label);
-               assert(nh_label->num_labels == 1);
-       }
 
-       if (nh_label && nh_label->num_labels) {
-               int i, num_labels = 0;
-               u_int32_t bos;
+       assert(nexthop);
+       for (struct nexthop *nh = nexthop; nh; nh = nh->rparent) {
                char label_buf1[20];
 
-               for (i = 0; i < nh_label->num_labels; i++) {
-                       if (nh_label->label[i] != MPLS_IMP_NULL_LABEL) {
-                               bos = ((i == (nh_label->num_labels - 1)) ? 1
-                                                                        : 0);
-                               out_lse[i] = mpls_lse_encode(nh_label->label[i],
-                                                            0, 0, bos);
-                               if (IS_ZEBRA_DEBUG_KERNEL) {
-                                       if (!num_labels)
-                                               sprintf(label_buf, "label %u",
-                                                       nh_label->label[i]);
-                                       else {
-                                               sprintf(label_buf1, "/%u",
-                                                       nh_label->label[i]);
-                                               strlcat(label_buf, label_buf1,
-                                                       sizeof(label_buf));
-                                       }
+               nh_label = nh->nh_label;
+               if (!nh_label || !nh_label->num_labels)
+                       continue;
+
+               for (int i = 0; i < nh_label->num_labels; i++) {
+                       if (nh_label->label[i] == MPLS_LABEL_IMPLICIT_NULL)
+                               continue;
+
+                       if (IS_ZEBRA_DEBUG_KERNEL) {
+                               if (!num_labels)
+                                       sprintf(label_buf, "label %u",
+                                               nh_label->label[i]);
+                               else {
+                                       sprintf(label_buf1, "/%u",
+                                               nh_label->label[i]);
+                                       strlcat(label_buf, label_buf1,
+                                               sizeof(label_buf));
                                }
-                               num_labels++;
                        }
+
+                       out_lse[num_labels] =
+                               mpls_lse_encode(nh_label->label[i], 0, 0, 0);
+                       num_labels++;
                }
-               if (num_labels) {
-                       if (rtmsg->rtm_family == AF_MPLS)
-                               addattr_l(nlmsg, req_size, RTA_NEWDST, &out_lse,
-                                         num_labels * sizeof(mpls_lse_t));
-                       else {
-                               struct rtattr *nest;
-                               u_int16_t encap = LWTUNNEL_ENCAP_MPLS;
-
-                               addattr_l(nlmsg, req_size, RTA_ENCAP_TYPE,
-                                         &encap, sizeof(u_int16_t));
-                               nest = addattr_nest(nlmsg, req_size, RTA_ENCAP);
-                               addattr_l(nlmsg, req_size, MPLS_IPTUNNEL_DST,
-                                         &out_lse,
-                                         num_labels * sizeof(mpls_lse_t));
-                               addattr_nest_end(nlmsg, nest);
-                       }
+       }
+
+       if (num_labels) {
+               /* Set the BoS bit */
+               out_lse[num_labels - 1] |= htonl(1 << MPLS_LS_S_SHIFT);
+
+               if (rtmsg->rtm_family == AF_MPLS)
+                       addattr_l(nlmsg, req_size, RTA_NEWDST, &out_lse,
+                                 num_labels * sizeof(mpls_lse_t));
+               else {
+                       struct rtattr *nest;
+                       u_int16_t encap = LWTUNNEL_ENCAP_MPLS;
+
+                       addattr_l(nlmsg, req_size, RTA_ENCAP_TYPE, &encap,
+                                 sizeof(u_int16_t));
+                       nest = addattr_nest(nlmsg, req_size, RTA_ENCAP);
+                       addattr_l(nlmsg, req_size, MPLS_IPTUNNEL_DST, &out_lse,
+                                 num_labels * sizeof(mpls_lse_t));
+                       addattr_nest_end(nlmsg, nest);
                }
        }
 
@@ -932,10 +974,17 @@ static void _netlink_route_build_singlepath(const char *routedesc, int bytelen,
                                routedesc, inet6_ntoa(nexthop->gate.ipv6),
                                label_buf, nexthop->ifindex);
        }
-       if (nexthop->type == NEXTHOP_TYPE_IFINDEX
-           || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX) {
+
+       /*
+        * We have the ifindex so we should always send it
+        * This is especially useful if we are doing route
+        * leaking.
+        */
+       if (nexthop->type != NEXTHOP_TYPE_BLACKHOLE)
                addattr32(nlmsg, req_size, RTA_OIF, nexthop->ifindex);
 
+       if (nexthop->type == NEXTHOP_TYPE_IFINDEX
+           || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX) {
                if (cmd == RTM_NEWROUTE) {
                        if (nexthop->rmap_src.ipv4.s_addr)
                                addattr_l(nlmsg, req_size, RTA_PREFSRC,
@@ -953,8 +1002,6 @@ static void _netlink_route_build_singlepath(const char *routedesc, int bytelen,
        }
 
        if (nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX) {
-               addattr32(nlmsg, req_size, RTA_OIF, nexthop->ifindex);
-
                if (cmd == RTM_NEWROUTE) {
                        if (!IN6_IS_ADDR_UNSPECIFIED(&nexthop->rmap_src.ipv6))
                                addattr_l(nlmsg, req_size, RTA_PREFSRC,
@@ -995,8 +1042,9 @@ static void _netlink_route_build_multipath(const char *routedesc, int bytelen,
                                           struct rtmsg *rtmsg,
                                           union g_addr **src)
 {
-       struct nexthop_label *nh_label;
+       struct mpls_label_stack *nh_label;
        mpls_lse_t out_lse[MPLS_MAX_LABELS];
+       int num_labels = 0;
        char label_buf[256];
 
        rtnh->rtnh_len = sizeof(*rtnh);
@@ -1011,63 +1059,60 @@ static void _netlink_route_build_multipath(const char *routedesc, int bytelen,
         * you fix this assumption
         */
        label_buf[0] = '\0';
-       /* outgoing label - either as NEWDST (in the case of LSR) or as ENCAP
-        * (in the case of LER)
-        */
-       nh_label = nexthop->nh_label;
-       if (rtmsg->rtm_family == AF_MPLS) {
-               assert(nh_label);
-               assert(nh_label->num_labels == 1);
-       }
 
-       if (nh_label && nh_label->num_labels) {
-               int i, num_labels = 0;
-               u_int32_t bos;
+       assert(nexthop);
+       for (struct nexthop *nh = nexthop; nh; nh = nh->rparent) {
                char label_buf1[20];
 
-               for (i = 0; i < nh_label->num_labels; i++) {
-                       if (nh_label->label[i] != MPLS_IMP_NULL_LABEL) {
-                               bos = ((i == (nh_label->num_labels - 1)) ? 1
-                                                                        : 0);
-                               out_lse[i] = mpls_lse_encode(nh_label->label[i],
-                                                            0, 0, bos);
-                               if (IS_ZEBRA_DEBUG_KERNEL) {
-                                       if (!num_labels)
-                                               sprintf(label_buf, "label %u",
-                                                       nh_label->label[i]);
-                                       else {
-                                               sprintf(label_buf1, "/%u",
-                                                       nh_label->label[i]);
-                                               strlcat(label_buf, label_buf1,
-                                                       sizeof(label_buf));
-                                       }
+               nh_label = nh->nh_label;
+               if (!nh_label || !nh_label->num_labels)
+                       continue;
+
+               for (int i = 0; i < nh_label->num_labels; i++) {
+                       if (nh_label->label[i] == MPLS_LABEL_IMPLICIT_NULL)
+                               continue;
+
+                       if (IS_ZEBRA_DEBUG_KERNEL) {
+                               if (!num_labels)
+                                       sprintf(label_buf, "label %u",
+                                               nh_label->label[i]);
+                               else {
+                                       sprintf(label_buf1, "/%u",
+                                               nh_label->label[i]);
+                                       strlcat(label_buf, label_buf1,
+                                               sizeof(label_buf));
                                }
-                               num_labels++;
                        }
+
+                       out_lse[num_labels] =
+                               mpls_lse_encode(nh_label->label[i], 0, 0, 0);
+                       num_labels++;
                }
-               if (num_labels) {
-                       if (rtmsg->rtm_family == AF_MPLS) {
-                               rta_addattr_l(rta, NL_PKT_BUF_SIZE, RTA_NEWDST,
-                                             &out_lse,
-                                             num_labels * sizeof(mpls_lse_t));
-                               rtnh->rtnh_len += RTA_LENGTH(
-                                       num_labels * sizeof(mpls_lse_t));
-                       } else {
-                               struct rtattr *nest;
-                               u_int16_t encap = LWTUNNEL_ENCAP_MPLS;
-                               int len = rta->rta_len;
-
-                               rta_addattr_l(rta, NL_PKT_BUF_SIZE,
-                                             RTA_ENCAP_TYPE, &encap,
-                                             sizeof(u_int16_t));
-                               nest = rta_nest(rta, NL_PKT_BUF_SIZE,
-                                               RTA_ENCAP);
-                               rta_addattr_l(rta, NL_PKT_BUF_SIZE,
-                                             MPLS_IPTUNNEL_DST, &out_lse,
-                                             num_labels * sizeof(mpls_lse_t));
-                               rta_nest_end(rta, nest);
-                               rtnh->rtnh_len += rta->rta_len - len;
-                       }
+       }
+
+       if (num_labels) {
+               /* Set the BoS bit */
+               out_lse[num_labels - 1] |= htonl(1 << MPLS_LS_S_SHIFT);
+
+               if (rtmsg->rtm_family == AF_MPLS) {
+                       rta_addattr_l(rta, NL_PKT_BUF_SIZE, RTA_NEWDST,
+                                     &out_lse,
+                                     num_labels * sizeof(mpls_lse_t));
+                       rtnh->rtnh_len +=
+                               RTA_LENGTH(num_labels * sizeof(mpls_lse_t));
+               } else {
+                       struct rtattr *nest;
+                       u_int16_t encap = LWTUNNEL_ENCAP_MPLS;
+                       int len = rta->rta_len;
+
+                       rta_addattr_l(rta, NL_PKT_BUF_SIZE, RTA_ENCAP_TYPE,
+                                     &encap, sizeof(u_int16_t));
+                       nest = rta_nest(rta, NL_PKT_BUF_SIZE, RTA_ENCAP);
+                       rta_addattr_l(rta, NL_PKT_BUF_SIZE, MPLS_IPTUNNEL_DST,
+                                     &out_lse,
+                                     num_labels * sizeof(mpls_lse_t));
+                       rta_nest_end(rta, nest);
+                       rtnh->rtnh_len += rta->rta_len - len;
                }
        }
 
@@ -1133,11 +1178,18 @@ static void _netlink_route_build_multipath(const char *routedesc, int bytelen,
                                routedesc, inet6_ntoa(nexthop->gate.ipv6),
                                label_buf, nexthop->ifindex);
        }
+
+       /*
+        * We have figured out the ifindex so we should always send it
+        * This is especially useful if we are doing route
+        * leaking.
+        */
+       if (nexthop->type != NEXTHOP_TYPE_BLACKHOLE)
+               rtnh->rtnh_ifindex = nexthop->ifindex;
+
        /* ifindex */
        if (nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX
            || nexthop->type == NEXTHOP_TYPE_IFINDEX) {
-               rtnh->rtnh_ifindex = nexthop->ifindex;
-
                if (nexthop->rmap_src.ipv4.s_addr)
                        *src = &nexthop->rmap_src;
                else if (nexthop->src.ipv4.s_addr)
@@ -1149,8 +1201,6 @@ static void _netlink_route_build_multipath(const char *routedesc, int bytelen,
                                "nexthop via if %u",
                                routedesc, nexthop->ifindex);
        } else if (nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX) {
-               rtnh->rtnh_ifindex = nexthop->ifindex;
-
                if (IS_ZEBRA_DEBUG_KERNEL)
                        zlog_debug(
                                "netlink_route_multipath() (%s): "
@@ -1310,7 +1360,10 @@ static int netlink_route_multipath(int cmd, struct prefix *p,
         * by the routing protocol and for communicating with protocol peers.
         */
        addattr32(&req.n, sizeof req, RTA_PRIORITY, NL_DEFAULT_ROUTE_METRIC);
-
+#if defined(SUPPORT_REALMS)
+       if (re->tag > 0 && re->tag <= 255)
+               addattr32(&req.n, sizeof req, RTA_FLOW, re->tag);
+#endif
        /* Table corresponding to this route. */
        if (re->table < 256)
                req.r.rtm_table = re->table;
@@ -1598,8 +1651,9 @@ int kernel_get_ipmr_sg_stats(struct zebra_vrf *zvrf, void *in)
        return suc;
 }
 
-void kernel_route_rib(struct prefix *p, struct prefix *src_p,
-                     struct route_entry *old, struct route_entry *new)
+void kernel_route_rib(struct route_node *rn, struct prefix *p,
+                     struct prefix *src_p, struct route_entry *old,
+                     struct route_entry *new)
 {
        int ret = 0;
 
@@ -1628,7 +1682,7 @@ void kernel_route_rib(struct prefix *p, struct prefix *src_p,
                        ret = netlink_route_multipath(RTM_NEWROUTE, p,
                                                      src_p, new, 0);
                }
-               kernel_route_rib_pass_fail(p, new,
+               kernel_route_rib_pass_fail(rn, p, new,
                                           (!ret) ?
                                           SOUTHBOUND_INSTALL_SUCCESS :
                                           SOUTHBOUND_INSTALL_FAILURE);
@@ -1638,7 +1692,7 @@ void kernel_route_rib(struct prefix *p, struct prefix *src_p,
        if (old) {
                ret = netlink_route_multipath(RTM_DELROUTE, p, src_p, old, 0);
 
-               kernel_route_rib_pass_fail(p, old,
+               kernel_route_rib_pass_fail(rn, p, old,
                                           (!ret) ?
                                           SOUTHBOUND_DELETE_SUCCESS :
                                           SOUTHBOUND_DELETE_FAILURE);
index 0d1a80e737b2f0c1cd7072910c32cf64936ac3c9..6d4af1203c7d457e0174d31bee188ccd7b1bf45b 100644 (file)
@@ -67,7 +67,7 @@ static int sin_masklen(struct in_addr mask)
 #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
 
 #ifdef __OpenBSD__
-static int kernel_rtm_add_labels(struct nexthop_label *nh_label,
+static int kernel_rtm_add_labels(struct mpls_label_stack *nh_label,
                                 struct sockaddr_mpls *smpls)
 {
        if (nh_label->num_labels > 1) {
@@ -387,8 +387,9 @@ static int kernel_rtm(int cmd, struct prefix *p, struct route_entry *re)
        return 0;
 }
 
-void kernel_route_rib(struct prefix *p, struct prefix *src_p,
-                     struct route_entry *old, struct route_entry *new)
+void kernel_route_rib(struct route_node *rn, struct prefix *p,
+                     struct prefix *src_p, struct route_entry *old,
+                     struct route_entry *new)
 {
        int route = 0;
 
@@ -410,12 +411,12 @@ void kernel_route_rib(struct prefix *p, struct prefix *src_p,
                zlog_err("Can't lower privileges");
 
        if (new) {
-               kernel_route_rib_pass_fail(p, new,
+               kernel_route_rib_pass_fail(rn, p, new,
                                           (!route) ?
                                           SOUTHBOUND_INSTALL_SUCCESS :
                                           SOUTHBOUND_INSTALL_FAILURE);
        } else {
-               kernel_route_rib_pass_fail(p, old,
+               kernel_route_rib_pass_fail(rn, p, old,
                                           (!route) ?
                                           SOUTHBOUND_DELETE_SUCCESS :
                                           SOUTHBOUND_DELETE_FAILURE);
@@ -473,4 +474,9 @@ extern int kernel_interface_set_master(struct interface *master,
        return 0;
 }
 
+uint32_t kernel_get_speed(struct interface *ifp)
+{
+       return ifp->speed;
+}
+
 #endif /* !HAVE_NETLINK */
index 39ecdb335c60da5c287659ea2a85d8ef33321781..95bc8db1c92fff2fb27f1614cc4cb990f9338753 100644 (file)
@@ -94,11 +94,12 @@ static void handle_route_entry(mib2_ipRouteEntry_t *routeEntry)
        prefix.prefixlen = ip_masklen(tmpaddr);
 
        memset(&nh, 0, sizeof(nh));
+       nh.vrf_id = VRF_DEFAULT;
        nh.type = NEXTHOP_TYPE_IPV4;
        nh.gate.ipv4.s_addr = routeEntry->ipRouteNextHop;
 
        rib_add(AFI_IP, SAFI_UNICAST, VRF_DEFAULT, ZEBRA_ROUTE_KERNEL, 0,
-               zebra_flags, &prefix, NULL, &nh, 0, 0, 0, 0);
+               zebra_flags, &prefix, NULL, &nh, 0, 0, 0, 0, 0);
 }
 
 void route_read(struct zebra_ns *zns)
index a5d0732f6b3d2fc09ac77a827c7fab0922791a99..03042eb083ba683c60a7323244b4c01c4b3af0f1 100644 (file)
@@ -2,8 +2,6 @@
 !
 ! zebra sample configuration file
 !
-! $Id: zebra.conf.sample,v 1.1 2002/12/13 20:15:30 paul Exp $
-!
 hostname Router
 password zebra
 enable password zebra
index 7448292d9f1c707a142a5ed260f357a0284a7bf0..a6e0882ff89b489a1f36e5e9bd8020296900b765 100644 (file)
@@ -713,7 +713,15 @@ static int zfpm_read_cb(struct thread *thread)
                nbyte = stream_read_try(ibuf, zfpm_g->sock,
                                        FPM_MSG_HDR_LEN - already);
                if (nbyte == 0 || nbyte == -1) {
-                       zfpm_connection_down("closed socket in read");
+                       if (nbyte == -1) {
+                               char buffer[1024];
+
+                               sprintf(buffer, "closed socket in read(%d): %s",
+                                       errno, safe_strerror(errno));
+                               zfpm_connection_down(buffer);
+                       }
+                       else
+                               zfpm_connection_down("closed socket in read");
                        return 0;
                }
 
@@ -743,7 +751,15 @@ static int zfpm_read_cb(struct thread *thread)
                nbyte = stream_read_try(ibuf, zfpm_g->sock, msg_len - already);
 
                if (nbyte == 0 || nbyte == -1) {
-                       zfpm_connection_down("failed to read message");
+                       if (nbyte == -1) {
+                               char buffer[1024];
+
+                               sprintf(buffer, "failed to read message(%d) %s",
+                                       errno, safe_strerror(errno));
+                               zfpm_connection_down(buffer);
+                       }
+                       else
+                               zfpm_connection_down("failed to read message");
                        return 0;
                }
 
@@ -842,19 +858,7 @@ static inline int zfpm_encode_route(rib_dest_t *dest, struct route_entry *re,
  */
 struct route_entry *zfpm_route_for_update(rib_dest_t *dest)
 {
-       struct route_entry *re;
-
-       RE_DEST_FOREACH_ROUTE (dest, re) {
-               if (!CHECK_FLAG(re->status, ROUTE_ENTRY_SELECTED_FIB))
-                       continue;
-
-               return re;
-       }
-
-       /*
-        * We have no route for this destination.
-        */
-       return NULL;
+       return dest->selected_fib;
 }
 
 /*
index 4c6fb002dca301b069760dc228df4a3020164423..ec80081a469212242a68d9ebac71c94aa492aa25 100644 (file)
@@ -104,7 +104,7 @@ static zebra_nhlfe_t *nhlfe_add(zebra_lsp_t *lsp, enum lsp_types_t lsp_type,
                                ifindex_t ifindex, mpls_label_t out_label);
 static int nhlfe_del(zebra_nhlfe_t *snhlfe);
 static void nhlfe_out_label_update(zebra_nhlfe_t *nhlfe,
-                                  struct nexthop_label *nh_label);
+                                  struct mpls_label_stack *nh_label);
 static int mpls_lsp_uninstall_all(struct hash *lsp_table, zebra_lsp_t *lsp,
                                  enum lsp_types_t type);
 static int mpls_static_lsp_uninstall_all(struct zebra_vrf *zvrf,
@@ -411,12 +411,13 @@ static int fec_change_update_lsp(struct zebra_vrf *zvrf, zebra_fec_t *fec,
        afi_t afi;
 
        /* Uninstall label forwarding entry, if previously installed. */
-       if (old_label != MPLS_INVALID_LABEL && old_label != MPLS_IMP_NULL_LABEL)
+       if (old_label != MPLS_INVALID_LABEL &&
+           old_label != MPLS_LABEL_IMPLICIT_NULL)
                lsp_uninstall(zvrf, old_label);
 
        /* Install label forwarding entry corr. to new label, if needed. */
        if (fec->label == MPLS_INVALID_LABEL
-           || fec->label == MPLS_IMP_NULL_LABEL)
+           || fec->label == MPLS_LABEL_IMPLICIT_NULL)
                return 0;
 
        afi = family2afi(PREFIX_FAMILY(&fec->rn->p));
@@ -457,7 +458,7 @@ static int fec_send(zebra_fec_t *fec, struct zserv *client)
        s = client->obuf;
        stream_reset(s);
 
-       zserv_create_header(s, ZEBRA_FEC_UPDATE, VRF_DEFAULT);
+       zclient_create_header(s, ZEBRA_FEC_UPDATE, VRF_DEFAULT);
 
        stream_putw(s, rn->p.family);
        stream_put_prefix(s, &rn->p);
@@ -614,7 +615,7 @@ static int nhlfe_nexthop_active_ipv4(zebra_nhlfe_t *nhlfe,
        struct route_entry *match;
        struct nexthop *match_nh;
 
-       table = zebra_vrf_table(AFI_IP, SAFI_UNICAST, VRF_DEFAULT);
+       table = zebra_vrf_table(AFI_IP, SAFI_UNICAST, nexthop->vrf_id);
        if (!table)
                return 0;
 
@@ -663,7 +664,7 @@ static int nhlfe_nexthop_active_ipv6(zebra_nhlfe_t *nhlfe,
        struct route_node *rn;
        struct route_entry *match;
 
-       table = zebra_vrf_table(AFI_IP6, SAFI_UNICAST, VRF_DEFAULT);
+       table = zebra_vrf_table(AFI_IP6, SAFI_UNICAST, nexthop->vrf_id);
        if (!table)
                return 0;
 
@@ -711,6 +712,22 @@ static int nhlfe_nexthop_active(zebra_nhlfe_t *nhlfe)
 
        /* Check on nexthop based on type. */
        switch (nexthop->type) {
+       case NEXTHOP_TYPE_IFINDEX:
+               /*
+                * Lookup if this type is special.  The
+                * NEXTHOP_TYPE_IFINDEX is a pop and
+                * forward into a different table for
+                * processing.  As such this ifindex
+                * passed to us may be a VRF device
+                * which will not be in the default
+                * VRF.  So let's look in all of them
+                */
+               ifp = if_lookup_by_index(nexthop->ifindex, VRF_UNKNOWN);
+               if (ifp && if_is_operative(ifp))
+                       SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
+               else
+                       UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
+               break;
        case NEXTHOP_TYPE_IPV4:
        case NEXTHOP_TYPE_IPV4_IFINDEX:
                if (nhlfe_nexthop_active_ipv4(nhlfe, nexthop))
@@ -728,7 +745,8 @@ static int nhlfe_nexthop_active(zebra_nhlfe_t *nhlfe)
 
        case NEXTHOP_TYPE_IPV6_IFINDEX:
                if (IN6_IS_ADDR_LINKLOCAL(&nexthop->gate.ipv6)) {
-                       ifp = if_lookup_by_index(nexthop->ifindex, VRF_DEFAULT);
+                       ifp = if_lookup_by_index(nexthop->ifindex,
+                                                nexthop->vrf_id);
                        if (ifp && if_is_operative(ifp))
                                SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
                        else
@@ -1052,6 +1070,8 @@ static char *nhlfe2str(zebra_nhlfe_t *nhlfe, char *buf, int size)
        case NEXTHOP_TYPE_IPV6:
                inet_ntop(AF_INET6, &nexthop->gate.ipv6, buf, size);
                break;
+       case NEXTHOP_TYPE_IFINDEX:
+               snprintf(buf, size, "Ifindex: %u", nexthop->ifindex);
        default:
                break;
        }
@@ -1090,6 +1110,9 @@ static int nhlfe_nhop_match(zebra_nhlfe_t *nhlfe, enum nexthop_types_t gtype,
                if (!cmp && nhop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
                        cmp = !(nhop->ifindex == ifindex);
                break;
+       case NEXTHOP_TYPE_IFINDEX:
+               cmp = !(nhop->ifindex == ifindex);
+               break;
        default:
                break;
        }
@@ -1149,6 +1172,7 @@ static zebra_nhlfe_t *nhlfe_add(zebra_lsp_t *lsp, enum lsp_types_t lsp_type,
        }
        nexthop_add_labels(nexthop, lsp_type, 1, &out_label);
 
+       nexthop->vrf_id = VRF_DEFAULT;
        nexthop->type = gtype;
        switch (nexthop->type) {
        case NEXTHOP_TYPE_IPV4:
@@ -1163,6 +1187,9 @@ static zebra_nhlfe_t *nhlfe_add(zebra_lsp_t *lsp, enum lsp_types_t lsp_type,
                if (ifindex)
                        nexthop->ifindex = ifindex;
                break;
+       case NEXTHOP_TYPE_IFINDEX:
+               nexthop->ifindex = ifindex;
+               break;
        default:
                nexthop_free(nexthop);
                XFREE(MTYPE_NHLFE, nhlfe);
@@ -1217,7 +1244,7 @@ static int nhlfe_del(zebra_nhlfe_t *nhlfe)
  * Update label for NHLFE entry.
  */
 static void nhlfe_out_label_update(zebra_nhlfe_t *nhlfe,
-                                  struct nexthop_label *nh_label)
+                                  struct mpls_label_stack *nh_label)
 {
        nhlfe->nexthop->nh_label->label[0] = nh_label->label[0];
 }
@@ -1324,9 +1351,9 @@ static json_object *nhlfe_json(zebra_nhlfe_t *nhlfe)
                        inet_ntop(AF_INET6, &nexthop->gate.ipv6, buf, BUFSIZ));
 
                if (nexthop->ifindex)
-                       json_object_string_add(
-                               json_nhlfe, "interface",
-                               ifindex2ifname(nexthop->ifindex, VRF_DEFAULT));
+                       json_object_string_add(json_nhlfe, "interface",
+                                              ifindex2ifname(nexthop->ifindex,
+                                                             nexthop->vrf_id));
                break;
        default:
                break;
@@ -1356,7 +1383,8 @@ static void nhlfe_print(zebra_nhlfe_t *nhlfe, struct vty *vty)
                vty_out(vty, "  via %s", inet_ntoa(nexthop->gate.ipv4));
                if (nexthop->ifindex)
                        vty_out(vty, " dev %s",
-                               ifindex2ifname(nexthop->ifindex, VRF_DEFAULT));
+                               ifindex2ifname(nexthop->ifindex,
+                                              nexthop->vrf_id));
                break;
        case NEXTHOP_TYPE_IPV6:
        case NEXTHOP_TYPE_IPV6_IFINDEX:
@@ -1364,7 +1392,8 @@ static void nhlfe_print(zebra_nhlfe_t *nhlfe, struct vty *vty)
                        inet_ntop(AF_INET6, &nexthop->gate.ipv6, buf, BUFSIZ));
                if (nexthop->ifindex)
                        vty_out(vty, " dev %s",
-                               ifindex2ifname(nexthop->ifindex, VRF_DEFAULT));
+                               ifindex2ifname(nexthop->ifindex,
+                                              nexthop->vrf_id));
                break;
        default:
                break;
@@ -1793,7 +1822,7 @@ int zebra_mpls_lsp_install(struct zebra_vrf *zvrf, struct route_node *rn,
        /* We cannot install a label forwarding entry if local label is the
         * implicit-null label.
         */
-       if (fec->label == MPLS_IMP_NULL_LABEL)
+       if (fec->label == MPLS_LABEL_IMPLICIT_NULL)
                return 0;
 
        if (lsp_install(zvrf, fec->label, rn, re))
@@ -2537,8 +2566,8 @@ int zebra_mpls_lsp_label_consistent(struct zebra_vrf *zvrf,
                        int cur_op, new_op;
 
                        cur_op = (slsp->snhlfe_list->out_label
-                                 == MPLS_IMP_NULL_LABEL);
-                       new_op = (out_label == MPLS_IMP_NULL_LABEL);
+                                 == MPLS_LABEL_IMPLICIT_NULL);
+                       new_op = (out_label == MPLS_LABEL_IMPLICIT_NULL);
                        if (cur_op != new_op)
                                return 0;
                }
@@ -2764,6 +2793,15 @@ void zebra_mpls_print_lsp_table(struct vty *vty, struct zebra_vrf *zvrf,
                                nexthop = nhlfe->nexthop;
 
                                switch (nexthop->type) {
+                               case NEXTHOP_TYPE_IFINDEX:
+                               {
+                                       struct interface *ifp;
+
+                                       ifp = if_lookup_by_index(
+                                               nexthop->ifindex, VRF_UNKNOWN);
+                                       vty_out(vty, "%15s", ifp->name);
+                                       break;
+                               }
                                case NEXTHOP_TYPE_IPV4:
                                case NEXTHOP_TYPE_IPV4_IFINDEX:
                                        vty_out(vty, "%15s",
@@ -2780,8 +2818,16 @@ void zebra_mpls_print_lsp_table(struct vty *vty, struct zebra_vrf *zvrf,
                                        break;
                                }
 
-                               vty_out(vty, "  %8d\n",
-                                       nexthop->nh_label->label[0]);
+                               if (nexthop->type != NEXTHOP_TYPE_IFINDEX)
+                                       vty_out(vty, "  %8s\n",
+                                               mpls_label2str(
+                                                       nexthop->nh_label
+                                                               ->num_labels,
+                                                       &nexthop->nh_label
+                                                                ->label[0],
+                                                       buf, BUFSIZ, 1));
+                               else
+                                       vty_out(vty, "\n");
                        }
                }
 
@@ -2810,11 +2856,11 @@ int zebra_mpls_write_lsp_config(struct vty *vty, struct zebra_vrf *zvrf)
 
                        snhlfe2str(snhlfe, buf, sizeof(buf));
                        switch (snhlfe->out_label) {
-                       case MPLS_V4_EXP_NULL_LABEL:
-                       case MPLS_V6_EXP_NULL_LABEL:
+                       case MPLS_LABEL_IPV4_EXPLICIT_NULL:
+                       case MPLS_LABEL_IPV6_EXPLICIT_NULL:
                                strlcpy(lstr, "explicit-null", sizeof(lstr));
                                break;
-                       case MPLS_IMP_NULL_LABEL:
+                       case MPLS_LABEL_IMPLICIT_NULL:
                                strlcpy(lstr, "implicit-null", sizeof(lstr));
                                break;
                        default:
@@ -2875,6 +2921,16 @@ int zebra_mpls_write_label_block_config(struct vty *vty, struct zebra_vrf *zvrf)
        return 1;
 }
 
+/*
+ * Called when VRF becomes inactive, cleans up information but keeps
+ * the table itself.
+ * NOTE: Currently supported only for default VRF.
+ */
+void zebra_mpls_cleanup_tables(struct zebra_vrf *zvrf)
+{
+       hash_iterate(zvrf->lsp_table, lsp_uninstall_from_kernel, NULL);
+}
+
 /*
  * Called upon process exiting, need to delete LSP forwarding
  * entries from the kernel.
index 22c771c34809aa86706180a480c00056d40b4b1b..fd14b29ca9d2afddc6c064c345568ec46a5d8d19 100644 (file)
@@ -316,6 +316,12 @@ void mpls_ldp_lsp_uninstall_all(struct hash_backet *backet, void *ctxt);
  */
 void mpls_ldp_ftn_uninstall_all(struct zebra_vrf *zvrf, int afi);
 
+/*
+ * Uninstall all Segment Routing NHLFEs for a particular LSP forwarding entry.
+ * If no other NHLFEs exist, the entry would be deleted.
+ */
+void mpls_sr_lsp_uninstall_all(struct hash_backet *backet, void *ctxt);
+
 #if defined(HAVE_CUMULUS)
 /*
  * Check that the label values used in LSP creation are consistent. The
@@ -378,6 +384,13 @@ void zebra_mpls_print_lsp_table(struct vty *vty, struct zebra_vrf *zvrf,
  */
 int zebra_mpls_write_lsp_config(struct vty *vty, struct zebra_vrf *zvrf);
 
+/*
+ * Called when VRF becomes inactive, cleans up information but keeps
+ * the table itself.
+ * NOTE: Currently supported only for default VRF.
+ */
+void zebra_mpls_cleanup_tables(struct zebra_vrf *zvrf);
+
 /*
  * Called upon process exiting, need to delete LSP forwarding
  * entries from the kernel.
@@ -415,9 +428,19 @@ static inline u_char lsp_distance(enum lsp_types_t type)
                return (route_distance(ZEBRA_ROUTE_LDP));
        case ZEBRA_LSP_BGP:
                return (route_distance(ZEBRA_ROUTE_BGP));
-       default:
+       case ZEBRA_LSP_NONE:
+       case ZEBRA_LSP_SHARP:
+       case ZEBRA_LSP_SR:
                return 150;
        }
+
+       /*
+        * For some reason certain compilers do not believe
+        * that all the cases have been handled.  And
+        * WTF does this work differently than when I removed
+        * the default case????
+        */
+       return 150;
 }
 
 /*
@@ -431,6 +454,8 @@ static inline enum lsp_types_t lsp_type_from_re_type(int re_type)
                return ZEBRA_LSP_STATIC;
        case ZEBRA_ROUTE_BGP:
                return ZEBRA_LSP_BGP;
+       case ZEBRA_ROUTE_SHARP:
+               return ZEBRA_LSP_SHARP;
        default:
                return ZEBRA_LSP_NONE;
        }
@@ -448,10 +473,21 @@ static inline int re_type_from_lsp_type(enum lsp_types_t lsp_type)
                return ZEBRA_ROUTE_LDP;
        case ZEBRA_LSP_BGP:
                return ZEBRA_ROUTE_BGP;
+       case ZEBRA_LSP_SR:
+               return ZEBRA_ROUTE_OSPF;
        case ZEBRA_LSP_NONE:
-       default:
                return ZEBRA_ROUTE_KERNEL;
+       case ZEBRA_LSP_SHARP:
+               return ZEBRA_ROUTE_SHARP;
        }
+
+       /*
+        * For some reason certain compilers do not believe
+        * that all the cases have been handled.  And
+        * WTF does this work differently than when I removed
+        * the default case????
+        */
+       return ZEBRA_ROUTE_KERNEL;
 }
 
 /* NHLFE type as printable string. */
@@ -464,9 +500,21 @@ static inline const char *nhlfe_type2str(enum lsp_types_t lsp_type)
                return "LDP";
        case ZEBRA_LSP_BGP:
                return "BGP";
-       default:
+       case ZEBRA_LSP_SR:
+               return "SR";
+       case ZEBRA_LSP_SHARP:
+               return "SHARP";
+       case ZEBRA_LSP_NONE:
                return "Unknown";
        }
+
+       /*
+        * For some reason certain compilers do not believe
+        * that all the cases have been handled.  And
+        * WTF does this work differently than when I removed
+        * the default case????
+        */
+       return "Unknown";
 }
 
 static inline void mpls_mark_lsps_for_processing(struct zebra_vrf *zvrf)
index 9d100bb7d0b3a1f560925a5e7f6992c1b7d85129..0d922830c781ab52eaf309398c216cbda3a47f25 100644 (file)
@@ -68,7 +68,7 @@ static int zebra_mpls_transit_lsp(struct vty *vty, int add_cmd,
                return CMD_WARNING_CONFIG_FAILED;
        }
 
-       out_label = MPLS_IMP_NULL_LABEL; /* as initialization */
+       out_label = MPLS_LABEL_IMPLICIT_NULL; /* as initialization */
        label = atoi(inlabel_str);
        if (!IS_MPLS_UNRESERVED_LABEL(label)) {
                vty_out(vty, "%% Invalid label\n");
@@ -107,11 +107,11 @@ static int zebra_mpls_transit_lsp(struct vty *vty, int add_cmd,
 
        if (outlabel_str) {
                if (outlabel_str[0] == 'i')
-                       out_label = MPLS_IMP_NULL_LABEL;
+                       out_label = MPLS_LABEL_IMPLICIT_NULL;
                else if (outlabel_str[0] == 'e' && gtype == NEXTHOP_TYPE_IPV4)
-                       out_label = MPLS_V4_EXP_NULL_LABEL;
+                       out_label = MPLS_LABEL_IPV4_EXPLICIT_NULL;
                else if (outlabel_str[0] == 'e' && gtype == NEXTHOP_TYPE_IPV6)
-                       out_label = MPLS_V6_EXP_NULL_LABEL;
+                       out_label = MPLS_LABEL_IPV6_EXPLICIT_NULL;
                else
                        out_label = atoi(outlabel_str);
        }
@@ -221,12 +221,12 @@ static int zebra_mpls_bind(struct vty *vty, int add_cmd, const char *prefix,
                }
 
                if (!strcmp(label_str, "implicit-null"))
-                       label = MPLS_IMP_NULL_LABEL;
+                       label = MPLS_LABEL_IMPLICIT_NULL;
                else if (!strcmp(label_str, "explicit-null")) {
                        if (p.family == AF_INET)
-                               label = MPLS_V4_EXP_NULL_LABEL;
+                               label = MPLS_LABEL_IPV4_EXPLICIT_NULL;
                        else
-                               label = MPLS_V6_EXP_NULL_LABEL;
+                               label = MPLS_LABEL_IPV6_EXPLICIT_NULL;
                } else {
                        label = atoi(label_str);
                        if (!IS_MPLS_UNRESERVED_LABEL(label)) {
index 519c120a67e09f66bbf12619a8b88c6a622e6161..e9cd19ebe0cfad8a982f43490637615c48b2340a 100644 (file)
@@ -61,7 +61,7 @@ stream_failure:
 
        stream_reset(s);
 
-       zserv_create_header(s, ZEBRA_IPMR_ROUTE_STATS, zvrf_id(zvrf));
+       zclient_create_header(s, ZEBRA_IPMR_ROUTE_STATS, zvrf_id(zvrf));
        stream_put_in_addr(s, &mroute.sg.src);
        stream_put_in_addr(s, &mroute.sg.grp);
        stream_put(s, &mroute.lastused, sizeof(mroute.lastused));
index 602dc5ea419c4aef769e5a2e4a57f57a9cec5af5..c48a6f7bd8ad377e8b7e882281a5f0f8cc147ea1 100644 (file)
@@ -30,6 +30,7 @@
 #include "zebra_vrf.h"
 #include "zebra_memory.h"
 #include "rt.h"
+#include "zebra_vxlan.h"
 
 DEFINE_MTYPE(ZEBRA, ZEBRA_NS, "Zebra Name Space")
 
@@ -40,6 +41,7 @@ struct zebra_ns *zebra_ns_lookup(ns_id_t ns_id)
        return dzns;
 }
 
+/* Do global enable actions - open sockets, read kernel config etc. */
 int zebra_ns_enable(ns_id_t ns_id, void **info)
 {
        struct zebra_ns *zns = (struct zebra_ns *)(*info);
@@ -48,7 +50,6 @@ int zebra_ns_enable(ns_id_t ns_id, void **info)
        rtadv_init(zns);
 #endif
 
-       zns->if_table = route_table_init();
        kernel_init(zns);
        interface_list(zns);
        route_read(zns);
@@ -61,6 +62,7 @@ int zebra_ns_disable(ns_id_t ns_id, void **info)
        struct zebra_ns *zns = (struct zebra_ns *)(*info);
 
        route_table_finish(zns->if_table);
+       zebra_vxlan_ns_disable(zns);
 #if defined(HAVE_RTADV)
        rtadv_terminate(zns);
 #endif
@@ -76,9 +78,15 @@ int zebra_ns_init(void)
 
        ns_init();
 
+       /* Do any needed per-NS data structure allocation. */
+       dzns->if_table = route_table_init();
+       zebra_vxlan_ns_init(dzns);
+
+       /* Register zebra VRF callbacks, create and activate default VRF. */
        zebra_vrf_init();
 
-       zebra_ns_enable(0, (void **)&dzns);
+       /* Default NS is activated */
+       zebra_ns_enable(NS_DEFAULT, (void **)&dzns);
 
        return 0;
 }
index 6cfba93e50ae66f8ecdccc6468acf7a03011ef89..5d90b9be67d3737ffed0c8f8797de72ee2455de6 100644 (file)
@@ -49,14 +49,14 @@ struct zebra_ns {
 
        struct route_table *if_table;
 
+       /* L3-VNI hash table (for EVPN). Only in default instance */
+       struct hash *l3vni_table;
+
 #if defined(HAVE_RTADV)
        struct rtadv rtadv;
 #endif /* HAVE_RTADV */
 };
 
-#define NS_DEFAULT 0
-#define NS_UNKNOWN UINT16_MAX
-
 struct zebra_ns *zebra_ns_lookup(ns_id_t ns_id);
 
 int zebra_ns_init(void);
index 769d2f566619a1dce2690187241aae1691be4ed9..187c2594adc1568dec7db3db5f72db6393ddd447 100644 (file)
@@ -432,7 +432,7 @@ static void if_bfd_session_update(struct interface *ifp, struct prefix *dp,
                } else {
                        zlog_debug(
                                "MESSAGE: ZEBRA_INTERFACE_BFD_DEST_UPDATE %s/%d "
-                               "with src %s/%d and vrf %d %s event",
+                               "with src %s/%d and vrf %u %s event",
                                inet_ntop(dp->family, &dp->u.prefix, buf[0],
                                          INET6_ADDRSTRLEN),
                                dp->prefixlen,
@@ -816,6 +816,8 @@ int zebra_ptm_bfd_dst_register(struct zserv *client, u_short length,
                           ptm_cb.out_data);
        zebra_ptm_send_message(ptm_cb.out_data, data_len);
 
+       return 0;
+
 stream_failure:
        ptm_lib_cleanup_msg(ptm_hdl, out_ctxt);
        return 0;
@@ -946,6 +948,8 @@ int zebra_ptm_bfd_dst_deregister(struct zserv *client, u_short length,
 
        zebra_ptm_send_message(ptm_cb.out_data, data_len);
 
+       return 0;
+
 stream_failure:
        ptm_lib_cleanup_msg(ptm_hdl, out_ctxt);
        return 0;
@@ -957,7 +961,7 @@ int zebra_ptm_bfd_client_register(struct zserv *client,
 {
        struct stream *s;
        unsigned int pid;
-       void *out_ctxt;
+       void *out_ctxt = NULL;
        char tmp_buf[64];
        int data_len = ZEBRA_PTM_SEND_MAX_SOCKBUF;
 
@@ -999,7 +1003,17 @@ int zebra_ptm_bfd_client_register(struct zserv *client,
 
        SET_FLAG(ptm_cb.client_flags[client->proto],
                 ZEBRA_PTM_BFD_CLIENT_FLAG_REG);
+
+       return 0;
+
 stream_failure:
+       /*
+        * IF we ever add more STREAM_GETXXX functions after the out_ctxt
+        * is allocated then we need to add this code back in
+        *
+        * if (out_ctxt)
+        *      ptm_lib_cleanup_msg(ptm_hdl, out_ctxt);
+        */
        return 0;
 }
 
index 1378ea186d51fe542b7fee2ec1d587141418fa52..8fddd400cc04ef89826d42e82692ed79f1158cd8 100644 (file)
@@ -41,7 +41,7 @@ static int zsend_interface_bfd_update(int cmd, struct zserv *client,
        s = client->obuf;
        stream_reset(s);
 
-       zserv_create_header(s, cmd, vrf_id);
+       zclient_create_header(s, cmd, vrf_id);
        if (ifp)
                stream_putl(s, ifp->ifindex);
        else
@@ -96,8 +96,7 @@ static int zsend_bfd_peer_replay(int cmd, struct zserv *client)
        s = client->obuf;
        stream_reset(s);
 
-       zserv_create_header(
-               s, cmd, VRF_DEFAULT); // Pending: adjust when multi-vrf bfd work
+       zclient_create_header(s, cmd, VRF_DEFAULT);
 
        /* Write packet size. */
        stream_putw_at(s, 0, stream_get_endp(s));
index 58b69659955cf2328e05592c225963376685af0d..967bc92850cb9d5282adf670fd15dc26ac77f009 100644 (file)
@@ -50,6 +50,7 @@
 #include "zebra/zebra_rnh.h"
 #include "zebra/interface.h"
 #include "zebra/connected.h"
+#include "zebra/zebra_vxlan.h"
 
 DEFINE_HOOK(rib_update, (struct route_node * rn, const char *reason),
            (rn, reason))
@@ -85,6 +86,7 @@ static const struct {
                [ZEBRA_ROUTE_BGP_DIRECT] = {ZEBRA_ROUTE_BGP_DIRECT, 20},
                [ZEBRA_ROUTE_BGP_DIRECT_EXT] = {ZEBRA_ROUTE_BGP_DIRECT_EXT, 20},
                [ZEBRA_ROUTE_BABEL] = {ZEBRA_ROUTE_BABEL, 100},
+               [ZEBRA_ROUTE_SHARP] = {ZEBRA_ROUTE_SHARP, 150},
 
        /* no entry/default: 150 */
 };
@@ -211,13 +213,15 @@ void route_entry_nexthop_delete(struct route_entry *re, struct nexthop *nexthop)
 
 
 struct nexthop *route_entry_nexthop_ifindex_add(struct route_entry *re,
-                                               ifindex_t ifindex)
+                                               ifindex_t ifindex,
+                                               vrf_id_t nh_vrf_id)
 {
        struct nexthop *nexthop;
 
        nexthop = nexthop_new();
        nexthop->type = NEXTHOP_TYPE_IFINDEX;
        nexthop->ifindex = ifindex;
+       nexthop->vrf_id = nh_vrf_id;
 
        route_entry_nexthop_add(re, nexthop);
 
@@ -226,12 +230,14 @@ struct nexthop *route_entry_nexthop_ifindex_add(struct route_entry *re,
 
 struct nexthop *route_entry_nexthop_ipv4_add(struct route_entry *re,
                                             struct in_addr *ipv4,
-                                            struct in_addr *src)
+                                            struct in_addr *src,
+                                            vrf_id_t nh_vrf_id)
 {
        struct nexthop *nexthop;
 
        nexthop = nexthop_new();
        nexthop->type = NEXTHOP_TYPE_IPV4;
+       nexthop->vrf_id = nh_vrf_id;
        nexthop->gate.ipv4 = *ipv4;
        if (src)
                nexthop->src.ipv4 = *src;
@@ -244,22 +250,25 @@ struct nexthop *route_entry_nexthop_ipv4_add(struct route_entry *re,
 struct nexthop *route_entry_nexthop_ipv4_ifindex_add(struct route_entry *re,
                                                     struct in_addr *ipv4,
                                                     struct in_addr *src,
-                                                    ifindex_t ifindex)
+                                                    ifindex_t ifindex,
+                                                    vrf_id_t nh_vrf_id)
 {
        struct nexthop *nexthop;
        struct interface *ifp;
 
        nexthop = nexthop_new();
+       nexthop->vrf_id = nh_vrf_id;
        nexthop->type = NEXTHOP_TYPE_IPV4_IFINDEX;
        nexthop->gate.ipv4 = *ipv4;
        if (src)
                nexthop->src.ipv4 = *src;
        nexthop->ifindex = ifindex;
-       ifp = if_lookup_by_index(nexthop->ifindex, re->vrf_id);
+       ifp = if_lookup_by_index(nexthop->ifindex, nh_vrf_id);
        /*Pending: need to think if null ifp here is ok during bootup?
          There was a crash because ifp here was coming to be NULL */
        if (ifp)
-               if (connected_is_unnumbered(ifp)) {
+               if (connected_is_unnumbered(ifp) ||
+                   CHECK_FLAG(re->flags, ZEBRA_FLAG_EVPN_ROUTE)) {
                        SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK);
                }
 
@@ -269,11 +278,13 @@ struct nexthop *route_entry_nexthop_ipv4_ifindex_add(struct route_entry *re,
 }
 
 struct nexthop *route_entry_nexthop_ipv6_add(struct route_entry *re,
-                                            struct in6_addr *ipv6)
+                                            struct in6_addr *ipv6,
+                                            vrf_id_t nh_vrf_id)
 {
        struct nexthop *nexthop;
 
        nexthop = nexthop_new();
+       nexthop->vrf_id = nh_vrf_id;
        nexthop->type = NEXTHOP_TYPE_IPV6;
        nexthop->gate.ipv6 = *ipv6;
 
@@ -284,11 +295,13 @@ struct nexthop *route_entry_nexthop_ipv6_add(struct route_entry *re,
 
 struct nexthop *route_entry_nexthop_ipv6_ifindex_add(struct route_entry *re,
                                                     struct in6_addr *ipv6,
-                                                    ifindex_t ifindex)
+                                                    ifindex_t ifindex,
+                                                    vrf_id_t nh_vrf_id)
 {
        struct nexthop *nexthop;
 
        nexthop = nexthop_new();
+       nexthop->vrf_id = nh_vrf_id;
        nexthop->type = NEXTHOP_TYPE_IPV6_IFINDEX;
        nexthop->gate.ipv6 = *ipv6;
        nexthop->ifindex = ifindex;
@@ -304,6 +317,7 @@ struct nexthop *route_entry_nexthop_blackhole_add(struct route_entry *re,
        struct nexthop *nexthop;
 
        nexthop = nexthop_new();
+       nexthop->vrf_id = VRF_DEFAULT;
        nexthop->type = NEXTHOP_TYPE_BLACKHOLE;
        nexthop->bh_type = bh_type;
 
@@ -320,6 +334,7 @@ static void nexthop_set_resolved(afi_t afi, struct nexthop *newhop,
        resolved_hop = nexthop_new();
        SET_FLAG(resolved_hop->flags, NEXTHOP_FLAG_ACTIVE);
 
+       resolved_hop->vrf_id = nexthop->vrf_id;
        switch (newhop->type) {
        case NEXTHOP_TYPE_IPV4:
        case NEXTHOP_TYPE_IPV4_IFINDEX:
@@ -370,6 +385,12 @@ static void nexthop_set_resolved(afi_t afi, struct nexthop *newhop,
                break;
        }
 
+       /* Copy labels of the resolved route */
+       if (newhop->nh_label)
+               nexthop_add_labels(resolved_hop, newhop->nh_label_type,
+                                  newhop->nh_label->num_labels,
+                                  &newhop->nh_label->label[0]);
+
        resolved_hop->rparent = nexthop;
        nexthop_add(&nexthop->resolved, resolved_hop);
 }
@@ -383,10 +404,11 @@ static int nexthop_active(afi_t afi, struct route_entry *re,
        struct prefix p;
        struct route_table *table;
        struct route_node *rn;
-       struct route_entry *match;
+       struct route_entry *match = NULL;
        int resolved;
        struct nexthop *newhop;
        struct interface *ifp;
+       rib_dest_t *dest;
 
        if ((nexthop->type == NEXTHOP_TYPE_IPV4)
            || nexthop->type == NEXTHOP_TYPE_IPV6)
@@ -394,7 +416,7 @@ static int nexthop_active(afi_t afi, struct route_entry *re,
 
        if (set) {
                UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE);
-               zebra_deregister_rnh_static_nexthops(re->vrf_id,
+               zebra_deregister_rnh_static_nexthops(nexthop->vrf_id,
                                                     nexthop->resolved, top);
                nexthops_free(nexthop->resolved);
                nexthop->resolved = NULL;
@@ -413,7 +435,7 @@ static int nexthop_active(afi_t afi, struct route_entry *re,
         * address in the routing table.
         */
        if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK)) {
-               ifp = if_lookup_by_index(nexthop->ifindex, re->vrf_id);
+               ifp = if_lookup_by_index(nexthop->ifindex, nexthop->vrf_id);
                if (ifp && connected_is_unnumbered(ifp)) {
                        if (if_is_operative(ifp))
                                return 1;
@@ -441,7 +463,7 @@ static int nexthop_active(afi_t afi, struct route_entry *re,
                break;
        }
        /* Lookup table.  */
-       table = zebra_vrf_table(afi, SAFI_UNICAST, re->vrf_id);
+       table = zebra_vrf_table(afi, SAFI_UNICAST, nexthop->vrf_id);
        if (!table)
                return 0;
 
@@ -463,20 +485,15 @@ static int nexthop_active(afi_t afi, struct route_entry *re,
                /* However, do not resolve over default route unless explicitly
                 * allowed. */
                if (is_default_prefix(&rn->p)
-                   && !nh_resolve_via_default(p.family))
+                   && !rnh_resolve_via_default(p.family))
                        return 0;
 
-               RNODE_FOREACH_RE (rn, match) {
-                       if (CHECK_FLAG(match->status, ROUTE_ENTRY_REMOVED))
-                               continue;
-
-                       /* if the next hop is imported from another table, skip
-                        * it */
-                       if (match->type == ZEBRA_ROUTE_TABLE)
-                               continue;
-                       if (CHECK_FLAG(match->status, ROUTE_ENTRY_SELECTED_FIB))
-                               break;
-               }
+               dest = rib_dest_from_rnode(rn);
+               if (dest && dest->selected_fib &&
+                   !CHECK_FLAG(dest->selected_fib->status,
+                               ROUTE_ENTRY_REMOVED) &&
+                   dest->selected_fib->type != ZEBRA_ROUTE_TABLE)
+                       match = dest->selected_fib;
 
                /* If there is no selected route or matched route is EGP, go up
                   tree. */
@@ -553,7 +570,7 @@ struct route_entry *rib_match(afi_t afi, safi_t safi, vrf_id_t vrf_id,
        struct prefix p;
        struct route_table *table;
        struct route_node *rn;
-       struct route_entry *match;
+       struct route_entry *match = NULL;
        struct nexthop *newhop;
 
        /* Lookup table.  */
@@ -574,15 +591,14 @@ struct route_entry *rib_match(afi_t afi, safi_t safi, vrf_id_t vrf_id,
        rn = route_node_match(table, (struct prefix *)&p);
 
        while (rn) {
+               rib_dest_t *dest;
+
                route_unlock_node(rn);
 
-               /* Pick up selected route. */
-               RNODE_FOREACH_RE (rn, match) {
-                       if (CHECK_FLAG(match->status, ROUTE_ENTRY_REMOVED))
-                               continue;
-                       if (CHECK_FLAG(match->status, ROUTE_ENTRY_SELECTED_FIB))
-                               break;
-               }
+               dest = rib_dest_from_rnode(rn);
+               if (dest && dest->selected_fib &&
+                   !CHECK_FLAG(dest->selected_fib->status, ROUTE_ENTRY_REMOVED))
+                       match = dest->selected_fib;
 
                /* If there is no selected route or matched route is EGP, go up
                   tree. */
@@ -689,8 +705,9 @@ struct route_entry *rib_lookup_ipv4(struct prefix_ipv4 *p, vrf_id_t vrf_id)
 {
        struct route_table *table;
        struct route_node *rn;
-       struct route_entry *match;
+       struct route_entry *match = NULL;
        struct nexthop *nexthop;
+       rib_dest_t *dest;
 
        /* Lookup table.  */
        table = zebra_vrf_table(AFI_IP, SAFI_UNICAST, vrf_id);
@@ -705,13 +722,11 @@ struct route_entry *rib_lookup_ipv4(struct prefix_ipv4 *p, vrf_id_t vrf_id)
 
        /* Unlock node. */
        route_unlock_node(rn);
+       dest = rib_dest_from_rnode(rn);
 
-       RNODE_FOREACH_RE (rn, match) {
-               if (CHECK_FLAG(match->status, ROUTE_ENTRY_REMOVED))
-                       continue;
-               if (CHECK_FLAG(match->status, ROUTE_ENTRY_SELECTED_FIB))
-                       break;
-       }
+       if (dest && dest->selected_fib &&
+           !CHECK_FLAG(dest->selected_fib->status, ROUTE_ENTRY_REMOVED))
+               match = dest->selected_fib;
 
        if (!match)
                return NULL;
@@ -743,9 +758,10 @@ int rib_lookup_ipv4_route(struct prefix_ipv4 *p, union sockunion *qgate,
 {
        struct route_table *table;
        struct route_node *rn;
-       struct route_entry *match;
+       struct route_entry *match = NULL;
        struct nexthop *nexthop;
        int nexthops_active;
+       rib_dest_t *dest;
 
        /* Lookup table.  */
        table = zebra_vrf_table(AFI_IP, SAFI_UNICAST, vrf_id);
@@ -761,15 +777,13 @@ int rib_lookup_ipv4_route(struct prefix_ipv4 *p, union sockunion *qgate,
 
        /* Unlock node. */
        route_unlock_node(rn);
+       dest = rib_dest_from_rnode(rn);
 
        /* Find out if a "selected" RR for the discovered RIB entry exists ever.
         */
-       RNODE_FOREACH_RE (rn, match) {
-               if (CHECK_FLAG(match->status, ROUTE_ENTRY_REMOVED))
-                       continue;
-               if (CHECK_FLAG(match->status, ROUTE_ENTRY_SELECTED_FIB))
-                       break;
-       }
+       if (dest && dest->selected_fib &&
+           !CHECK_FLAG(dest->selected_fib->status, ROUTE_ENTRY_REMOVED))
+               match = dest->selected_fib;
 
        /* None such found :( */
        if (!match)
@@ -837,7 +851,7 @@ static unsigned nexthop_active_check(struct route_node *rn,
                family = 0;
        switch (nexthop->type) {
        case NEXTHOP_TYPE_IFINDEX:
-               ifp = if_lookup_by_index(nexthop->ifindex, re->vrf_id);
+               ifp = if_lookup_by_index(nexthop->ifindex, nexthop->vrf_id);
                if (ifp && if_is_operative(ifp))
                        SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
                else
@@ -846,7 +860,9 @@ static unsigned nexthop_active_check(struct route_node *rn,
        case NEXTHOP_TYPE_IPV4:
        case NEXTHOP_TYPE_IPV4_IFINDEX:
                family = AFI_IP;
-               if (nexthop_active(AFI_IP, re, nexthop, set, rn))
+               if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_EVPN_RVTEP))
+                       SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
+               else if (nexthop_active(AFI_IP, re, nexthop, set, rn))
                        SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
                else
                        UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
@@ -863,7 +879,8 @@ static unsigned nexthop_active_check(struct route_node *rn,
                if (rn->p.family != AF_INET)
                        family = AFI_IP6;
                if (IN6_IS_ADDR_LINKLOCAL(&nexthop->gate.ipv6)) {
-                       ifp = if_lookup_by_index(nexthop->ifindex, re->vrf_id);
+                       ifp = if_lookup_by_index(nexthop->ifindex,
+                                                nexthop->vrf_id);
                        if (ifp && if_is_operative(ifp))
                                SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
                        else
@@ -906,15 +923,16 @@ static unsigned nexthop_active_check(struct route_node *rn,
        memset(&nexthop->rmap_src.ipv6, 0, sizeof(union g_addr));
 
        /* It'll get set if required inside */
-       ret = zebra_route_map_check(family, re->type, p, nexthop, re->vrf_id,
-                                   re->tag);
+       ret = zebra_route_map_check(family, re->type, p, nexthop,
+                                   nexthop->vrf_id, re->tag);
        if (ret == RMAP_DENYMATCH) {
                if (IS_ZEBRA_DEBUG_RIB) {
                        srcdest_rnode2str(rn, buf, sizeof(buf));
                        zlog_debug(
                                "%u:%s: Filtering out with NH out %s due to route map",
                                re->vrf_id, buf,
-                               ifindex2ifname(nexthop->ifindex, re->vrf_id));
+                               ifindex2ifname(nexthop->ifindex,
+                                              nexthop->vrf_id));
                }
                UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
        }
@@ -993,14 +1011,19 @@ int zebra_rib_labeled_unicast(struct route_entry *re)
        return 1;
 }
 
-void kernel_route_rib_pass_fail(struct prefix *p, struct route_entry *re,
+void kernel_route_rib_pass_fail(struct route_node *rn, struct prefix *p,
+                               struct route_entry *re,
                                enum southbound_results res)
 {
        struct nexthop *nexthop;
        char buf[PREFIX_STRLEN];
+       rib_dest_t *dest;
+
+       dest = rib_dest_from_rnode(rn);
 
        switch (res) {
        case SOUTHBOUND_INSTALL_SUCCESS:
+               dest->selected_fib = re;
                for (ALL_NEXTHOPS(re->nexthop, nexthop)) {
                        if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
                                continue;
@@ -1014,16 +1037,37 @@ void kernel_route_rib_pass_fail(struct prefix *p, struct route_entry *re,
                                         p, ZAPI_ROUTE_INSTALLED);
                break;
        case SOUTHBOUND_INSTALL_FAILURE:
+               /*
+                * I am not sure this is the right thing to do here
+                * but the code always set selected_fib before
+                * this assignment was moved here.
+                */
+               dest->selected_fib = re;
+
                zsend_route_notify_owner(re->type, re->instance, re->vrf_id,
                                         p, ZAPI_ROUTE_FAIL_INSTALL);
                zlog_warn("%u:%s: Route install failed", re->vrf_id,
                          prefix2str(p, buf, sizeof(buf)));
                break;
        case SOUTHBOUND_DELETE_SUCCESS:
+               /*
+                * The case where selected_fib is not re is
+                * when we have received a system route
+                * that is overriding our installed route
+                * as such we should leave the selected_fib
+                * pointer alone
+                */
+               if (dest->selected_fib == re)
+                       dest->selected_fib = NULL;
                for (ALL_NEXTHOPS(re->nexthop, nexthop))
                        UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
                break;
        case SOUTHBOUND_DELETE_FAILURE:
+               /*
+                * Should we set this to NULL if the
+                * delete fails?
+                */
+               dest->selected_fib = NULL;
                zlog_warn("%u:%s: Route Deletion failure", re->vrf_id,
                          prefix2str(p, buf, sizeof(buf)));
                break;
@@ -1078,7 +1122,7 @@ void rib_install_kernel(struct route_node *rn, struct route_entry *re,
         * the kernel.
         */
        hook_call(rib_update, rn, "installing in kernel");
-       kernel_route_rib(p, src_p, old, re);
+       kernel_route_rib(rn, p, src_p, old, re);
        zvrf->installs++;
 
        return;
@@ -1105,7 +1149,7 @@ void rib_uninstall_kernel(struct route_node *rn, struct route_entry *re)
         * the kernel.
         */
        hook_call(rib_update, rn, "uninstalling from kernel");
-       kernel_route_rib(p, src_p, re, NULL);
+       kernel_route_rib(rn, p, src_p, re, NULL);
        zvrf->removals++;
 
        return;
@@ -1115,8 +1159,9 @@ void rib_uninstall_kernel(struct route_node *rn, struct route_entry *re)
 static void rib_uninstall(struct route_node *rn, struct route_entry *re)
 {
        rib_table_info_t *info = srcdest_rnode_table_info(rn);
+       rib_dest_t *dest = rib_dest_from_rnode(rn);
 
-       if (CHECK_FLAG(re->status, ROUTE_ENTRY_SELECTED_FIB)) {
+       if (dest && dest->selected_fib == re) {
                if (info->safi == SAFI_UNICAST)
                        hook_call(rib_update, rn, "rib_uninstall");
 
@@ -1126,8 +1171,6 @@ static void rib_uninstall(struct route_node *rn, struct route_entry *re)
                /* If labeled-unicast route, uninstall transit LSP. */
                if (zebra_rib_labeled_unicast(re))
                        zebra_mpls_lsp_uninstall(info->zvrf, rn, re);
-
-               UNSET_FLAG(re->status, ROUTE_ENTRY_SELECTED_FIB);
        }
 
        if (CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED)) {
@@ -1201,6 +1244,8 @@ int rib_gc_dest(struct route_node *rn)
 static void rib_process_add_fib(struct zebra_vrf *zvrf, struct route_node *rn,
                                struct route_entry *new)
 {
+       rib_dest_t *dest = rib_dest_from_rnode(rn);
+
        hook_call(rib_update, rn, "new route selected");
 
        /* Update real nexthop. This may actually determine if nexthop is active
@@ -1210,7 +1255,6 @@ static void rib_process_add_fib(struct zebra_vrf *zvrf, struct route_node *rn,
                return;
        }
 
-       SET_FLAG(new->status, ROUTE_ENTRY_SELECTED_FIB);
        if (IS_ZEBRA_DEBUG_RIB) {
                char buf[SRCDEST2STR_BUFFER];
                srcdest_rnode2str(rn, buf, sizeof(buf));
@@ -1224,6 +1268,8 @@ static void rib_process_add_fib(struct zebra_vrf *zvrf, struct route_node *rn,
 
        if (!RIB_SYSTEM_ROUTE(new))
                rib_install_kernel(rn, new, NULL);
+       else
+               dest->selected_fib = new;
 
        UNSET_FLAG(new->status, ROUTE_ENTRY_CHANGED);
 }
@@ -1231,6 +1277,7 @@ static void rib_process_add_fib(struct zebra_vrf *zvrf, struct route_node *rn,
 static void rib_process_del_fib(struct zebra_vrf *zvrf, struct route_node *rn,
                                struct route_entry *old)
 {
+       rib_dest_t *dest = rib_dest_from_rnode(rn);
        hook_call(rib_update, rn, "removing existing route");
 
        /* Uninstall from kernel. */
@@ -1247,8 +1294,17 @@ static void rib_process_del_fib(struct zebra_vrf *zvrf, struct route_node *rn,
 
        if (!RIB_SYSTEM_ROUTE(old))
                rib_uninstall_kernel(rn, old);
-
-       UNSET_FLAG(old->status, ROUTE_ENTRY_SELECTED_FIB);
+       else {
+               /*
+                * We are setting this to NULL here
+                * because that is what we traditionally
+                * have been doing.  I am not positive
+                * that this is the right thing to do
+                * but let's leave the code alone
+                * for the RIB_SYSTEM_ROUTE case
+                */
+               dest->selected_fib = NULL;
+       }
 
        /* Update nexthop for route, reset changed flag. */
        nexthop_active_update(rn, old, 1);
@@ -1262,7 +1318,7 @@ static void rib_process_update_fib(struct zebra_vrf *zvrf,
 {
        struct nexthop *nexthop = NULL;
        int nh_active = 0;
-       int installed = 1;
+       rib_dest_t *dest = rib_dest_from_rnode(rn);
 
        /*
         * We have to install or update if a new route has been selected or
@@ -1311,11 +1367,23 @@ static void rib_process_update_fib(struct zebra_vrf *zvrf,
                                        zebra_mpls_lsp_install(zvrf, rn, new);
 
                                rib_install_kernel(rn, new, old);
+                       } else {
+                               /*
+                                * We do not need to install the
+                                * selected route because it
+                                * is already isntalled by
+                                * the system( ie not us )
+                                * so just mark it as winning
+                                * we do need to ensure that
+                                * if we uninstall a route
+                                * from ourselves we don't
+                                * over write this pointer
+                                */
+                               dest->selected_fib = NULL;
                        }
-
                        /* If install succeeded or system route, cleanup flags
                         * for prior route. */
-                       if (installed && new != old) {
+                       if (new != old) {
                                if (RIB_SYSTEM_ROUTE(new)) {
                                        if (!RIB_SYSTEM_ROUTE(old))
                                                rib_uninstall_kernel(rn, old);
@@ -1326,10 +1394,6 @@ static void rib_process_update_fib(struct zebra_vrf *zvrf,
                                                           NEXTHOP_FLAG_FIB);
                                }
                        }
-
-                       /* Update for redistribution. */
-                       if (installed)
-                               SET_FLAG(new->status, ROUTE_ENTRY_SELECTED_FIB);
                }
 
                /*
@@ -1337,7 +1401,7 @@ static void rib_process_update_fib(struct zebra_vrf *zvrf,
                 * failed, we
                 * may need to uninstall and delete for redistribution.
                 */
-               if (!nh_active || !installed) {
+               if (!nh_active) {
                        if (IS_ZEBRA_DEBUG_RIB) {
                                char buf[SRCDEST2STR_BUFFER];
                                srcdest_rnode2str(rn, buf, sizeof(buf));
@@ -1364,7 +1428,8 @@ static void rib_process_update_fib(struct zebra_vrf *zvrf,
 
                        if (!RIB_SYSTEM_ROUTE(old))
                                rib_uninstall_kernel(rn, old);
-                       UNSET_FLAG(new->status, ROUTE_ENTRY_SELECTED_FIB);
+                       else
+                               dest->selected_fib = NULL;
                }
        } else {
                /*
@@ -1377,12 +1442,12 @@ static void rib_process_update_fib(struct zebra_vrf *zvrf,
                 * to add routes.
                 */
                if (!RIB_SYSTEM_ROUTE(new)) {
-                       int in_fib = 0;
+                       bool in_fib = false;
 
                        for (ALL_NEXTHOPS(new->nexthop, nexthop))
                                if (CHECK_FLAG(nexthop->flags,
                                               NEXTHOP_FLAG_FIB)) {
-                                       in_fib = 1;
+                                       in_fib = true;
                                        break;
                                }
                        if (!in_fib)
@@ -1392,8 +1457,6 @@ static void rib_process_update_fib(struct zebra_vrf *zvrf,
 
        /* Update prior route. */
        if (new != old) {
-               UNSET_FLAG(old->status, ROUTE_ENTRY_SELECTED_FIB);
-
                /* Set real nexthop. */
                nexthop_active_update(rn, old, 1);
                UNSET_FLAG(old->status, ROUTE_ENTRY_CHANGED);
@@ -1475,6 +1538,15 @@ static void rib_process(struct route_node *rn)
        if (IS_ZEBRA_DEBUG_RIB_DETAILED)
                zlog_debug("%u:%s: Processing rn %p", vrf_id, buf, rn);
 
+       /*
+        * we can have rn's that have a NULL info pointer
+        * (dest).  As such let's not let the deref happen
+        * additionally we know RNODE_FOREACH_RE_SAFE
+        * will not iterate so we are ok.
+        */
+       if (dest)
+               old_fib = dest->selected_fib;
+
        RNODE_FOREACH_RE_SAFE (rn, re, next) {
                if (IS_ZEBRA_DEBUG_RIB_DETAILED)
                        zlog_debug(
@@ -1490,11 +1562,6 @@ static void rib_process(struct route_node *rn)
                        assert(old_selected == NULL);
                        old_selected = re;
                }
-               /* Currently in fib */
-               if (CHECK_FLAG(re->status, ROUTE_ENTRY_SELECTED_FIB)) {
-                       assert(old_fib == NULL);
-                       old_fib = re;
-               }
 
                /* Skip deleted entries from selection */
                if (CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED))
@@ -2044,6 +2111,9 @@ void rib_unlink(struct route_node *rn, struct route_entry *re)
                dest->routes = re->next;
        }
 
+       if (dest->selected_fib == re)
+               dest->selected_fib = NULL;
+
        /* free RE and nexthops */
        zebra_deregister_rnh_static_nexthops(re->vrf_id, re->nexthop, rn);
        nexthops_free(re->nexthop);
@@ -2183,8 +2253,8 @@ void rib_lookup_and_pushup(struct prefix_ipv4 *p, vrf_id_t vrf_id)
 {
        struct route_table *table;
        struct route_node *rn;
-       struct route_entry *re;
        unsigned changed = 0;
+       rib_dest_t *dest;
 
        if (NULL == (table = zebra_vrf_table(AFI_IP, SAFI_UNICAST, vrf_id))) {
                zlog_err("%s: zebra_vrf_table() returned NULL", __func__);
@@ -2198,6 +2268,7 @@ void rib_lookup_and_pushup(struct prefix_ipv4 *p, vrf_id_t vrf_id)
        /* Unlock node. */
        route_unlock_node(rn);
 
+       dest = rib_dest_from_rnode(rn);
        /* Check all RE entries. In case any changes have to be done, requeue
         * the RN into RIBQ head. If the routing message about the new connected
         * route (generated by the IP address we are going to assign very soon)
@@ -2206,20 +2277,17 @@ void rib_lookup_and_pushup(struct prefix_ipv4 *p, vrf_id_t vrf_id)
         * revalidation
         * of the rest of the RE.
         */
-       RNODE_FOREACH_RE (rn, re) {
-               if (CHECK_FLAG(re->status, ROUTE_ENTRY_SELECTED_FIB)
-                   && !RIB_SYSTEM_ROUTE(re)) {
-                       changed = 1;
-                       if (IS_ZEBRA_DEBUG_RIB) {
-                               char buf[PREFIX_STRLEN];
-                               zlog_debug(
-                                       "%u:%s: freeing way for connected prefix",
-                                       re->vrf_id,
-                                       prefix2str(&rn->p, buf, sizeof(buf)));
-                               route_entry_dump(&rn->p, NULL, re);
-                       }
-                       rib_uninstall(rn, re);
+       if (dest->selected_fib && !RIB_SYSTEM_ROUTE(dest->selected_fib)) {
+               changed = 1;
+               if (IS_ZEBRA_DEBUG_RIB) {
+                       char buf[PREFIX_STRLEN];
+
+                       zlog_debug("%u:%s: freeing way for connected prefix",
+                                  dest->selected_fib->vrf_id,
+                                  prefix2str(&rn->p, buf, sizeof(buf)));
+                       route_entry_dump(&rn->p, NULL, dest->selected_fib);
                }
+               rib_uninstall(rn, dest->selected_fib);
        }
        if (changed)
                rib_queue_add(rn);
@@ -2316,7 +2384,8 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p,
 void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type,
                u_short instance, int flags, struct prefix *p,
                struct prefix_ipv6 *src_p, const struct nexthop *nh,
-               u_int32_t table_id, u_int32_t metric, bool fromkernel)
+               u_int32_t table_id, u_int32_t metric, bool fromkernel,
+               struct ethaddr *rmac)
 {
        struct route_table *table;
        struct route_node *rn;
@@ -2325,6 +2394,7 @@ void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type,
        struct route_entry *same = NULL;
        struct nexthop *rtnh;
        char buf2[INET6_ADDRSTRLEN];
+       rib_dest_t *dest;
 
        assert(!src_p || afi == AFI_IP6);
 
@@ -2357,14 +2427,14 @@ void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type,
                return;
        }
 
+       dest = rib_dest_from_rnode(rn);
+       fib = dest->selected_fib;
+
        /* Lookup same type route. */
        RNODE_FOREACH_RE (rn, re) {
                if (CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED))
                        continue;
 
-               if (CHECK_FLAG(re->status, ROUTE_ENTRY_SELECTED_FIB))
-                       fib = re;
-
                if (re->type != type)
                        continue;
                if (re->instance != instance)
@@ -2427,8 +2497,12 @@ void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type,
                                        UNSET_FLAG(rtnh->flags,
                                                   NEXTHOP_FLAG_FIB);
 
-                               UNSET_FLAG(fib->status,
-                                          ROUTE_ENTRY_SELECTED_FIB);
+                               /*
+                                * This is a non FRR route
+                                * as such we should mark
+                                * it as deleted
+                                */
+                               dest->selected_fib = NULL;
                        } else {
                                /* This means someone else, other than Zebra,
                                 * has deleted
@@ -2469,6 +2543,22 @@ void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type,
 
                        return;
                }
+
+               if (CHECK_FLAG(flags, ZEBRA_FLAG_EVPN_ROUTE)) {
+                       struct nexthop *tmp_nh;
+
+                       for (ALL_NEXTHOPS(re->nexthop, tmp_nh)) {
+                               struct ipaddr vtep_ip;
+
+                               memset(&vtep_ip, 0, sizeof(struct ipaddr));
+                               vtep_ip.ipa_type = IPADDR_V4;
+                               memcpy(&(vtep_ip.ipaddr_v4),
+                                      &(tmp_nh->gate.ipv4),
+                                      sizeof(struct in_addr));
+                               zebra_vxlan_evpn_vrf_route_del(re->vrf_id, rmac,
+                                                              &vtep_ip, p);
+                       }
+               }
                rib_delnode(rn, same);
        }
 
@@ -2480,7 +2570,7 @@ void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type,
 int rib_add(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, u_short instance,
            int flags, struct prefix *p, struct prefix_ipv6 *src_p,
            const struct nexthop *nh, u_int32_t table_id, u_int32_t metric,
-           u_int32_t mtu, uint8_t distance)
+           u_int32_t mtu, uint8_t distance, route_tag_t tag)
 {
        struct route_entry *re;
        struct nexthop *nexthop;
@@ -2497,6 +2587,7 @@ int rib_add(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, u_short instance,
        re->vrf_id = vrf_id;
        re->nexthop_num = 0;
        re->uptime = time(NULL);
+       re->tag = tag;
 
        /* Add nexthop. */
        nexthop = nexthop_new();
@@ -2740,24 +2831,24 @@ void rib_close_table(struct route_table *table)
 {
        struct route_node *rn;
        rib_table_info_t *info;
-       struct route_entry *re;
+       rib_dest_t *dest;
 
        if (!table)
                return;
 
        info = table->info;
 
-       for (rn = route_top(table); rn; rn = srcdest_route_next(rn))
-               RNODE_FOREACH_RE (rn, re) {
-                       if (!CHECK_FLAG(re->status, ROUTE_ENTRY_SELECTED_FIB))
-                               continue;
+       for (rn = route_top(table); rn; rn = srcdest_route_next(rn)) {
+               dest = rib_dest_from_rnode(rn);
 
+               if (dest && dest->selected_fib) {
                        if (info->safi == SAFI_UNICAST)
                                hook_call(rib_update, rn, NULL);
 
-                       if (!RIB_SYSTEM_ROUTE(re))
-                               rib_uninstall_kernel(rn, re);
+                       if (!RIB_SYSTEM_ROUTE(dest->selected_fib))
+                               rib_uninstall_kernel(rn, dest->selected_fib);
                }
+       }
 }
 
 /* Routing information base initialize. */
index 33d0b3a641efef6a33cefbd6d45123cd057bf147..9fc5afff0f392e01bf16638ad16247f4f7f56048 100644 (file)
@@ -659,7 +659,7 @@ static struct route_entry *zebra_rnh_resolve_nexthop_entry(vrf_id_t vrfid,
                 * match route to be exact if so specified
                 */
                if (is_default_prefix(&rn->p) &&
-                   !nh_resolve_via_default(rn->p.family))
+                   !rnh_resolve_via_default(rn->p.family))
                        return NULL;
 
                /* Identify appropriate route entry. */
@@ -951,6 +951,7 @@ static void copy_state(struct rnh *rnh, struct route_entry *re,
        state->type = re->type;
        state->distance = re->distance;
        state->metric = re->metric;
+       state->vrf_id = re->vrf_id;
 
        route_entry_copy_nexthops(state, re->nexthop);
        rnh->state = state;
@@ -1000,7 +1001,7 @@ static int send_client(struct rnh *rnh, struct zserv *client, rnh_type_t type,
        s = client->obuf;
        stream_reset(s);
 
-       zserv_create_header(s, cmd, vrf_id);
+       zclient_create_header(s, cmd, vrf_id);
 
        stream_putw(s, rn->p.family);
        switch (rn->p.family) {
@@ -1032,6 +1033,7 @@ static int send_client(struct rnh *rnh, struct zserv *client, rnh_type_t type,
                                stream_putc(s, nexthop->type);
                                switch (nexthop->type) {
                                case NEXTHOP_TYPE_IPV4:
+                               case NEXTHOP_TYPE_IPV4_IFINDEX:
                                        stream_put_in_addr(s,
                                                           &nexthop->gate.ipv4);
                                        stream_putl(s, nexthop->ifindex);
@@ -1039,15 +1041,7 @@ static int send_client(struct rnh *rnh, struct zserv *client, rnh_type_t type,
                                case NEXTHOP_TYPE_IFINDEX:
                                        stream_putl(s, nexthop->ifindex);
                                        break;
-                               case NEXTHOP_TYPE_IPV4_IFINDEX:
-                                       stream_put_in_addr(s,
-                                                          &nexthop->gate.ipv4);
-                                       stream_putl(s, nexthop->ifindex);
-                                       break;
                                case NEXTHOP_TYPE_IPV6:
-                                       stream_put(s, &nexthop->gate.ipv6, 16);
-                                       stream_putl(s, nexthop->ifindex);
-                                       break;
                                case NEXTHOP_TYPE_IPV6_IFINDEX:
                                        stream_put(s, &nexthop->gate.ipv6, 16);
                                        stream_putl(s, nexthop->ifindex);
index 7e183684da40917a8bdbcee660c77c0b94060485..bd121ec83c6ef1d0f56541c1cc34cea451cda610 100644 (file)
@@ -54,6 +54,15 @@ typedef enum { RNH_NEXTHOP_TYPE, RNH_IMPORT_CHECK_TYPE } rnh_type_t;
 extern int zebra_rnh_ip_default_route;
 extern int zebra_rnh_ipv6_default_route;
 
+static inline int rnh_resolve_via_default(int family)
+{
+       if (((family == AF_INET) && zebra_rnh_ip_default_route)
+           || ((family == AF_INET6) && zebra_rnh_ipv6_default_route))
+               return 1;
+       else
+               return 0;
+}
+
 extern struct rnh *zebra_add_rnh(struct prefix *p, vrf_id_t vrfid,
                                 rnh_type_t type);
 extern struct rnh *zebra_lookup_rnh(struct prefix *p, vrf_id_t vrfid,
index 61af60b5da1e3ccd1d4dc16fc24d23a8799c246d..882a03f8445b68277446f0619145459c8c57b612 100644 (file)
@@ -1193,7 +1193,7 @@ static void *route_set_src_compile(const char *arg)
        union g_addr src, *psrc;
 
        if ((inet_pton(AF_INET6, arg, &src.ipv6) == 1)
-           || (src.ipv4.s_addr && (inet_pton(AF_INET, arg, &src.ipv4) == 1))) {
+           || (inet_pton(AF_INET, arg, &src.ipv4) == 1)) {
                psrc = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(union g_addr));
                *psrc = src;
                return psrc;
@@ -1329,7 +1329,7 @@ route_map_result_t zebra_nht_route_map_check(int family, int client_proto,
        struct nh_rmap_obj nh_obj;
 
        nh_obj.nexthop = nexthop;
-       nh_obj.vrf_id = re->vrf_id;
+       nh_obj.vrf_id = nexthop->vrf_id;
        nh_obj.source_protocol = re->type;
        nh_obj.metric = re->metric;
        nh_obj.tag = re->tag;
index 5927ba9d750e5146eec12125b3f308f55dc4b40d..b42bd818af5bc63ba4d66aa33ed4946fc1cba6d4 100644 (file)
@@ -87,35 +87,36 @@ void static_install_route(afi_t afi, safi_t safi, struct prefix *p,
                switch (si->type) {
                case STATIC_IPV4_GATEWAY:
                        nexthop = route_entry_nexthop_ipv4_add(
-                               re, &si->addr.ipv4, NULL);
+                               re, &si->addr.ipv4, NULL, si->nh_vrf_id);
                        nh_p.family = AF_INET;
                        nh_p.prefixlen = IPV4_MAX_BITLEN;
                        nh_p.u.prefix4 = si->addr.ipv4;
-                       zebra_register_rnh_static_nh(si->vrf_id, &nh_p, rn);
+                       zebra_register_rnh_static_nh(si->nh_vrf_id, &nh_p, rn);
                        break;
                case STATIC_IPV4_GATEWAY_IFNAME:
                        nexthop = route_entry_nexthop_ipv4_ifindex_add(
-                               re, &si->addr.ipv4, NULL, si->ifindex);
+                               re, &si->addr.ipv4, NULL, si->ifindex,
+                               si->nh_vrf_id);
                        break;
                case STATIC_IFNAME:
-                       nexthop = route_entry_nexthop_ifindex_add(re,
-                                                                 si->ifindex);
+                       nexthop = route_entry_nexthop_ifindex_add(
+                               re, si->ifindex, si->nh_vrf_id);
                        break;
                case STATIC_BLACKHOLE:
                        nexthop = route_entry_nexthop_blackhole_add(
                                re, bh_type);
                        break;
                case STATIC_IPV6_GATEWAY:
-                       nexthop = route_entry_nexthop_ipv6_add(re,
-                                                              &si->addr.ipv6);
+                       nexthop = route_entry_nexthop_ipv6_add(
+                               re, &si->addr.ipv6, si->nh_vrf_id);
                        nh_p.family = AF_INET6;
                        nh_p.prefixlen = IPV6_MAX_BITLEN;
                        nh_p.u.prefix6 = si->addr.ipv6;
-                       zebra_register_rnh_static_nh(si->vrf_id, &nh_p, rn);
+                       zebra_register_rnh_static_nh(si->nh_vrf_id, &nh_p, rn);
                        break;
                case STATIC_IPV6_GATEWAY_IFNAME:
                        nexthop = route_entry_nexthop_ipv6_ifindex_add(
-                               re, &si->addr.ipv6, si->ifindex);
+                               re, &si->addr.ipv6, si->ifindex, si->nh_vrf_id);
                        break;
                }
                /* Update label(s), if present. */
@@ -141,7 +142,7 @@ void static_install_route(afi_t afi, safi_t safi, struct prefix *p,
                 */
                if (si->type == STATIC_IPV4_GATEWAY
                    || si->type == STATIC_IPV6_GATEWAY)
-                       zebra_evaluate_rnh(si->vrf_id, nh_p.family, 1,
+                       zebra_evaluate_rnh(si->nh_vrf_id, nh_p.family, 1,
                                           RNH_NEXTHOP_TYPE, &nh_p);
                else
                        rib_queue_add(rn);
@@ -156,7 +157,7 @@ void static_install_route(afi_t afi, safi_t safi, struct prefix *p,
                re->mtu = 0;
                re->vrf_id = si->vrf_id;
                re->table =
-                       si->vrf_id
+                       (si->vrf_id != VRF_DEFAULT)
                                ? (zebra_vrf_lookup_by_id(si->vrf_id))->table_id
                                : zebrad.rtm_table_default;
                re->nexthop_num = 0;
@@ -165,35 +166,36 @@ void static_install_route(afi_t afi, safi_t safi, struct prefix *p,
                switch (si->type) {
                case STATIC_IPV4_GATEWAY:
                        nexthop = route_entry_nexthop_ipv4_add(
-                               re, &si->addr.ipv4, NULL);
+                               re, &si->addr.ipv4, NULL, si->nh_vrf_id);
                        nh_p.family = AF_INET;
                        nh_p.prefixlen = IPV4_MAX_BITLEN;
                        nh_p.u.prefix4 = si->addr.ipv4;
-                       zebra_register_rnh_static_nh(si->vrf_id, &nh_p, rn);
+                       zebra_register_rnh_static_nh(si->nh_vrf_id, &nh_p, rn);
                        break;
                case STATIC_IPV4_GATEWAY_IFNAME:
                        nexthop = route_entry_nexthop_ipv4_ifindex_add(
-                               re, &si->addr.ipv4, NULL, si->ifindex);
+                               re, &si->addr.ipv4, NULL, si->ifindex,
+                               si->nh_vrf_id);
                        break;
                case STATIC_IFNAME:
-                       nexthop = route_entry_nexthop_ifindex_add(re,
-                                                                 si->ifindex);
+                       nexthop = route_entry_nexthop_ifindex_add(
+                               re, si->ifindex, si->nh_vrf_id);
                        break;
                case STATIC_BLACKHOLE:
                        nexthop = route_entry_nexthop_blackhole_add(
                                re, bh_type);
                        break;
                case STATIC_IPV6_GATEWAY:
-                       nexthop = route_entry_nexthop_ipv6_add(re,
-                                                              &si->addr.ipv6);
+                       nexthop = route_entry_nexthop_ipv6_add(
+                               re, &si->addr.ipv6, si->nh_vrf_id);
                        nh_p.family = AF_INET6;
                        nh_p.prefixlen = IPV6_MAX_BITLEN;
                        nh_p.u.prefix6 = si->addr.ipv6;
-                       zebra_register_rnh_static_nh(si->vrf_id, &nh_p, rn);
+                       zebra_register_rnh_static_nh(si->nh_vrf_id, &nh_p, rn);
                        break;
                case STATIC_IPV6_GATEWAY_IFNAME:
                        nexthop = route_entry_nexthop_ipv6_ifindex_add(
-                               re, &si->addr.ipv6, si->ifindex);
+                               re, &si->addr.ipv6, si->ifindex, si->nh_vrf_id);
                        break;
                }
                /* Update label(s), if present. */
@@ -221,7 +223,7 @@ void static_install_route(afi_t afi, safi_t safi, struct prefix *p,
                if (si->type == STATIC_IPV4_GATEWAY
                    || si->type == STATIC_IPV6_GATEWAY) {
                        rib_addnode(rn, re, 0);
-                       zebra_evaluate_rnh(si->vrf_id, nh_p.family, 1,
+                       zebra_evaluate_rnh(si->nh_vrf_id, nh_p.family, 1,
                                           RNH_NEXTHOP_TYPE, &nh_p);
                } else
                        rib_addnode(rn, re, 1);
@@ -331,11 +333,12 @@ void static_uninstall_route(afi_t afi, safi_t safi, struct prefix *p,
                }
                UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
                if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB)) {
+                       rib_dest_t *dest = rib_dest_from_rnode(rn);
+
                        /* If there are other active nexthops, do an update. */
                        if (re->nexthop_active_num > 1) {
                                /* Update route in kernel if it's in fib */
-                               if (CHECK_FLAG(re->status,
-                                              ROUTE_ENTRY_SELECTED_FIB))
+                               if (dest->selected_fib)
                                        rib_install_kernel(rn, re, re);
                                /* Update redistribution if it's selected */
                                if (CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED))
@@ -350,8 +353,7 @@ void static_uninstall_route(afi_t afi, safi_t safi, struct prefix *p,
                                                p, (struct prefix *)src_p, re);
                                /* Remove from kernel if fib route becomes
                                 * inactive */
-                               if (CHECK_FLAG(re->status,
-                                              ROUTE_ENTRY_SELECTED_FIB))
+                               if (dest->selected_fib)
                                        rib_uninstall_kernel(rn, re);
                        }
                }
@@ -378,6 +380,7 @@ 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,
                     const char *ifname, enum static_blackhole_type bh_type,
                     route_tag_t tag, u_char distance, struct zebra_vrf *zvrf,
+                    struct zebra_vrf *nh_zvrf,
                     struct static_nh_label *snh_label)
 {
        struct route_node *rn;
@@ -439,6 +442,8 @@ int static_add_route(afi_t afi, safi_t safi, u_char type, struct prefix *p,
        si->bh_type = bh_type;
        si->tag = tag;
        si->vrf_id = zvrf_id(zvrf);
+       si->nh_vrf_id = zvrf_id(nh_zvrf);
+
        if (ifname)
                strlcpy(si->ifname, ifname, sizeof(si->ifname));
        si->ifindex = IFINDEX_INTERNAL;
@@ -493,7 +498,7 @@ int static_add_route(afi_t afi, safi_t safi, u_char type, struct prefix *p,
        else {
                struct interface *ifp;
 
-               ifp = if_lookup_by_name(ifname, zvrf_id(zvrf));
+               ifp = if_lookup_by_name(ifname, zvrf_id(nh_zvrf));
                if (ifp && ifp->ifindex != IFINDEX_INTERNAL) {
                        si->ifindex = ifp->ifindex;
                        static_install_route(afi, safi, p, src_p, si);
index 68fe73b0a348971c377d91f972769f75b0b23b30..234e3e4036060f0e4927a8bfdbed5e86f055bd20 100644 (file)
@@ -54,6 +54,7 @@ struct static_route {
 
        /* VRF identifier. */
        vrf_id_t vrf_id;
+       vrf_id_t nh_vrf_id;
 
        /* Administrative distance. */
        u_char distance;
@@ -89,6 +90,7 @@ extern int static_add_route(afi_t, safi_t safi, u_char type, struct prefix *p,
                            const char *ifname,
                            enum static_blackhole_type bh_type, route_tag_t tag,
                            u_char distance, struct zebra_vrf *zvrf,
+                           struct zebra_vrf *nh_zvrf,
                            struct static_nh_label *snh_label);
 
 extern int static_delete_route(afi_t, safi_t safi, u_char type,
index 0d0a8dd747e99b54e18753c2b201611b1dc66396..b9b3048486f7132b94d5dade28790c2a3624c77c 100644 (file)
 
 extern struct zebra_t zebrad;
 
+static void zebra_vrf_table_create(struct zebra_vrf *zvrf, afi_t afi,
+                                  safi_t safi);
+static void zebra_rnhtable_node_cleanup(struct route_table *table,
+                                       struct route_node *node);
+
 /* VRF information update. */
 static void zebra_vrf_add_update(struct zebra_vrf *zvrf)
 {
@@ -82,7 +87,7 @@ static int zebra_vrf_new(struct vrf *vrf)
        struct zebra_vrf *zvrf;
 
        if (IS_ZEBRA_DEBUG_EVENT)
-               zlog_info("ZVRF %s with id %u", vrf->name, vrf->vrf_id);
+               zlog_info("VRF %s created, id %u", vrf->name, vrf->vrf_id);
 
        zvrf = zebra_vrf_alloc();
        zvrf->zns = zebra_ns_lookup(
@@ -101,14 +106,36 @@ static int zebra_vrf_enable(struct vrf *vrf)
        struct route_table *stable;
        struct route_node *rn;
        struct static_route *si;
+       struct route_table *table;
        struct interface *ifp;
        afi_t afi;
        safi_t safi;
 
        assert(zvrf);
+       if (IS_ZEBRA_DEBUG_EVENT)
+               zlog_debug("VRF %s id %u is now active",
+                          zvrf_name(zvrf), zvrf_id(zvrf));
 
+       /* Inform clients that the VRF is now active. This is an
+        * add for the clients.
+        */
        zebra_vrf_add_update(zvrf);
 
+       /* Allocate tables */
+       for (afi = AFI_IP; afi <= AFI_IP6; afi++) {
+               for (safi = SAFI_UNICAST; safi <= SAFI_MULTICAST; safi++)
+                       zebra_vrf_table_create(zvrf, afi, safi);
+
+               table = route_table_init();
+               table->cleanup = zebra_rnhtable_node_cleanup;
+               zvrf->rnh_table[afi] = table;
+
+               table = route_table_init();
+               table->cleanup = zebra_rnhtable_node_cleanup;
+               zvrf->import_check_table[afi] = table;
+       }
+
+       /* Install any static routes configured for this VRF. */
        for (afi = AFI_IP; afi < AFI_MAX; afi++)
                for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) {
                        stable = zvrf->stable[afi][safi];
@@ -132,6 +159,9 @@ static int zebra_vrf_enable(struct vrf *vrf)
                                }
                }
 
+       /* Kick off any VxLAN-EVPN processing. */
+       zebra_vxlan_vrf_enable(zvrf);
+
        return 0;
 }
 
@@ -142,13 +172,19 @@ static int zebra_vrf_disable(struct vrf *vrf)
        struct route_table *stable;
        struct route_node *rn;
        struct static_route *si;
+       struct route_table *table;
+       struct interface *ifp;
+       u_int32_t table_id;
        afi_t afi;
        safi_t safi;
+       unsigned i;
 
-       if (IS_ZEBRA_DEBUG_KERNEL)
-               zlog_debug("VRF %s id %u is now disabled.", zvrf_name(zvrf),
-                          zvrf_id(zvrf));
+       assert(zvrf);
+       if (IS_ZEBRA_DEBUG_EVENT)
+               zlog_debug("VRF %s id %u is now inactive",
+                          zvrf_name(zvrf), zvrf_id(zvrf));
 
+       /* Uninstall any static routes configured for this VRF. */
        for (afi = AFI_IP; afi < AFI_MAX; afi++)
                for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) {
                        stable = zvrf->stable[afi][safi];
@@ -161,6 +197,84 @@ static int zebra_vrf_disable(struct vrf *vrf)
                                                afi, safi, &rn->p, NULL, si);
                }
 
+       /* Stop any VxLAN-EVPN processing. */
+       zebra_vxlan_vrf_disable(zvrf);
+
+       /* Inform clients that the VRF is now inactive. This is a
+        * delete for the clients.
+        */
+       zebra_vrf_delete_update(zvrf);
+
+       /* If asked to retain routes, there's nothing more to do. */
+       if (CHECK_FLAG(zvrf->flags, ZEBRA_VRF_RETAIN))
+               return 0;
+
+       /* Remove all routes. */
+       for (afi = AFI_IP; afi <= AFI_IP6; afi++) {
+               for (safi = SAFI_UNICAST; safi <= SAFI_MULTICAST; safi++)
+                       rib_close_table(zvrf->table[afi][safi]);
+
+               if (vrf->vrf_id == VRF_DEFAULT)
+                       for (table_id = 0; table_id < ZEBRA_KERNEL_TABLE_MAX;
+                            table_id++)
+                               if (zvrf->other_table[afi][table_id])
+                                       rib_close_table(zvrf->other_table[afi][table_id]);
+       }
+
+       /* Cleanup Vxlan, MPLS and PW tables. */
+       zebra_vxlan_cleanup_tables(zvrf);
+       zebra_mpls_cleanup_tables(zvrf);
+       zebra_pw_exit(zvrf);
+
+       /* Remove link-local IPv4 addresses created for BGP unnumbered peering. */
+       FOR_ALL_INTERFACES (vrf, ifp)
+               if_nbr_ipv6ll_to_ipv4ll_neigh_del_all(ifp);
+
+       /* clean-up work queues */
+       for (i = 0; i < MQ_SIZE; i++) {
+               struct listnode *lnode, *nnode;
+               struct route_node *rnode;
+               rib_dest_t *dest;
+
+               for (ALL_LIST_ELEMENTS(zebrad.mq->subq[i], lnode, nnode, rnode)) {
+                       dest = rib_dest_from_rnode(rnode);
+                       if (dest && rib_dest_vrf(dest) == zvrf) {
+                               route_unlock_node(rnode);
+                               list_delete_node(zebrad.mq->subq[i], lnode);
+                               zebrad.mq->size--;
+                       }
+               }
+       }
+
+       /* Cleanup (free) routing tables and NHT tables. */
+       for (afi = AFI_IP; afi <= AFI_IP6; afi++) {
+               void *table_info;
+
+               for (safi = SAFI_UNICAST; safi <= SAFI_MULTICAST; safi++) {
+                       table = zvrf->table[afi][safi];
+                       table_info = table->info;
+                       route_table_finish(table);
+                       XFREE(MTYPE_RIB_TABLE_INFO, table_info);
+                       zvrf->table[afi][safi] = NULL;
+               }
+
+               if (vrf->vrf_id == VRF_DEFAULT)
+                       for (table_id = 0; table_id < ZEBRA_KERNEL_TABLE_MAX;
+                            table_id++)
+                               if (zvrf->other_table[afi][table_id]) {
+                                       table = zvrf->other_table[afi][table_id];
+                                       table_info = table->info;
+                                       route_table_finish(table);
+                                       XFREE(MTYPE_RIB_TABLE_INFO, table_info);
+                                       zvrf->other_table[afi][table_id] = NULL;
+                               }
+
+               route_table_finish(zvrf->rnh_table[afi]);
+               zvrf->rnh_table[afi] = NULL;
+               route_table_finish(zvrf->import_check_table[afi]);
+               zvrf->import_check_table[afi] = NULL;
+       }
+
        return 0;
 }
 
@@ -174,38 +288,9 @@ static int zebra_vrf_delete(struct vrf *vrf)
        unsigned i;
 
        assert(zvrf);
-
-       zebra_vrf_delete_update(zvrf);
-
-       /* uninstall everything */
-       if (!CHECK_FLAG(zvrf->flags, ZEBRA_VRF_RETAIN)) {
-               struct interface *ifp;
-
-               for (afi = AFI_IP; afi <= AFI_IP6; afi++) {
-                       for (safi = SAFI_UNICAST; safi <= SAFI_MULTICAST;
-                            safi++)
-                               rib_close_table(zvrf->table[afi][safi]);
-
-                       if (vrf->vrf_id == VRF_DEFAULT)
-                               for (table_id = 0;
-                                    table_id < ZEBRA_KERNEL_TABLE_MAX;
-                                    table_id++)
-                                       if (zvrf->other_table[afi][table_id])
-                                               rib_close_table(
-                                                       zvrf->other_table
-                                                               [afi]
-                                                               [table_id]);
-               }
-
-               /* Cleanup Vxlan table and update kernel */
-               zebra_vxlan_close_tables(zvrf);
-
-               zebra_mpls_close_tables(zvrf);
-               zebra_pw_exit(zvrf);
-
-               FOR_ALL_INTERFACES (vrf, ifp)
-                       if_nbr_ipv6ll_to_ipv4ll_neigh_del_all(ifp);
-       }
+       if (IS_ZEBRA_DEBUG_EVENT)
+               zlog_debug("VRF %s id %u deleted",
+                          zvrf_name(zvrf), zvrf_id(zvrf));
 
        /* clean-up work queues */
        for (i = 0; i < MQ_SIZE; i++) {
@@ -213,8 +298,7 @@ static int zebra_vrf_delete(struct vrf *vrf)
                struct route_node *rnode;
                rib_dest_t *dest;
 
-               for (ALL_LIST_ELEMENTS(zebrad.mq->subq[i], lnode, nnode,
-                                      rnode)) {
+               for (ALL_LIST_ELEMENTS(zebrad.mq->subq[i], lnode, nnode, rnode)) {
                        dest = rib_dest_from_rnode(rnode);
                        if (dest && rib_dest_vrf(dest) == zvrf) {
                                route_unlock_node(rnode);
@@ -224,22 +308,27 @@ static int zebra_vrf_delete(struct vrf *vrf)
                }
        }
 
+       /* Free Vxlan and MPLS. */
+       zebra_vxlan_close_tables(zvrf);
+       zebra_mpls_close_tables(zvrf);
+
        /* release allocated memory */
        for (afi = AFI_IP; afi <= AFI_IP6; afi++) {
                void *table_info;
 
                for (safi = SAFI_UNICAST; safi <= SAFI_MULTICAST; safi++) {
                        table = zvrf->table[afi][safi];
-                       table_info = table->info;
-                       route_table_finish(table);
-                       XFREE(MTYPE_RIB_TABLE_INFO, table_info);
+                       if (table) {
+                               table_info = table->info;
+                               route_table_finish(table);
+                               XFREE(MTYPE_RIB_TABLE_INFO, table_info);
+                       }
 
                        table = zvrf->stable[afi][safi];
                        route_table_finish(table);
                }
 
-               for (table_id = 0; table_id < ZEBRA_KERNEL_TABLE_MAX;
-                    table_id++)
+               for (table_id = 0; table_id < ZEBRA_KERNEL_TABLE_MAX; table_id++)
                        if (zvrf->other_table[afi][table_id]) {
                                table = zvrf->other_table[afi][table_id];
                                table_info = table->info;
@@ -250,6 +339,10 @@ static int zebra_vrf_delete(struct vrf *vrf)
                route_table_finish(zvrf->rnh_table[afi]);
                route_table_finish(zvrf->import_check_table[afi]);
        }
+
+       /* Cleanup EVPN states for vrf */
+       zebra_vxlan_vrf_delete(zvrf);
+
        list_delete_all_node(zvrf->rid_all_sorted_list);
        list_delete_all_node(zvrf->rid_lo_sorted_list);
        XFREE(MTYPE_ZEBRA_VRF, zvrf);
@@ -258,6 +351,37 @@ static int zebra_vrf_delete(struct vrf *vrf)
        return 0;
 }
 
+/* Return if this VRF has any FRR configuration or not.
+ * IMPORTANT: This function needs to be updated when additional configuration
+ * is added for a VRF.
+ */
+int zebra_vrf_has_config(struct zebra_vrf *zvrf)
+{
+       afi_t afi;
+       safi_t safi;
+       struct route_table *stable;
+
+       /* NOTE: This is a don't care for the default VRF, but we go through
+        * the motions to keep things consistent.
+        */
+       /* Any static routes? */
+       for (afi = AFI_IP; afi < AFI_MAX; afi++) {
+               for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) {
+                       stable = zvrf->stable[afi][safi];
+                       if (!stable)
+                               continue;
+                       if (route_table_count(stable))
+                               return 1;
+               }
+       }
+
+       /* EVPN L3-VNI? */
+       if (zvrf->l3vni)
+               return 1;
+
+       return 0;
+}
+
 /* Lookup the routing table in a VRF based on both VRF-Id and table-id.
  * NOTE: Table-id is relevant only in the Default VRF.
  */
@@ -350,9 +474,9 @@ struct zebra_vrf *zebra_vrf_alloc(void)
 
        zvrf = XCALLOC(MTYPE_ZEBRA_VRF, sizeof(struct zebra_vrf));
 
+       /* Allocate table for static route configuration. */
        for (afi = AFI_IP; afi <= AFI_IP6; afi++) {
                for (safi = SAFI_UNICAST; safi <= SAFI_MULTICAST; safi++) {
-                       zebra_vrf_table_create(zvrf, afi, safi);
                        if (afi == AFI_IP6)
                                table = srcdest_table_init();
                        else
@@ -360,14 +484,6 @@ struct zebra_vrf *zebra_vrf_alloc(void)
                        table->cleanup = zebra_stable_node_cleanup;
                        zvrf->stable[afi][safi] = table;
                }
-
-               table = route_table_init();
-               table->cleanup = zebra_rnhtable_node_cleanup;
-               zvrf->rnh_table[afi] = table;
-
-               table = route_table_init();
-               table->cleanup = zebra_rnhtable_node_cleanup;
-               zvrf->import_check_table[afi] = table;
        }
 
        zebra_vxlan_init_tables(zvrf);
@@ -452,6 +568,7 @@ struct route_table *zebra_vrf_other_route_table(afi_t afi, u_int32_t table_id,
                        info->afi = afi;
                        info->safi = SAFI_UNICAST;
                        table->info = info;
+                       table->cleanup = zebra_rtable_node_cleanup;
                        zvrf->other_table[afi][table_id] = table;
                }
 
@@ -472,10 +589,25 @@ static int vrf_config_write(struct vty *vty)
                if (!zvrf)
                        continue;
 
-               if (strcmp(zvrf_name(zvrf), VRF_DEFAULT_NAME)) {
+               if (zvrf_id(zvrf) == VRF_DEFAULT) {
+                       if (zvrf->l3vni)
+                               vty_out(vty, "vni %u\n", zvrf->l3vni);
+                       vty_out(vty, "!\n");
+               }
+
+               if (vrf_is_user_cfged(vrf)) {
                        vty_out(vty, "vrf %s\n", zvrf_name(zvrf));
+                       if (zvrf->l3vni)
+                               vty_out(vty, " vni %u\n", zvrf->l3vni);
                        vty_out(vty, "!\n");
                }
+
+               static_config(vty, zvrf, AFI_IP, SAFI_UNICAST, "ip route");
+               static_config(vty, zvrf, AFI_IP, SAFI_MULTICAST, "ip mroute");
+               static_config(vty, zvrf, AFI_IP6, SAFI_UNICAST, "ipv6 route");
+
+               if (vrf->vrf_id != VRF_DEFAULT)
+                       vty_out(vty, "!\n");
        }
        return 0;
 }
index 1dfc0b3eb8b11f941209e6cb8a372ef49a377d93..d3a5316b9d4571b53b74c1349cedf43d0d829266 100644 (file)
@@ -24,6 +24,7 @@
 
 #include <zebra/zebra_ns.h>
 #include <zebra/zebra_pw.h>
+#include <lib/vxlan.h>
 
 /* MPLS (Segment Routing) global block */
 typedef struct mpls_srgb_t_ {
@@ -78,6 +79,9 @@ struct zebra_vrf {
         */
        struct zebra_ns *zns;
 
+       /* MPLS Label to handle L3VPN <-> vrf popping */
+       mpls_label_t label[AFI_MAX];
+
        /* MPLS static LSP config table */
        struct hash *slsp_table;
 
@@ -114,6 +118,9 @@ struct zebra_vrf {
         */
        int advertise_gw_macip;
 
+       /* l3-vni info */
+       vni_t l3vni;
+
        /* Route Installs */
        uint64_t installs;
        uint64_t removals;
@@ -145,5 +152,6 @@ extern struct route_table *zebra_vrf_static_table(afi_t, safi_t,
                                                  struct zebra_vrf *zvrf);
 extern struct route_table *
 zebra_vrf_other_route_table(afi_t afi, u_int32_t table_id, vrf_id_t vrf_id);
+extern int zebra_vrf_has_config(struct zebra_vrf *zvrf);
 extern void zebra_vrf_init(void);
 #endif
index e4407d731691f22719b10eff7481e059b0ef14a6..269244f7688dec1f72bd89407b46503c1f8cc41a 100644 (file)
@@ -49,6 +49,7 @@
 #include "zebra/zserv.h"
 #include "zebra/router-id.h"
 #include "zebra/ipforward.h"
+#include "zebra/zebra_vxlan_private.h"
 
 extern int allow_delete;
 
@@ -65,17 +66,28 @@ static void vty_show_ip_route_summary(struct vty *vty,
 static void vty_show_ip_route_summary_prefix(struct vty *vty,
                                             struct route_table *table);
 
+/*
+ * special macro to allow us to get the correct zebra_vrf
+ */
+#define ZEBRA_DECLVAR_CONTEXT(A, B)                    \
+       struct vrf *A = VTY_GET_CONTEXT(vrf);           \
+       struct zebra_vrf *B =                           \
+               (vrf) ? vrf->info : NULL;               \
+
 /* VNI range as per RFC 7432 */
 #define CMD_VNI_RANGE "(1-16777215)"
 
 /* General function for static route. */
-static int zebra_static_route(struct vty *vty, afi_t afi, safi_t safi,
-                             const char *negate, const char *dest_str,
-                             const char *mask_str, const char *src_str,
-                             const char *gate_str, const char *ifname,
-                             const char *flag_str, const char *tag_str,
-                             const char *distance_str, const char *vrf_id_str,
-                             const char *label_str)
+static int zebra_static_route_leak(struct vty *vty,
+                                  struct zebra_vrf *zvrf,
+                                  struct zebra_vrf *nh_zvrf,
+                                  afi_t afi, safi_t safi,
+                                  const char *negate, const char *dest_str,
+                                  const char *mask_str, const char *src_str,
+                                  const char *gate_str, const char *ifname,
+                                  const char *flag_str, const char *tag_str,
+                                  const char *distance_str,
+                                  const char *label_str)
 {
        int ret;
        u_char distance;
@@ -86,7 +98,6 @@ static int zebra_static_route(struct vty *vty, afi_t afi, safi_t safi,
        struct in_addr mask;
        enum static_blackhole_type bh_type = 0;
        route_tag_t tag = 0;
-       struct zebra_vrf *zvrf;
        u_char type;
        struct static_nh_label snh_label;
 
@@ -136,14 +147,6 @@ static int zebra_static_route(struct vty *vty, afi_t afi, safi_t safi,
        if (tag_str)
                tag = strtoul(tag_str, NULL, 10);
 
-       /* VRF id */
-       zvrf = zebra_vrf_lookup_by_name(vrf_id_str);
-
-       if (!zvrf) {
-               vty_out(vty, "%% vrf %s is not defined\n", vrf_id_str);
-               return CMD_WARNING_CONFIG_FAILED;
-       }
-
        /* Labels */
        memset(&snh_label, 0, sizeof(struct static_nh_label));
        if (label_str) {
@@ -162,8 +165,8 @@ static int zebra_static_route(struct vty *vty, afi_t afi, safi_t safi,
                        case -2:
                                vty_out(vty,
                                        "%% Cannot use reserved label(s) (%d-%d)\n",
-                                       MPLS_MIN_RESERVED_LABEL,
-                                       MPLS_MAX_RESERVED_LABEL);
+                                       MPLS_LABEL_RESERVED_MIN,
+                                       MPLS_LABEL_RESERVED_MAX);
                                break;
                        case -3:
                                vty_out(vty,
@@ -228,16 +231,68 @@ static int zebra_static_route(struct vty *vty, afi_t afi, safi_t safi,
                        type = STATIC_IPV6_GATEWAY;
        }
 
-       if (!negate)
+       if (!negate) {
                static_add_route(afi, safi, type, &p, src_p, gatep, ifname,
-                                bh_type, tag, distance, zvrf, &snh_label);
-       else
+                                bh_type, tag, distance, zvrf, nh_zvrf,
+                                &snh_label);
+               /* Mark as having FRR configuration */
+               vrf_set_user_cfged(zvrf->vrf);
+       } else {
                static_delete_route(afi, safi, type, &p, src_p, gatep, ifname,
                                    tag, distance, zvrf, &snh_label);
+               /* If no other FRR config for this VRF, mark accordingly. */
+               if (!zebra_vrf_has_config(zvrf))
+                       vrf_reset_user_cfged(zvrf->vrf);
+       }
 
        return CMD_SUCCESS;
 }
 
+static int zebra_static_route(struct vty *vty, afi_t afi, safi_t safi,
+                             const char *negate, const char *dest_str,
+                             const char *mask_str, const char *src_str,
+                             const char *gate_str, const char *ifname,
+                             const char *flag_str, const char *tag_str,
+                             const char *distance_str, const char *vrf_name,
+                             const char *label_str)
+{
+       struct zebra_vrf *zvrf;
+       struct vrf *vrf;
+
+       /* VRF id */
+       zvrf = zebra_vrf_lookup_by_name(vrf_name);
+
+       /* When trying to delete, the VRF must exist. */
+       if (negate && !zvrf) {
+               vty_out(vty, "%% vrf %s is not defined\n", vrf_name);
+               return CMD_WARNING_CONFIG_FAILED;
+       }
+
+       /* When trying to create, create the VRF if it doesn't exist.
+        * Note: The VRF isn't active until we hear about it from the kernel.
+        */
+       if (!zvrf) {
+               vrf = vrf_get(VRF_UNKNOWN, vrf_name);
+               if (!vrf) {
+                       vty_out(vty, "%% Could not create vrf %s\n", vrf_name);
+                       return CMD_WARNING_CONFIG_FAILED;
+               }
+               zvrf = vrf->info;
+               if (!zvrf) {
+                       vty_out(vty, "%% Could not create vrf-info %s\n",
+                               vrf_name);
+                       return CMD_WARNING_CONFIG_FAILED;
+               }
+               /* Mark as having FRR configuration */
+               vrf_set_user_cfged(vrf);
+       }
+       return zebra_static_route_leak(vty, zvrf, zvrf, afi, safi,
+                                      negate, dest_str, mask_str, src_str,
+                                      gate_str, ifname, flag_str, tag_str,
+                                      distance_str, label_str);
+}
+
+
 /* Static unicast routes for multicast RPF lookup. */
 DEFPY (ip_mroute_dist,
        ip_mroute_dist_cmd,
@@ -378,6 +433,43 @@ DEFPY(ip_route_blackhole,
                                  tag_str, distance_str, vrf, label);
 }
 
+DEFPY(ip_route_blackhole_vrf,
+      ip_route_blackhole_vrf_cmd,
+      "[no] ip route\
+       <A.B.C.D/M$prefix|A.B.C.D$prefix A.B.C.D$mask>                        \
+       <reject|blackhole>$flag                                               \
+       [{                                                                    \
+         tag (1-4294967295)                                                  \
+         |(1-255)$distance                                                   \
+         |label WORD                                                         \
+          }]",
+      NO_STR IP_STR
+      "Establish static routes\n"
+      "IP destination prefix (e.g. 10.0.0.0/8)\n"
+      "IP destination prefix\n"
+      "IP destination prefix mask\n"
+      "Emit an ICMP unreachable when matched\n"
+      "Silently discard pkts when matched\n"
+      "Set tag for this route\n"
+      "Tag value\n"
+      "Distance value for this route\n"
+      MPLS_LABEL_HELPSTR)
+{
+       VTY_DECLVAR_CONTEXT(vrf, vrf);
+       struct zebra_vrf *zvrf = vrf->info;
+
+       /*
+        * Coverity is complaining that prefix could
+        * be dereferenced, but we know that prefix will
+        * valid.  Add an assert to make it happy
+        */
+       assert(prefix);
+       return zebra_static_route_leak(vty, zvrf, zvrf,
+                                      AFI_IP, SAFI_UNICAST, no, prefix,
+                                      mask_str, NULL, NULL, NULL, flag,
+                                      tag_str, distance_str, label);
+}
+
 DEFPY(ip_route_address_interface,
       ip_route_address_interface_cmd,
       "[no] ip route\
@@ -389,6 +481,7 @@ DEFPY(ip_route_address_interface,
          |(1-255)$distance                            \
          |vrf NAME                                    \
          |label WORD                                  \
+         |nexthop-vrf NAME                            \
           }]",
       NO_STR IP_STR
       "Establish static routes\n"
@@ -402,16 +495,93 @@ DEFPY(ip_route_address_interface,
       "Tag value\n"
       "Distance value for this route\n"
       VRF_CMD_HELP_STR
-      MPLS_LABEL_HELPSTR)
+      MPLS_LABEL_HELPSTR
+      VRF_CMD_HELP_STR)
 {
+       struct zebra_vrf *zvrf;
+       struct zebra_vrf *nh_zvrf;
+
        const char *flag = NULL;
        if (ifname && !strncasecmp(ifname, "Null0", 5)) {
                flag = "Null0";
                ifname = NULL;
        }
-       return zebra_static_route(vty, AFI_IP, SAFI_UNICAST, no, prefix,
-                                 mask_str, NULL, gate_str, ifname, flag,
-                                 tag_str, distance_str, vrf, label);
+
+       zvrf = zebra_vrf_lookup_by_name(vrf);
+       if (!zvrf) {
+               vty_out(vty, "%% vrf %s is not defined\n",
+                       vrf);
+               return CMD_WARNING_CONFIG_FAILED;
+       }
+
+       if (nexthop_vrf)
+               nh_zvrf = zebra_vrf_lookup_by_name(nexthop_vrf);
+       else
+               nh_zvrf = zvrf;
+
+       if (!nh_zvrf) {
+               vty_out(vty, "%% nexthop vrf %s is not defined\n",
+                       nexthop_vrf);
+               return CMD_WARNING_CONFIG_FAILED;
+       }
+
+       return zebra_static_route_leak(vty, zvrf, nh_zvrf,
+                                      AFI_IP, SAFI_UNICAST, no, prefix,
+                                      mask_str, NULL, gate_str, ifname, flag,
+                                      tag_str, distance_str, label);
+}
+
+DEFPY(ip_route_address_interface_vrf,
+      ip_route_address_interface_vrf_cmd,
+      "[no] ip route\
+       <A.B.C.D/M$prefix|A.B.C.D$prefix A.B.C.D$mask> \
+       A.B.C.D$gate                                   \
+       INTERFACE$ifname                               \
+       [{                                             \
+         tag (1-4294967295)                           \
+         |(1-255)$distance                            \
+         |label WORD                                  \
+         |nexthop-vrf NAME                            \
+          }]",
+      NO_STR IP_STR
+      "Establish static routes\n"
+      "IP destination prefix (e.g. 10.0.0.0/8)\n"
+      "IP destination prefix\n"
+      "IP destination prefix mask\n"
+      "IP gateway address\n"
+      "IP gateway interface name. Specify 'Null0' (case-insensitive) for a \
+      null route.\n"
+      "Set tag for this route\n"
+      "Tag value\n"
+      "Distance value for this route\n"
+      MPLS_LABEL_HELPSTR
+      VRF_CMD_HELP_STR)
+{
+       VTY_DECLVAR_CONTEXT(vrf, vrf);
+       const char *flag = NULL;
+       struct zebra_vrf *zvrf = vrf->info;
+       struct zebra_vrf *nh_zvrf;
+
+       if (ifname && !strncasecmp(ifname, "Null0", 5)) {
+               flag = "Null0";
+               ifname = NULL;
+       }
+
+       if (nexthop_vrf)
+               nh_zvrf = zebra_vrf_lookup_by_name(nexthop_vrf);
+       else
+               nh_zvrf = zvrf;
+
+       if (!nh_zvrf) {
+               vty_out(vty, "%% nexthop vrf %s is not defined\n",
+                       nexthop_vrf);
+               return CMD_WARNING_CONFIG_FAILED;
+       }
+
+       return zebra_static_route_leak(vty, zvrf, nh_zvrf,
+                                      AFI_IP, SAFI_UNICAST, no, prefix,
+                                      mask_str, NULL, gate_str, ifname, flag,
+                                      tag_str, distance_str, label);
 }
 
 DEFPY(ip_route,
@@ -424,6 +594,7 @@ DEFPY(ip_route,
          |(1-255)$distance                            \
          |vrf NAME                                    \
          |label WORD                                  \
+         |nexthop-vrf NAME                            \
           }]",
       NO_STR IP_STR
       "Establish static routes\n"
@@ -436,16 +607,92 @@ DEFPY(ip_route,
       "Tag value\n"
       "Distance value for this route\n"
       VRF_CMD_HELP_STR
-      MPLS_LABEL_HELPSTR)
+      MPLS_LABEL_HELPSTR
+      VRF_CMD_HELP_STR)
 {
+       struct zebra_vrf *zvrf;
+       struct zebra_vrf *nh_zvrf;
        const char *flag = NULL;
+
        if (ifname && !strncasecmp(ifname, "Null0", 5)) {
                flag = "Null0";
                ifname = NULL;
        }
-       return zebra_static_route(vty, AFI_IP, SAFI_UNICAST, no, prefix,
-                                 mask_str, NULL, gate_str, ifname, flag,
-                                 tag_str, distance_str, vrf, label);
+
+       zvrf = zebra_vrf_lookup_by_name(vrf);
+       if (!zvrf) {
+               vty_out(vty, "%% vrf %s is not defined\n",
+                       vrf);
+               return CMD_WARNING_CONFIG_FAILED;
+       }
+
+       if (nexthop_vrf)
+               nh_zvrf = zebra_vrf_lookup_by_name(nexthop_vrf);
+       else
+               nh_zvrf = zvrf;
+
+       if (!nh_zvrf) {
+               vty_out(vty, "%% nexthop vrf %s is not defined\n",
+                       nexthop_vrf);
+               return CMD_WARNING_CONFIG_FAILED;
+       }
+
+
+       return zebra_static_route_leak(vty, zvrf, nh_zvrf,
+                                      AFI_IP, SAFI_UNICAST, no, prefix,
+                                      mask_str, NULL, gate_str, ifname, flag,
+                                      tag_str, distance_str, label);
+}
+
+DEFPY(ip_route_vrf,
+      ip_route_vrf_cmd,
+      "[no] ip route\
+       <A.B.C.D/M$prefix|A.B.C.D$prefix A.B.C.D$mask> \
+       <A.B.C.D$gate|INTERFACE$ifname>                \
+       [{                                             \
+         tag (1-4294967295)                           \
+         |(1-255)$distance                            \
+         |label WORD                                  \
+         |nexthop-vrf NAME                            \
+          }]",
+      NO_STR IP_STR
+      "Establish static routes\n"
+      "IP destination prefix (e.g. 10.0.0.0/8)\n"
+      "IP destination prefix\n"
+      "IP destination prefix mask\n"
+      "IP gateway address\n"
+      "IP gateway interface name\n"
+      "Set tag for this route\n"
+      "Tag value\n"
+      "Distance value for this route\n"
+      MPLS_LABEL_HELPSTR
+      VRF_CMD_HELP_STR)
+{
+       VTY_DECLVAR_CONTEXT(vrf, vrf);
+       struct zebra_vrf *zvrf = vrf->info;
+       struct zebra_vrf *nh_zvrf;
+
+       const char *flag = NULL;
+       if (ifname && !strncasecmp(ifname, "Null0", 5)) {
+               flag = "Null0";
+               ifname = NULL;
+       }
+
+       if (nexthop_vrf)
+               nh_zvrf = zebra_vrf_lookup_by_name(nexthop_vrf);
+       else
+               nh_zvrf = zvrf;
+
+       if (!nh_zvrf) {
+               vty_out(vty, "%% nexthop vrf %s is not defined\n",
+                       nexthop_vrf);
+               return CMD_WARNING_CONFIG_FAILED;
+       }
+
+       return zebra_static_route_leak(vty, zvrf, nh_zvrf,
+                                      AFI_IP, SAFI_UNICAST, no, prefix,
+                                      mask_str, NULL, gate_str, ifname, flag,
+                                      tag_str, distance_str, label);
 }
 
 /* New RIB.  Detailed information for IPv4 route. */
@@ -474,8 +721,13 @@ static void vty_show_ip_route_detail(struct vty *vty, struct route_node *rn,
                vty_out(vty, "\"");
                vty_out(vty, ", distance %u, metric %u", re->distance,
                        re->metric);
-               if (re->tag)
+               if (re->tag) {
                        vty_out(vty, ", tag %u", re->tag);
+#if defined(SUPPORT_REALMS)
+                       if (re->tag > 0 && re->tag <= 255)
+                               vty_out(vty, "(realm)");
+#endif
+               }
                if (re->mtu)
                        vty_out(vty, ", mtu %u", re->mtu);
                if (re->vrf_id != VRF_DEFAULT) {
@@ -524,8 +776,9 @@ static void vty_show_ip_route_detail(struct vty *vty, struct route_node *rn,
                                        inet_ntoa(nexthop->gate.ipv4));
                                if (nexthop->ifindex)
                                        vty_out(vty, ", via %s",
-                                               ifindex2ifname(nexthop->ifindex,
-                                                              re->vrf_id));
+                                               ifindex2ifname(
+                                                       nexthop->ifindex,
+                                                       nexthop->vrf_id));
                                break;
                        case NEXTHOP_TYPE_IPV6:
                        case NEXTHOP_TYPE_IPV6_IFINDEX:
@@ -534,13 +787,14 @@ static void vty_show_ip_route_detail(struct vty *vty, struct route_node *rn,
                                                  buf, sizeof buf));
                                if (nexthop->ifindex)
                                        vty_out(vty, ", via %s",
-                                               ifindex2ifname(nexthop->ifindex,
-                                                              re->vrf_id));
+                                               ifindex2ifname(
+                                                       nexthop->ifindex,
+                                                       nexthop->vrf_id));
                                break;
                        case NEXTHOP_TYPE_IFINDEX:
                                vty_out(vty, " directly connected, %s",
                                        ifindex2ifname(nexthop->ifindex,
-                                                      re->vrf_id));
+                                                      nexthop->vrf_id));
                                break;
                        case NEXTHOP_TYPE_BLACKHOLE:
                                vty_out(vty, " unreachable");
@@ -562,6 +816,14 @@ static void vty_show_ip_route_detail(struct vty *vty, struct route_node *rn,
                        default:
                                break;
                        }
+
+                       if (re->vrf_id != nexthop->vrf_id) {
+                               struct vrf *vrf =
+                                       vrf_lookup_by_id(nexthop->vrf_id);
+
+                               vty_out(vty, "(vrf %s)", vrf->name);
+                       }
+
                        if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_DUPLICATE))
                                vty_out(vty, " (duplicate nexthop removed)");
 
@@ -700,8 +962,9 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn,
                                                            nexthop->ifindex);
                                        json_object_string_add(
                                                json_nexthop, "interfaceName",
-                                               ifindex2ifname(nexthop->ifindex,
-                                                              re->vrf_id));
+                                               ifindex2ifname(
+                                                       nexthop->ifindex,
+                                                       nexthop->vrf_id));
                                }
                                break;
                        case NEXTHOP_TYPE_IPV6:
@@ -719,8 +982,9 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn,
                                                            nexthop->ifindex);
                                        json_object_string_add(
                                                json_nexthop, "interfaceName",
-                                               ifindex2ifname(nexthop->ifindex,
-                                                              re->vrf_id));
+                                               ifindex2ifname(
+                                                       nexthop->ifindex,
+                                                       nexthop->vrf_id));
                                }
                                break;
 
@@ -733,7 +997,7 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn,
                                json_object_string_add(
                                        json_nexthop, "interfaceName",
                                        ifindex2ifname(nexthop->ifindex,
-                                                      re->vrf_id));
+                                                      nexthop->vrf_id));
                                break;
                        case NEXTHOP_TYPE_BLACKHOLE:
                                json_object_boolean_true_add(json_nexthop,
@@ -760,6 +1024,14 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn,
                                break;
                        }
 
+                       if (nexthop->vrf_id != re->vrf_id) {
+                               struct vrf *vrf =
+                                       vrf_lookup_by_id(nexthop->vrf_id);
+
+                               json_object_string_add(json_nexthop,
+                                                      "vrf",
+                                                      vrf->name);
+                       }
                        if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_DUPLICATE))
                                json_object_boolean_true_add(json_nexthop,
                                                             "duplicate");
@@ -867,7 +1139,7 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn,
                        if (nexthop->ifindex)
                                vty_out(vty, ", %s",
                                        ifindex2ifname(nexthop->ifindex,
-                                                      re->vrf_id));
+                                                      nexthop->vrf_id));
                        break;
                case NEXTHOP_TYPE_IPV6:
                case NEXTHOP_TYPE_IPV6_IFINDEX:
@@ -877,12 +1149,13 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn,
                        if (nexthop->ifindex)
                                vty_out(vty, ", %s",
                                        ifindex2ifname(nexthop->ifindex,
-                                                      re->vrf_id));
+                                                      nexthop->vrf_id));
                        break;
 
                case NEXTHOP_TYPE_IFINDEX:
                        vty_out(vty, " is directly connected, %s",
-                               ifindex2ifname(nexthop->ifindex, re->vrf_id));
+                               ifindex2ifname(nexthop->ifindex,
+                                              nexthop->vrf_id));
                        break;
                case NEXTHOP_TYPE_BLACKHOLE:
                        vty_out(vty, " unreachable");
@@ -903,6 +1176,13 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn,
                default:
                        break;
                }
+
+               if (nexthop->vrf_id != re->vrf_id) {
+                       struct vrf *vrf = vrf_lookup_by_id(nexthop->vrf_id);
+
+                       vty_out(vty, "(vrf %s)", vrf->name);
+               }
+
                if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE))
                        vty_out(vty, " inactive");
 
@@ -963,6 +1243,7 @@ static int do_show_ip_route(struct vty *vty, const char *vrf_name, afi_t afi,
                            u_short ospf_instance_id)
 {
        struct route_table *table;
+       rib_dest_t *dest;
        struct route_node *rn;
        struct route_entry *re;
        int first = 1;
@@ -1000,10 +1281,11 @@ static int do_show_ip_route(struct vty *vty, const char *vrf_name, afi_t afi,
 
        /* Show all routes. */
        for (rn = route_top(table); rn; rn = route_next(rn)) {
+               dest = rib_dest_from_rnode(rn);
+
                RNODE_FOREACH_RE (rn, re) {
                        if (use_fib
-                           && !CHECK_FLAG(re->status,
-                                          ROUTE_ENTRY_SELECTED_FIB))
+                           && re != dest->selected_fib)
                                continue;
 
                        if (tag && re->tag != tag)
@@ -1165,7 +1447,7 @@ DEFUN (ip_nht_default_route,
                return CMD_SUCCESS;
 
        zebra_rnh_ip_default_route = 1;
-       zebra_evaluate_rnh(0, AF_INET, 1, RNH_NEXTHOP_TYPE, NULL);
+       zebra_evaluate_rnh(VRF_DEFAULT, AF_INET, 1, RNH_NEXTHOP_TYPE, NULL);
        return CMD_SUCCESS;
 }
 
@@ -1181,7 +1463,7 @@ DEFUN (no_ip_nht_default_route,
                return CMD_SUCCESS;
 
        zebra_rnh_ip_default_route = 0;
-       zebra_evaluate_rnh(0, AF_INET, 1, RNH_NEXTHOP_TYPE, NULL);
+       zebra_evaluate_rnh(VRF_DEFAULT, AF_INET, 1, RNH_NEXTHOP_TYPE, NULL);
        return CMD_SUCCESS;
 }
 
@@ -1196,7 +1478,7 @@ DEFUN (ipv6_nht_default_route,
                return CMD_SUCCESS;
 
        zebra_rnh_ipv6_default_route = 1;
-       zebra_evaluate_rnh(0, AF_INET6, 1, RNH_NEXTHOP_TYPE, NULL);
+       zebra_evaluate_rnh(VRF_DEFAULT, AF_INET6, 1, RNH_NEXTHOP_TYPE, NULL);
        return CMD_SUCCESS;
 }
 
@@ -1212,7 +1494,7 @@ DEFUN (no_ipv6_nht_default_route,
                return CMD_SUCCESS;
 
        zebra_rnh_ipv6_default_route = 0;
-       zebra_evaluate_rnh(0, AF_INET6, 1, RNH_NEXTHOP_TYPE, NULL);
+       zebra_evaluate_rnh(VRF_DEFAULT, AF_INET6, 1, RNH_NEXTHOP_TYPE, NULL);
        return CMD_SUCCESS;
 }
 
@@ -1587,97 +1869,98 @@ static void vty_show_ip_route_summary_prefix(struct vty *vty,
 }
 
 /* Write static route configuration. */
-static int static_config(struct vty *vty, afi_t afi, safi_t safi,
-                        const char *cmd)
+int static_config(struct vty *vty, struct zebra_vrf *zvrf,
+                 afi_t afi, safi_t safi, const char *cmd)
 {
+       char spacing[100];
        struct route_node *rn;
        struct static_route *si;
        struct route_table *stable;
-       struct vrf *vrf;
-       struct zebra_vrf *zvrf;
        char buf[SRCDEST2STR_BUFFER];
        int write = 0;
 
-       RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
-               if (!(zvrf = vrf->info))
-                       continue;
-               if ((stable = zvrf->stable[afi][safi]) == NULL)
-                       continue;
+       if ((stable = zvrf->stable[afi][safi]) == NULL)
+               return write;
 
-               for (rn = route_top(stable); rn; rn = srcdest_route_next(rn))
-                       for (si = rn->info; si; si = si->next) {
-                               vty_out(vty, "%s %s", cmd,
-                                       srcdest_rnode2str(rn, buf, sizeof buf));
+       sprintf(spacing, "%s%s",
+               (zvrf->vrf->vrf_id == VRF_DEFAULT) ? "" : " ",
+               cmd);
 
-                               switch (si->type) {
-                               case STATIC_IPV4_GATEWAY:
-                                       vty_out(vty, " %s",
-                                               inet_ntoa(si->addr.ipv4));
-                                       break;
-                               case STATIC_IPV6_GATEWAY:
-                                       vty_out(vty, " %s",
-                                               inet_ntop(AF_INET6,
-                                                         &si->addr.ipv6, buf,
-                                                         sizeof buf));
-                                       break;
-                               case STATIC_IFNAME:
-                                       vty_out(vty, " %s", si->ifname);
-                                       break;
-                               case STATIC_BLACKHOLE:
-                                       switch (si->bh_type) {
-                                       case STATIC_BLACKHOLE_DROP:
-                                               vty_out(vty, " blackhole");
-                                               break;
-                                       case STATIC_BLACKHOLE_NULL:
-                                               vty_out(vty, " Null0");
-                                               break;
-                                       case STATIC_BLACKHOLE_REJECT:
-                                               vty_out(vty, " reject");
-                                               break;
-                                       }
+       for (rn = route_top(stable); rn; rn = srcdest_route_next(rn))
+               for (si = rn->info; si; si = si->next) {
+                       vty_out(vty, "%s %s", spacing,
+                               srcdest_rnode2str(rn, buf, sizeof buf));
+
+                       switch (si->type) {
+                       case STATIC_IPV4_GATEWAY:
+                               vty_out(vty, " %s",
+                                       inet_ntoa(si->addr.ipv4));
+                               break;
+                       case STATIC_IPV6_GATEWAY:
+                               vty_out(vty, " %s",
+                                       inet_ntop(AF_INET6,
+                                                 &si->addr.ipv6, buf,
+                                                 sizeof buf));
+                               break;
+                       case STATIC_IFNAME:
+                               vty_out(vty, " %s", si->ifname);
+                               break;
+                       case STATIC_BLACKHOLE:
+                               switch (si->bh_type) {
+                               case STATIC_BLACKHOLE_DROP:
+                                       vty_out(vty, " blackhole");
                                        break;
-                               case STATIC_IPV4_GATEWAY_IFNAME:
-                                       vty_out(vty, " %s %s",
-                                               inet_ntop(AF_INET,
-                                                         &si->addr.ipv4, buf,
-                                                         sizeof buf),
-                                               si->ifname);
+                               case STATIC_BLACKHOLE_NULL:
+                                       vty_out(vty, " Null0");
                                        break;
-                               case STATIC_IPV6_GATEWAY_IFNAME:
-                                       vty_out(vty, " %s %s",
-                                               inet_ntop(AF_INET6,
-                                                         &si->addr.ipv6, buf,
-                                                         sizeof buf),
-                                               si->ifname);
+                               case STATIC_BLACKHOLE_REJECT:
+                                       vty_out(vty, " reject");
                                        break;
                                }
+                               break;
+                       case STATIC_IPV4_GATEWAY_IFNAME:
+                               vty_out(vty, " %s %s",
+                                       inet_ntop(AF_INET,
+                                                 &si->addr.ipv4, buf,
+                                                 sizeof buf),
+                                       si->ifname);
+                               break;
+                       case STATIC_IPV6_GATEWAY_IFNAME:
+                               vty_out(vty, " %s %s",
+                                       inet_ntop(AF_INET6,
+                                                 &si->addr.ipv6, buf,
+                                                 sizeof buf),
+                                       si->ifname);
+                               break;
+                       }
 
-                               if (si->tag)
-                                       vty_out(vty, " tag %" ROUTE_TAG_PRI,
-                                               si->tag);
+                       if (si->tag)
+                               vty_out(vty, " tag %" ROUTE_TAG_PRI,
+                                       si->tag);
 
-                               if (si->distance
-                                   != ZEBRA_STATIC_DISTANCE_DEFAULT)
-                                       vty_out(vty, " %d", si->distance);
+                       if (si->distance
+                           != ZEBRA_STATIC_DISTANCE_DEFAULT)
+                               vty_out(vty, " %d", si->distance);
 
-                               if (si->vrf_id != VRF_DEFAULT)
-                                       vty_out(vty, " vrf %s",
-                                               zvrf_name(zvrf));
+                       if (si->nh_vrf_id != si->vrf_id) {
+                               struct vrf *vrf;
 
-                               /* Label information */
-                               if (si->snh_label.num_labels)
-                                       vty_out(vty, " label %s",
-                                               mpls_label2str(
-                                                       si->snh_label
-                                                               .num_labels,
-                                                       si->snh_label.label,
-                                                       buf, sizeof buf, 0));
+                               vrf = vrf_lookup_by_id(si->nh_vrf_id);
+                               vty_out(vty, " nexthop-vrf %s",
+                                       (vrf) ? vrf->name : "Unknown");
+                       }
 
-                               vty_out(vty, "\n");
+                       /* Label information */
+                       if (si->snh_label.num_labels)
+                               vty_out(vty, " label %s",
+                                       mpls_label2str(si->snh_label.num_labels,
+                                                      si->snh_label.label,
+                                                      buf, sizeof buf, 0));
 
-                               write = 1;
-                       }
-       }
+                       vty_out(vty, "\n");
+
+                       write = 1;
+               }
        return write;
 }
 
@@ -1711,6 +1994,44 @@ DEFPY(ipv6_route_blackhole,
                                  tag_str, distance_str, vrf, label);
 }
 
+DEFPY(ipv6_route_blackhole_vrf,
+      ipv6_route_blackhole_vrf_cmd,
+      "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \
+          <Null0|reject|blackhole>$flag                    \
+          [{                                               \
+            tag (1-4294967295)                             \
+            |(1-255)$distance                              \
+            |label WORD                                    \
+          }]",
+      NO_STR
+      IPV6_STR
+      "Establish static routes\n"
+      "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
+      "IPv6 source-dest route\n"
+      "IPv6 source prefix\n"
+      "Null interface\n"
+      "Emit an ICMP unreachable when matched\n"
+      "Silently discard pkts when matched\n"
+      "Set tag for this route\n"
+      "Tag value\n"
+      "Distance value for this prefix\n"
+      MPLS_LABEL_HELPSTR)
+{
+       VTY_DECLVAR_CONTEXT(vrf, vrf);
+       struct zebra_vrf *zvrf = vrf->info;
+
+       /*
+        * Coverity is complaining that prefix could
+        * be dereferenced, but we know that prefix will
+        * valid.  Add an assert to make it happy
+        */
+       assert(prefix);
+       return zebra_static_route_leak(vty, zvrf, zvrf,
+                                      AFI_IP6, SAFI_UNICAST, no, prefix_str,
+                                      NULL, from_str, NULL, NULL, flag,
+                                      tag_str, distance_str, label);
+}
+
 DEFPY(ipv6_route_address_interface,
       ipv6_route_address_interface_cmd,
       "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \
@@ -1721,6 +2042,7 @@ DEFPY(ipv6_route_address_interface,
             |(1-255)$distance                              \
             |vrf NAME                                      \
             |label WORD                                    \
+            |nexthop-vrf NAME                              \
           }]",
       NO_STR
       IPV6_STR
@@ -1734,11 +2056,80 @@ DEFPY(ipv6_route_address_interface,
       "Tag value\n"
       "Distance value for this prefix\n"
       VRF_CMD_HELP_STR
-      MPLS_LABEL_HELPSTR)
+      MPLS_LABEL_HELPSTR
+      VRF_CMD_HELP_STR)
 {
-       return zebra_static_route(vty, AFI_IP6, SAFI_UNICAST, no, prefix_str,
-                                 NULL, from_str, gate_str, ifname, NULL,
-                                 tag_str, distance_str, vrf, label);
+       struct zebra_vrf *zvrf;
+       struct zebra_vrf *nh_zvrf;
+
+       zvrf = zebra_vrf_lookup_by_name(vrf);
+       if (!zvrf) {
+               vty_out(vty, "%% vrf %s is not defined\n",
+                       vrf);
+               return CMD_WARNING_CONFIG_FAILED;
+       }
+
+       if (nexthop_vrf)
+               nh_zvrf = zebra_vrf_lookup_by_name(nexthop_vrf);
+       else
+               nh_zvrf = zvrf;
+
+       if (!nh_zvrf) {
+               vty_out(vty, "%% nexthop vrf %s is not defined\n",
+                       nexthop_vrf);
+               return CMD_WARNING_CONFIG_FAILED;
+       }
+
+       return zebra_static_route_leak(vty, zvrf, nh_zvrf,
+                                      AFI_IP6, SAFI_UNICAST, no, prefix_str,
+                                      NULL, from_str, gate_str, ifname, NULL,
+                                      tag_str, distance_str, label);
+}
+
+DEFPY(ipv6_route_address_interface_vrf,
+      ipv6_route_address_interface_vrf_cmd,
+      "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \
+          X:X::X:X$gate                                    \
+          INTERFACE$ifname                                 \
+          [{                                               \
+            tag (1-4294967295)                             \
+            |(1-255)$distance                              \
+            |label WORD                                    \
+            |nexthop-vrf NAME                              \
+          }]",
+      NO_STR
+      IPV6_STR
+      "Establish static routes\n"
+      "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
+      "IPv6 source-dest route\n"
+      "IPv6 source prefix\n"
+      "IPv6 gateway address\n"
+      "IPv6 gateway interface name\n"
+      "Set tag for this route\n"
+      "Tag value\n"
+      "Distance value for this prefix\n"
+      MPLS_LABEL_HELPSTR
+      VRF_CMD_HELP_STR)
+{
+       VTY_DECLVAR_CONTEXT(vrf, vrf);
+       struct zebra_vrf *zvrf = vrf->info;
+       struct zebra_vrf *nh_zvrf;
+
+       if (nexthop_vrf)
+               nh_zvrf = zebra_vrf_lookup_by_name(nexthop_vrf);
+       else
+               nh_zvrf = zvrf;
+
+       if (!nh_zvrf) {
+               vty_out(vty, "%% nexthop vrf %s is not defined\n",
+                       nexthop_vrf);
+               return CMD_WARNING_CONFIG_FAILED;
+       }
+
+       return zebra_static_route_leak(vty, zvrf, nh_zvrf,
+                                      AFI_IP6, SAFI_UNICAST, no, prefix_str,
+                                      NULL, from_str, gate_str, ifname, NULL,
+                                      tag_str, distance_str, label);
 }
 
 DEFPY(ipv6_route,
@@ -1750,6 +2141,7 @@ DEFPY(ipv6_route,
             |(1-255)$distance                              \
             |vrf NAME                                      \
             |label WORD                                    \
+            |nexthop-vrf NAME                              \
           }]",
       NO_STR
       IPV6_STR
@@ -1763,11 +2155,79 @@ DEFPY(ipv6_route,
       "Tag value\n"
       "Distance value for this prefix\n"
       VRF_CMD_HELP_STR
-      MPLS_LABEL_HELPSTR)
+      MPLS_LABEL_HELPSTR
+      VRF_CMD_HELP_STR)
 {
-       return zebra_static_route(vty, AFI_IP6, SAFI_UNICAST, no, prefix_str,
-                                 NULL, from_str, gate_str, ifname, NULL,
-                                 tag_str, distance_str, vrf, label);
+       struct zebra_vrf *zvrf;
+       struct zebra_vrf *nh_zvrf;
+
+       zvrf = zebra_vrf_lookup_by_name(vrf);
+       if (!zvrf) {
+               vty_out(vty, "%% vrf %s is not defined\n",
+                       vrf);
+               return CMD_WARNING_CONFIG_FAILED;
+       }
+
+       if (nexthop_vrf)
+               nh_zvrf = zebra_vrf_lookup_by_name(nexthop_vrf);
+       else
+               nh_zvrf = zvrf;
+
+       if (!nh_zvrf) {
+               vty_out(vty, "%% nexthop vrf %s is not defined\n",
+                       nexthop_vrf);
+               return CMD_WARNING_CONFIG_FAILED;
+       }
+
+       return zebra_static_route_leak(vty, zvrf, nh_zvrf,
+                                      AFI_IP6, SAFI_UNICAST, no, prefix_str,
+                                      NULL, from_str, gate_str, ifname, NULL,
+                                      tag_str, distance_str, label);
+}
+
+DEFPY(ipv6_route_vrf,
+      ipv6_route_vrf_cmd,
+      "[no] ipv6 route X:X::X:X/M$prefix [from X:X::X:X/M] \
+          <X:X::X:X$gate|INTERFACE$ifname>                 \
+          [{                                               \
+            tag (1-4294967295)                             \
+            |(1-255)$distance                              \
+            |label WORD                                    \
+            |nexthop-vrf NAME                              \
+          }]",
+      NO_STR
+      IPV6_STR
+      "Establish static routes\n"
+      "IPv6 destination prefix (e.g. 3ffe:506::/32)\n"
+      "IPv6 source-dest route\n"
+      "IPv6 source prefix\n"
+      "IPv6 gateway address\n"
+      "IPv6 gateway interface name\n"
+      "Set tag for this route\n"
+      "Tag value\n"
+      "Distance value for this prefix\n"
+      MPLS_LABEL_HELPSTR
+      VRF_CMD_HELP_STR)
+{
+       VTY_DECLVAR_CONTEXT(vrf, vrf);
+       struct zebra_vrf *zvrf = vrf->info;
+       struct zebra_vrf *nh_zvrf;
+
+       if (nexthop_vrf)
+               nh_zvrf = zebra_vrf_lookup_by_name(nexthop_vrf);
+       else
+               nh_zvrf = zvrf;
+
+       if (!nh_zvrf) {
+               vty_out(vty, "%% nexthop vrf %s is not defined\n",
+                       nexthop_vrf);
+               return CMD_WARNING_CONFIG_FAILED;
+       }
+
+       return zebra_static_route_leak(vty, zvrf, nh_zvrf,
+                                      AFI_IP6, SAFI_UNICAST, no, prefix_str,
+                                      NULL, from_str, gate_str, ifname, NULL,
+                                      tag_str, distance_str, label);
 }
 
 /*
@@ -1874,7 +2334,7 @@ DEFUN (show_vrf,
        RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
                if (!(zvrf = vrf->info))
                        continue;
-               if (!zvrf_id(zvrf))
+               if (zvrf_id(zvrf) == VRF_DEFAULT)
                        continue;
 
                vty_out(vty, "vrf %s ", zvrf_name(zvrf));
@@ -1883,12 +2343,173 @@ DEFUN (show_vrf,
                else
                        vty_out(vty, "id %u table %u", zvrf_id(zvrf),
                                zvrf->table_id);
+               if (vrf_is_user_cfged(vrf))
+                       vty_out(vty, " (configured)");
                vty_out(vty, "\n");
        }
 
        return CMD_SUCCESS;
 }
 
+DEFUN (default_vrf_vni_mapping,
+       default_vrf_vni_mapping_cmd,
+       "vni " CMD_VNI_RANGE,
+       "VNI corresponding to the DEFAULT VRF\n"
+       "VNI-ID\n")
+{
+       int ret = 0;
+       char err[ERR_STR_SZ];
+       struct zebra_vrf *zvrf = NULL;
+       vni_t vni = strtoul(argv[1]->arg, NULL, 10);
+
+       zvrf = vrf_info_lookup(VRF_DEFAULT);
+       if (!zvrf)
+               return CMD_WARNING;
+
+       ret = zebra_vxlan_process_vrf_vni_cmd(zvrf, vni, err, ERR_STR_SZ, 1);
+       if (ret != 0) {
+               vty_out(vty, "%s\n", err);
+               return CMD_WARNING;
+       }
+
+       return CMD_SUCCESS;
+}
+
+DEFUN (no_default_vrf_vni_mapping,
+       no_default_vrf_vni_mapping_cmd,
+       "no vni " CMD_VNI_RANGE,
+       NO_STR
+       "VNI corresponding to DEFAULT VRF\n"
+       "VNI-ID")
+{
+       int ret = 0;
+       char err[ERR_STR_SZ];
+       vni_t vni = strtoul(argv[2]->arg, NULL, 10);
+       struct zebra_vrf *zvrf = NULL;
+
+       zvrf = vrf_info_lookup(VRF_DEFAULT);
+       if (!zvrf)
+               return CMD_WARNING;
+
+       ret = zebra_vxlan_process_vrf_vni_cmd(zvrf, vni, err, ERR_STR_SZ, 0);
+       if (ret != 0) {
+               vty_out(vty, "%s\n", err);
+               return CMD_WARNING;
+       }
+
+       return CMD_SUCCESS;
+}
+
+DEFUN (vrf_vni_mapping,
+       vrf_vni_mapping_cmd,
+       "vni " CMD_VNI_RANGE,
+       "VNI corresponding to tenant VRF\n"
+       "VNI-ID\n")
+{
+       int ret = 0;
+
+       ZEBRA_DECLVAR_CONTEXT(vrf, zvrf);
+       vni_t vni = strtoul(argv[1]->arg, NULL, 10);
+       char err[ERR_STR_SZ];
+
+       assert(vrf);
+       assert(zvrf);
+
+       /* Mark as having FRR configuration */
+       vrf_set_user_cfged(vrf);
+       ret = zebra_vxlan_process_vrf_vni_cmd(zvrf, vni, err, ERR_STR_SZ, 1);
+       if (ret != 0) {
+               vty_out(vty, "%s\n", err);
+               return CMD_WARNING;
+       }
+
+       return CMD_SUCCESS;
+}
+
+DEFUN (no_vrf_vni_mapping,
+       no_vrf_vni_mapping_cmd,
+       "no vni " CMD_VNI_RANGE,
+       NO_STR
+       "VNI corresponding to tenant VRF\n"
+       "VNI-ID")
+{
+       int ret = 0;
+       char err[ERR_STR_SZ];
+       vni_t vni = strtoul(argv[2]->arg, NULL, 10);
+
+       ZEBRA_DECLVAR_CONTEXT(vrf, zvrf);
+
+       assert(vrf);
+       assert(zvrf);
+
+       ret = zebra_vxlan_process_vrf_vni_cmd(zvrf, vni, err, ERR_STR_SZ, 0);
+       if (ret != 0) {
+               vty_out(vty, "%s\n", err);
+               return CMD_WARNING;
+       }
+
+       /* If no other FRR config for this VRF, mark accordingly. */
+       if (!zebra_vrf_has_config(zvrf))
+               vrf_reset_user_cfged(vrf);
+
+       return CMD_SUCCESS;
+}
+
+/* show vrf */
+DEFUN (show_vrf_vni,
+       show_vrf_vni_cmd,
+       "show vrf vni [json]",
+       SHOW_STR
+       "VRF\n"
+       "VNI\n"
+       JSON_STR)
+{
+       struct vrf *vrf;
+       struct zebra_vrf *zvrf;
+       json_object *json = NULL;
+       json_object *json_vrfs = NULL;
+       u_char uj = use_json(argc, argv);
+
+       if (uj) {
+               json = json_object_new_object();
+               json_vrfs = json_object_new_array();
+       }
+
+       if (!uj)
+               vty_out(vty, "%-37s %-10s %-20s %-20s %-5s %-18s\n",
+                       "VRF", "VNI", "VxLAN IF", "L3-SVI", "State", "Rmac");
+
+       RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name) {
+               zvrf = vrf->info;
+               if (!zvrf)
+                       continue;
+
+               zebra_vxlan_print_vrf_vni(vty, zvrf, json_vrfs);
+       }
+
+       if (uj) {
+               json_object_object_add(json, "vrfs", json_vrfs);
+               vty_out(vty, "%s\n", json_object_to_json_string_ext(
+                                            json, JSON_C_TO_STRING_PRETTY));
+               json_object_free(json);
+       }
+
+       return CMD_SUCCESS;
+}
+
+DEFUN (show_evpn_global,
+       show_evpn_global_cmd,
+       "show evpn [json]",
+       SHOW_STR
+       "EVPN\n"
+       JSON_STR)
+{
+       u_char uj = use_json(argc, argv);
+
+       zebra_vxlan_print_evpn(vty, uj);
+       return CMD_SUCCESS;
+}
+
 DEFUN (show_evpn_vni,
        show_evpn_vni_cmd,
        "show evpn vni [json]",
@@ -1924,6 +2545,130 @@ DEFUN (show_evpn_vni_vni,
        return CMD_SUCCESS;
 }
 
+DEFUN (show_evpn_rmac_vni_mac,
+       show_evpn_rmac_vni_mac_cmd,
+       "show evpn rmac vni " CMD_VNI_RANGE " mac WORD [json]",
+       SHOW_STR
+       "EVPN\n"
+       "RMAC\n"
+       "L3 VNI\n"
+       "VNI number\n"
+       "MAC\n"
+       "mac-address (e.g. 0a:0a:0a:0a:0a:0a)\n"
+       JSON_STR)
+{
+       vni_t l3vni = 0;
+       struct ethaddr mac;
+       u_char uj = use_json(argc, argv);
+
+       l3vni = strtoul(argv[4]->arg, NULL, 10);
+       if (!prefix_str2mac(argv[6]->arg, &mac)) {
+               vty_out(vty, "%% Malformed MAC address\n");
+               return CMD_WARNING;
+       }
+       zebra_vxlan_print_specific_rmac_l3vni(vty, l3vni, &mac, uj);
+       return CMD_SUCCESS;
+}
+
+DEFUN (show_evpn_rmac_vni,
+       show_evpn_rmac_vni_cmd,
+       "show evpn rmac vni " CMD_VNI_RANGE "[json]",
+       SHOW_STR
+       "EVPN\n"
+       "RMAC\n"
+       "L3 VNI\n"
+       "VNI number\n"
+       JSON_STR)
+{
+       vni_t l3vni = 0;
+       u_char uj = use_json(argc, argv);
+
+       l3vni = strtoul(argv[4]->arg, NULL, 10);
+       zebra_vxlan_print_rmacs_l3vni(vty, l3vni, uj);
+
+       return CMD_SUCCESS;
+}
+
+DEFUN (show_evpn_rmac_vni_all,
+       show_evpn_rmac_vni_all_cmd,
+       "show evpn rmac vni all [json]",
+       SHOW_STR
+       "EVPN\n"
+       "RMAC addresses\n"
+       "L3 VNI\n"
+       "All VNIs\n"
+       JSON_STR)
+{
+       u_char uj = use_json(argc, argv);
+
+       zebra_vxlan_print_rmacs_all_l3vni(vty, uj);
+
+       return CMD_SUCCESS;
+}
+
+DEFUN (show_evpn_nh_vni_ip,
+       show_evpn_nh_vni_ip_cmd,
+       "show evpn next-hops vni " CMD_VNI_RANGE " ip WORD [json]",
+       SHOW_STR
+       "EVPN\n"
+       "Remote Vteps\n"
+       "L3 VNI\n"
+       "VNI number\n"
+       "Ip address\n"
+       "Host address (ipv4 or ipv6)\n"
+       JSON_STR)
+{
+       vni_t l3vni;
+       struct ipaddr ip;
+       u_char uj = use_json(argc, argv);
+
+       l3vni = strtoul(argv[4]->arg, NULL, 10);
+       if (str2ipaddr(argv[6]->arg, &ip) != 0) {
+               if (!uj)
+                       vty_out(vty, "%% Malformed Neighbor address\n");
+               return CMD_WARNING;
+       }
+       zebra_vxlan_print_specific_nh_l3vni(vty, l3vni, &ip, uj);
+
+       return CMD_SUCCESS;
+}
+
+DEFUN (show_evpn_nh_vni,
+       show_evpn_nh_vni_cmd,
+       "show evpn next-hops vni " CMD_VNI_RANGE "[json]",
+       SHOW_STR
+       "EVPN\n"
+       "Remote Vteps\n"
+       "L3 VNI\n"
+       "VNI number\n"
+       JSON_STR)
+{
+       vni_t l3vni;
+       u_char uj = use_json(argc, argv);
+
+       l3vni = strtoul(argv[4]->arg, NULL, 10);
+       zebra_vxlan_print_nh_l3vni(vty, l3vni, uj);
+
+       return CMD_SUCCESS;
+}
+
+DEFUN (show_evpn_nh_vni_all,
+       show_evpn_nh_vni_all_cmd,
+       "show evpn next-hops vni all [json]",
+       SHOW_STR
+       "EVPN\n"
+       "Remote VTEPs\n"
+       "L3 VNI\n"
+       "All VNIs\n"
+       JSON_STR)
+{
+       u_char uj = use_json(argc, argv);
+
+       zebra_vxlan_print_nh_all_l3vni(vty, uj);
+
+       return CMD_SUCCESS;
+}
+
 DEFUN (show_evpn_mac_vni,
        show_evpn_mac_vni_cmd,
        "show evpn mac vni " CMD_VNI_RANGE "[json]",
@@ -2144,11 +2889,8 @@ static int zebra_ip_config(struct vty *vty)
 {
        int write = 0;
 
-       write += static_config(vty, AFI_IP, SAFI_UNICAST, "ip route");
-       write += static_config(vty, AFI_IP, SAFI_MULTICAST, "ip mroute");
-       write += static_config(vty, AFI_IP6, SAFI_UNICAST, "ipv6 route");
-
        write += zebra_import_table_config(vty);
+
        return write;
 }
 
@@ -2584,8 +3326,11 @@ void zebra_vty_init(void)
        install_element(CONFIG_NODE, &ip_multicast_mode_cmd);
        install_element(CONFIG_NODE, &no_ip_multicast_mode_cmd);
        install_element(CONFIG_NODE, &ip_route_blackhole_cmd);
+       install_element(VRF_NODE, &ip_route_blackhole_vrf_cmd);
        install_element(CONFIG_NODE, &ip_route_address_interface_cmd);
+       install_element(VRF_NODE, &ip_route_address_interface_vrf_cmd);
        install_element(CONFIG_NODE, &ip_route_cmd);
+       install_element(VRF_NODE, &ip_route_vrf_cmd);
        install_element(CONFIG_NODE, &ip_zebra_import_table_distance_cmd);
        install_element(CONFIG_NODE, &no_ip_zebra_import_table_cmd);
        install_element(CONFIG_NODE, &zebra_workqueue_timer_cmd);
@@ -2594,6 +3339,7 @@ void zebra_vty_init(void)
        install_element(CONFIG_NODE, &no_zebra_packet_process_cmd);
 
        install_element(VIEW_NODE, &show_vrf_cmd);
+       install_element(VIEW_NODE, &show_vrf_vni_cmd);
        install_element(VIEW_NODE, &show_route_cmd);
        install_element(VIEW_NODE, &show_route_detail_cmd);
        install_element(VIEW_NODE, &show_route_summary_cmd);
@@ -2606,8 +3352,11 @@ void zebra_vty_init(void)
        install_element(VIEW_NODE, &show_ip_rpf_addr_cmd);
 
        install_element(CONFIG_NODE, &ipv6_route_blackhole_cmd);
+       install_element(VRF_NODE, &ipv6_route_blackhole_vrf_cmd);
        install_element(CONFIG_NODE, &ipv6_route_address_interface_cmd);
+       install_element(VRF_NODE, &ipv6_route_address_interface_vrf_cmd);
        install_element(CONFIG_NODE, &ipv6_route_cmd);
+       install_element(VRF_NODE, &ipv6_route_vrf_cmd);
        install_element(CONFIG_NODE, &ip_nht_default_route_cmd);
        install_element(CONFIG_NODE, &no_ip_nht_default_route_cmd);
        install_element(CONFIG_NODE, &ipv6_nht_default_route_cmd);
@@ -2617,8 +3366,15 @@ void zebra_vty_init(void)
        /* Commands for VRF */
        install_element(VIEW_NODE, &show_ipv6_mroute_vrf_all_cmd);
 
+       install_element(VIEW_NODE, &show_evpn_global_cmd);
        install_element(VIEW_NODE, &show_evpn_vni_cmd);
        install_element(VIEW_NODE, &show_evpn_vni_vni_cmd);
+       install_element(VIEW_NODE, &show_evpn_rmac_vni_mac_cmd);
+       install_element(VIEW_NODE, &show_evpn_rmac_vni_cmd);
+       install_element(VIEW_NODE, &show_evpn_rmac_vni_all_cmd);
+       install_element(VIEW_NODE, &show_evpn_nh_vni_ip_cmd);
+       install_element(VIEW_NODE, &show_evpn_nh_vni_cmd);
+       install_element(VIEW_NODE, &show_evpn_nh_vni_all_cmd);
        install_element(VIEW_NODE, &show_evpn_mac_vni_cmd);
        install_element(VIEW_NODE, &show_evpn_mac_vni_all_cmd);
        install_element(VIEW_NODE, &show_evpn_mac_vni_all_vtep_cmd);
@@ -2628,4 +3384,10 @@ void zebra_vty_init(void)
        install_element(VIEW_NODE, &show_evpn_neigh_vni_all_cmd);
        install_element(VIEW_NODE, &show_evpn_neigh_vni_neigh_cmd);
        install_element(VIEW_NODE, &show_evpn_neigh_vni_vtep_cmd);
+
+       install_element(CONFIG_NODE, &default_vrf_vni_mapping_cmd);
+       install_element(CONFIG_NODE, &no_default_vrf_vni_mapping_cmd);
+       install_element(VRF_NODE, &vrf_vni_mapping_cmd);
+       install_element(VRF_NODE, &no_vrf_vni_mapping_cmd);
+
 }
index 9c70b55a1a4e4cb4a4d82567efa2620ccbc0d50b..c9cc556a4478f6ea520d646763c775efb6c17778 100644 (file)
 #include "zebra/zebra_vxlan.h"
 #include "zebra/zebra_memory.h"
 #include "zebra/zebra_l2.h"
-#include "lib/json.h"
 
+DEFINE_MTYPE_STATIC(ZEBRA, HOST_PREFIX, "host prefix");
 DEFINE_MTYPE_STATIC(ZEBRA, ZVNI, "VNI hash");
+DEFINE_MTYPE_STATIC(ZEBRA, ZL3VNI, "L3 VNI hash");
 DEFINE_MTYPE_STATIC(ZEBRA, ZVNI_VTEP, "VNI remote VTEP");
 DEFINE_MTYPE_STATIC(ZEBRA, MAC, "VNI MAC");
 DEFINE_MTYPE_STATIC(ZEBRA, NEIGH, "VNI Neighbor");
@@ -57,10 +58,17 @@ DEFINE_MTYPE_STATIC(ZEBRA, NEIGH, "VNI Neighbor");
 
 
 /* static function declarations */
+static int ip_prefix_send_to_client(vrf_id_t vrf_id,
+                                            struct prefix *p,
+                                            uint16_t cmd);
 static void zvni_print_neigh(zebra_neigh_t *n, void *ctxt, json_object *json);
 static void zvni_print_neigh_hash(struct hash_backet *backet, void *ctxt);
 static void zvni_print_neigh_hash_all_vni(struct hash_backet *backet,
                                          void **args);
+static void zl3vni_print_nh(zebra_neigh_t *n, struct vty *vty,
+                           json_object *json);
+static void zl3vni_print_rmac(zebra_mac_t *zrmac, struct vty *vty,
+                             json_object *json);
 static void zvni_print_mac(zebra_mac_t *mac, void *ctxt);
 static void zvni_print_mac_hash(struct hash_backet *backet, void *ctxt);
 static void zvni_print_mac_hash_all_vni(struct hash_backet *backet, void *ctxt);
@@ -91,11 +99,45 @@ static int zvni_neigh_send_del_to_client(vni_t vni,
                                         struct ethaddr *macaddr, u_char flags);
 static int zvni_neigh_install(zebra_vni_t *zvni, zebra_neigh_t *n);
 static int zvni_neigh_uninstall(zebra_vni_t *zvni, zebra_neigh_t *n);
-static zebra_vni_t *zvni_map_svi(struct interface *ifp,
+static zebra_vni_t *zvni_from_svi(struct interface *ifp,
                                 struct interface *br_if);
 static struct interface *zvni_map_to_svi(vlanid_t vid,
                                         struct interface *br_if);
 
+/* l3-vni next-hop neigh related APIs */
+static zebra_neigh_t *zl3vni_nh_lookup(zebra_l3vni_t *zl3vni,
+                                      struct ipaddr *ip);
+static void *zl3vni_nh_alloc(void *p);
+static zebra_neigh_t *zl3vni_nh_add(zebra_l3vni_t *zl3vni,
+                                   struct ipaddr *vtep_ip,
+                                   struct ethaddr *rmac);
+static int zl3vni_nh_del(zebra_l3vni_t *zl3vni, zebra_neigh_t *n);
+static int zl3vni_nh_install(zebra_l3vni_t *zl3vni, zebra_neigh_t *n);
+static int zl3vni_nh_uninstall(zebra_l3vni_t *zl3vni, zebra_neigh_t *n);
+
+/* l3-vni rmac related APIs */
+static void zl3vni_print_rmac_hash(struct hash_backet *, void *);
+static zebra_mac_t *zl3vni_rmac_lookup(zebra_l3vni_t *zl3vni,
+                                      struct ethaddr *rmac);
+static void *zl3vni_rmac_alloc(void *p);
+static zebra_mac_t *zl3vni_rmac_add(zebra_l3vni_t *zl3vni,
+                                   struct ethaddr *rmac);
+static int zl3vni_rmac_del(zebra_l3vni_t *zl3vni, zebra_mac_t *zrmac);
+static int zl3vni_rmac_install(zebra_l3vni_t *zl3vni, zebra_mac_t *zrmac);
+static int zl3vni_rmac_uninstall(zebra_l3vni_t *zl3vni,
+                                zebra_mac_t *zrmac);
+
+/* l3-vni related APIs*/
+static zebra_l3vni_t *zl3vni_lookup(vni_t vni);
+static void *zl3vni_alloc(void *p);
+static zebra_l3vni_t *zl3vni_add(vni_t vni, vrf_id_t vrf_id);
+static int zl3vni_del(zebra_l3vni_t *zl3vni);
+static zebra_l3vni_t *zl3vni_from_vrf(vrf_id_t);
+static struct interface *zl3vni_map_to_svi_if(zebra_l3vni_t *zl3vni);
+static struct interface *zl3vni_map_to_vxlan_if(zebra_l3vni_t *zl3vni);
+static void zebra_vxlan_process_l3vni_oper_up(zebra_l3vni_t *zl3vni);
+static void zebra_vxlan_process_l3vni_oper_down(zebra_l3vni_t *zl3vni);
+
 static unsigned int mac_hash_keymake(void *p);
 static int mac_cmp(const void *p1, const void *p2);
 static void *zvni_mac_alloc(void *p);
@@ -245,6 +287,12 @@ static void zvni_print_neigh(zebra_neigh_t *n, void *ctxt, json_object *json)
                                                         : "Inactive");
                }
        }
+       if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_DEF_GW)) {
+               if (!json)
+                       vty_out(vty, " Default-gateway");
+               else
+                       json_object_boolean_true_add(json, "defaultGateway");
+       }
        if (json == NULL)
                vty_out(vty, "\n");
 }
@@ -385,6 +433,85 @@ static void zvni_print_neigh_hash_all_vni(struct hash_backet *backet,
                json_object_object_add(json, vni_str, json_vni);
 }
 
+/* print a specific next hop for an l3vni */
+static void zl3vni_print_nh(zebra_neigh_t *n,
+                           struct vty *vty,
+                           json_object *json)
+{
+       char buf1[ETHER_ADDR_STRLEN];
+       char buf2[INET6_ADDRSTRLEN];
+       struct listnode *node = NULL;
+       struct prefix *p = NULL;
+       json_object *json_hosts = NULL;
+
+       if (!json) {
+               vty_out(vty, "Ip: %s\n",
+                       ipaddr2str(&n->ip, buf2, sizeof(buf2)));
+               vty_out(vty, "  RMAC: %s\n",
+                      prefix_mac2str(&n->emac, buf1, sizeof(buf1)));
+               vty_out(vty, "  Refcount: %d\n", listcount(n->host_list));
+               vty_out(vty, "  Prefixes:\n");
+               for (ALL_LIST_ELEMENTS_RO(n->host_list, node, p))
+                       vty_out(vty, "    %s\n",
+                               prefix2str(p, buf2, sizeof(buf2)));
+       } else {
+               json_hosts = json_object_new_array();
+               json_object_string_add(json, "ip",
+                                      ipaddr2str(&(n->ip), buf2,
+                                                 sizeof(buf2)));
+               json_object_string_add(json, "routerMac",
+                                      prefix_mac2str(&n->emac, buf2,
+                                                     sizeof(buf2)));
+               json_object_int_add(json, "refCount", listcount(n->host_list));
+               for (ALL_LIST_ELEMENTS_RO(n->host_list, node, p))
+                       json_object_array_add(json_hosts,
+                                             json_object_new_string(
+                                                       prefix2str(p, buf2,
+                                                               sizeof(buf2))));
+               json_object_object_add(json, "prefixList", json_hosts);
+       }
+}
+
+/* Print a specific RMAC entry */
+static void zl3vni_print_rmac(zebra_mac_t *zrmac,
+                             struct vty *vty,
+                             json_object *json)
+{
+       char buf1[ETHER_ADDR_STRLEN];
+       char buf2[PREFIX_STRLEN];
+       struct listnode *node = NULL;
+       struct prefix *p = NULL;
+       json_object *json_hosts = NULL;
+
+       if (!json) {
+               vty_out(vty, "MAC: %s\n",
+                       prefix_mac2str(&zrmac->macaddr, buf1, sizeof(buf1)));
+               vty_out(vty, " Remote VTEP: %s\n",
+                       inet_ntoa(zrmac->fwd_info.r_vtep_ip));
+               vty_out(vty, " Refcount: %d\n", listcount(zrmac->host_list));
+               vty_out(vty, "  Prefixes:\n");
+               for (ALL_LIST_ELEMENTS_RO(zrmac->host_list, node, p))
+                       vty_out(vty, "    %s\n",
+                               prefix2str(p, buf2, sizeof(buf2)));
+       } else {
+               json_hosts = json_object_new_array();
+               json_object_string_add(json, "routerMac",
+                                      prefix_mac2str(&zrmac->macaddr,
+                                                     buf1,
+                                                     sizeof(buf1)));
+               json_object_string_add(json, "vtepIp",
+                                      inet_ntoa(zrmac->fwd_info.r_vtep_ip));
+               json_object_int_add(json, "refCount",
+                                   listcount(zrmac->host_list));
+               for (ALL_LIST_ELEMENTS_RO(zrmac->host_list, node, p))
+                       json_object_array_add(json_hosts,
+                                             json_object_new_string(
+                                                       prefix2str(p, buf2,
+                                                               sizeof(buf2))));
+               json_object_object_add(json, "prefixList", json_hosts);
+       }
+}
+
 /*
  * Print a specific MAC entry.
  */
@@ -419,6 +546,12 @@ static void zvni_print_mac(zebra_mac_t *mac, void *ctxt)
                vty_out(vty, " Auto Mac ");
        }
 
+       if (CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY))
+               vty_out(vty, " Sticky Mac ");
+
+       if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DEF_GW))
+               vty_out(vty, " Default-gateway Mac ");
+
        vty_out(vty, "\n");
        /* print all the associated neigh */
        vty_out(vty, " Neighbors:\n");
@@ -603,6 +736,229 @@ static void zvni_print_mac_hash_all_vni(struct hash_backet *backet, void *ctxt)
        }
 }
 
+static void zl3vni_print_nh_hash(struct hash_backet *backet,
+                                void *ctx)
+{
+       struct nh_walk_ctx *wctx = NULL;
+       struct vty *vty = NULL;
+       struct json_object *json_vni = NULL;
+       struct json_object *json_nh = NULL;
+       zebra_neigh_t *n = NULL;
+       char buf1[ETHER_ADDR_STRLEN];
+       char buf2[INET6_ADDRSTRLEN];
+
+       wctx = (struct nh_walk_ctx *)ctx;
+       vty = wctx->vty;
+       json_vni = wctx->json;
+       if (json_vni)
+               json_nh = json_object_new_object();
+       n = (zebra_neigh_t *)backet->data;
+       if (!n)
+               return;
+
+       if (!json_vni) {
+               vty_out(vty, "%-15s %-17s\n",
+                       ipaddr2str(&(n->ip), buf2, sizeof(buf2)),
+                       prefix_mac2str(&n->emac, buf1, sizeof(buf1)));
+       } else {
+               json_object_string_add(json_nh, "nexthopIp",
+                                      ipaddr2str(&n->ip, buf2, sizeof(buf2)));
+               json_object_string_add(json_nh, "routerMac",
+                                      prefix_mac2str(&n->emac, buf1,
+                                                     sizeof(buf1)));
+               json_object_object_add(json_vni,
+                                      ipaddr2str(&(n->ip), buf2, sizeof(buf2)),
+                                      json_nh);
+       }
+}
+
+static void zl3vni_print_nh_hash_all_vni(struct hash_backet *backet,
+                                        void **args)
+{
+       struct vty *vty = NULL;
+       json_object *json = NULL;
+       json_object *json_vni = NULL;
+       zebra_l3vni_t *zl3vni = NULL;
+       uint32_t num_nh = 0;
+       struct nh_walk_ctx wctx;
+       char vni_str[VNI_STR_LEN];
+
+       vty = (struct vty *)args[0];
+       json = (struct json_object *)args[1];
+
+       zl3vni = (zebra_l3vni_t *)backet->data;
+       if (!zl3vni) {
+               if (json)
+                       vty_out(vty, "{}\n");
+               return;
+       }
+
+       num_nh = hashcount(zl3vni->nh_table);
+       if (!num_nh)
+               return;
+
+       if (json) {
+               json_vni = json_object_new_object();
+               snprintf(vni_str, VNI_STR_LEN, "%u", zl3vni->vni);
+       }
+
+       if (json == NULL) {
+               vty_out(vty, "\nVNI %u #Next-Hops %u\n\n",
+                       zl3vni->vni, num_nh);
+               vty_out(vty, "%-15s %-17s\n", "IP", "RMAC");
+       } else
+               json_object_int_add(json_vni, "numNextHops", num_nh);
+
+       memset(&wctx, 0, sizeof(struct nh_walk_ctx));
+       wctx.vty = vty;
+       wctx.json = json_vni;
+       hash_iterate(zl3vni->nh_table, zl3vni_print_nh_hash, &wctx);
+       if (json)
+               json_object_object_add(json, vni_str, json_vni);
+}
+
+static void zl3vni_print_rmac_hash_all_vni(struct hash_backet *backet,
+                                          void **args)
+{
+       struct vty *vty = NULL;
+       json_object *json = NULL;
+       json_object *json_vni = NULL;
+       zebra_l3vni_t *zl3vni = NULL;
+       u_int32_t num_rmacs;
+       struct rmac_walk_ctx wctx;
+       char vni_str[VNI_STR_LEN];
+
+       vty = (struct vty *)args[0];
+       json = (struct json_object *)args[1];
+
+       zl3vni = (zebra_l3vni_t *)backet->data;
+       if (!zl3vni) {
+               if (json)
+                       vty_out(vty, "{}\n");
+               return;
+       }
+
+       num_rmacs = hashcount(zl3vni->rmac_table);
+       if (!num_rmacs)
+               return;
+
+       if (json) {
+               json_vni = json_object_new_object();
+               snprintf(vni_str, VNI_STR_LEN, "%u", zl3vni->vni);
+       }
+
+       if (json == NULL) {
+               vty_out(vty, "\nVNI %u #RMACs %u\n\n",
+                       zl3vni->vni, num_rmacs);
+               vty_out(vty, "%-17s %-21s\n", "RMAC", "Remote VTEP");
+       } else
+               json_object_int_add(json_vni, "numRmacs", num_rmacs);
+
+       /* assign per-vni to wctx->json object to fill macs
+        * under the vni. Re-assign primary json object to fill
+        * next vni information.
+        */
+       memset(&wctx, 0, sizeof(struct rmac_walk_ctx));
+       wctx.vty = vty;
+       wctx.json = json_vni;
+       hash_iterate(zl3vni->rmac_table, zl3vni_print_rmac_hash, &wctx);
+       if (json)
+               json_object_object_add(json, vni_str, json_vni);
+}
+
+static void zl3vni_print_rmac_hash(struct hash_backet *backet,
+                                  void *ctx)
+{
+       zebra_mac_t *zrmac = NULL;
+       struct rmac_walk_ctx *wctx = NULL;
+       struct vty *vty = NULL;
+       struct json_object *json = NULL;
+       struct json_object *json_rmac = NULL;
+       char buf[ETHER_ADDR_STRLEN];
+
+       wctx = (struct rmac_walk_ctx *)ctx;
+       vty = wctx->vty;
+       json = wctx->json;
+       if (json)
+               json_rmac = json_object_new_object();
+       zrmac = (zebra_mac_t *)backet->data;
+       if (!zrmac)
+               return;
+
+       if (!json) {
+               vty_out(vty, "%-17s %-21s\n",
+                       prefix_mac2str(&zrmac->macaddr, buf, sizeof(buf)),
+                                       inet_ntoa(zrmac->fwd_info.r_vtep_ip));
+       } else {
+               json_object_string_add(json_rmac, "routerMac",
+                                      prefix_mac2str(&zrmac->macaddr, buf,
+                                                     sizeof(buf)));
+               json_object_string_add(json_rmac, "vtepIp",
+                                      inet_ntoa(zrmac->fwd_info.r_vtep_ip));
+               json_object_object_add(json,
+                                      prefix_mac2str(&zrmac->macaddr, buf,
+                                                     sizeof(buf)),
+                                      json_rmac);
+       }
+}
+
+/* print a specific L3 VNI entry */
+static void zl3vni_print(zebra_l3vni_t *zl3vni, void **ctx)
+{
+       char buf[ETHER_ADDR_STRLEN];
+       struct vty *vty = NULL;
+       json_object *json = NULL;
+       zebra_vni_t *zvni = NULL;
+       json_object *json_vni_list = NULL;
+       struct listnode *node = NULL, *nnode = NULL;
+
+       vty = ctx[0];
+       json = ctx[1];
+
+       if (!json) {
+               vty_out(vty, "VNI: %u\n", zl3vni->vni);
+               vty_out(vty, "  Type: %s\n", "L3");
+               vty_out(vty, "  Tenant VRF: %s\n",
+                       zl3vni_vrf_name(zl3vni));
+               vty_out(vty, "  Local Vtep Ip: %s\n",
+                       inet_ntoa(zl3vni->local_vtep_ip));
+               vty_out(vty, "  Vxlan-Intf: %s\n",
+                       zl3vni_vxlan_if_name(zl3vni));
+               vty_out(vty, "  SVI-If: %s\n",
+                       zl3vni_svi_if_name(zl3vni));
+               vty_out(vty, "  State: %s\n",
+                       zl3vni_state2str(zl3vni));
+               vty_out(vty, "  Router MAC: %s\n",
+                       zl3vni_rmac2str(zl3vni, buf, sizeof(buf)));
+               vty_out(vty, "  L2 VNIs: ");
+               for (ALL_LIST_ELEMENTS(zl3vni->l2vnis, node, nnode, zvni))
+                       vty_out(vty, "%u ", zvni->vni);
+               vty_out(vty, "\n");
+       } else {
+               json_vni_list = json_object_new_array();
+               json_object_int_add(json, "vni", zl3vni->vni);
+               json_object_string_add(json, "type", "L3");
+               json_object_string_add(json, "localVtepIp",
+                                      inet_ntoa(zl3vni->local_vtep_ip));
+               json_object_string_add(json, "vxlanIntf",
+                                      zl3vni_vxlan_if_name(zl3vni));
+               json_object_string_add(json, "sviIntf",
+                                      zl3vni_svi_if_name(zl3vni));
+               json_object_string_add(json, "state",
+                                      zl3vni_state2str(zl3vni));
+               json_object_string_add(json, "vrf",
+                                      zl3vni_vrf_name(zl3vni));
+               json_object_string_add(json, "routerMac",
+                                      zl3vni_rmac2str(zl3vni, buf,
+                                                      sizeof(buf)));
+               for (ALL_LIST_ELEMENTS(zl3vni->l2vnis, node, nnode, zvni)) {
+                       json_object_array_add(json_vni_list,
+                                             json_object_new_int(zvni->vni));
+               }
+               json_object_object_add(json, "l2Vnis", json_vni_list);
+       }
+}
+
 /*
  * Print a specific VNI entry.
  */
@@ -619,10 +975,16 @@ static void zvni_print(zebra_vni_t *zvni, void **ctxt)
        vty = ctxt[0];
        json = ctxt[1];
 
-       if (json == NULL)
+       if (json == NULL) {
                vty_out(vty, "VNI: %u\n", zvni->vni);
-       else
+               vty_out(vty, " Type: %s\n", "L2");
+               vty_out(vty, " Tenant VRF: %s\n", vrf_id_to_name(zvni->vrf_id));
+       } else {
                json_object_int_add(json, "vni", zvni->vni);
+               json_object_string_add(json, "type", "L2");
+               json_object_string_add(json, "vrf",
+                                      vrf_id_to_name(zvni->vrf_id));
+       }
 
        if (!zvni->vxlan_if) { // unexpected
                if (json == NULL)
@@ -631,11 +993,13 @@ static void zvni_print(zebra_vni_t *zvni, void **ctxt)
        }
        num_macs = num_valid_macs(zvni);
        num_neigh = hashcount(zvni->neigh_table);
-       if (json == NULL)
-               vty_out(vty, " VxLAN interface: %s ifIndex: %u VTEP IP: %s\n",
-                       zvni->vxlan_if->name, zvni->vxlan_if->ifindex,
+       if (json == NULL) {
+               vty_out(vty, " VxLAN interface: %s\n",
+                       zvni->vxlan_if->name);
+               vty_out(vty, " VxLAN ifIndex: %u\n", zvni->vxlan_if->ifindex);
+               vty_out(vty," Local VTEP IP: %s\n",
                        inet_ntoa(zvni->local_vtep_ip));
-       else {
+       else {
                json_object_string_add(json, "vxlanInterface",
                                       zvni->vxlan_if->name);
                json_object_int_add(json, "ifindex", zvni->vxlan_if->ifindex);
@@ -682,6 +1046,52 @@ static void zvni_print(zebra_vni_t *zvni, void **ctxt)
        }
 }
 
+/* print a L3 VNI hash entry */
+static void zl3vni_print_hash(struct hash_backet *backet,
+                             void *ctx[])
+{
+       struct vty *vty = NULL;
+       json_object *json = NULL;
+       json_object *json_vni = NULL;
+       zebra_l3vni_t *zl3vni = NULL;
+
+       vty = (struct vty *)ctx[0];
+       json = (json_object *)ctx[1];
+
+       zl3vni = (zebra_l3vni_t *)backet->data;
+       if (!zl3vni)
+               return;
+
+       if (!json) {
+               vty_out(vty,
+                       "%-10u %-4s %-21s %-8lu %-8lu %-15s %-37s\n",
+                       zl3vni->vni, "L3",
+                       zl3vni_vxlan_if_name(zl3vni),
+                       hashcount(zl3vni->rmac_table),
+                       hashcount(zl3vni->nh_table),
+                       "n/a",
+                       zl3vni_vrf_name(zl3vni));
+       } else {
+               char vni_str[VNI_STR_LEN];
+
+               snprintf(vni_str, VNI_STR_LEN, "%u", zl3vni->vni);
+               json_vni = json_object_new_object();
+               json_object_int_add(json_vni, "vni", zl3vni->vni);
+               json_object_string_add(json_vni, "vxlanIf",
+                                      zl3vni_vxlan_if_name(zl3vni));
+               json_object_int_add(json_vni, "numMacs",
+                                   hashcount(zl3vni->rmac_table));
+               json_object_int_add(json_vni, "numArpNd",
+                                   hashcount(zl3vni->nh_table));
+               json_object_string_add(json_vni, "numRemoteVteps", "n/a");
+               json_object_string_add(json_vni, "type", "L3");
+               json_object_string_add(json_vni, "tenantVrf",
+                                      zl3vni_vrf_name(zl3vni));
+               json_object_object_add(json, vni_str, json_vni);
+       }
+
+}
+
 /*
  * Print a VNI hash entry - called for display of all VNIs.
  */
@@ -714,22 +1124,26 @@ static void zvni_print_hash(struct hash_backet *backet, void *ctxt[])
        num_macs = num_valid_macs(zvni);
        num_neigh = hashcount(zvni->neigh_table);
        if (json == NULL)
-               vty_out(vty, "%-10u %-21s %-15s %-8u %-8u %-15u\n", zvni->vni,
+               vty_out(vty,
+                       "%-10u %-4s %-21s %-8u %-8u %-15u %-37s\n",
+                       zvni->vni, "L2",
                        zvni->vxlan_if ? zvni->vxlan_if->name : "unknown",
-                       inet_ntoa(zvni->local_vtep_ip), num_macs, num_neigh,
-                       num_vteps);
+                       num_macs, num_neigh, num_vteps,
+                       vrf_id_to_name(zvni->vrf_id));
        else {
                char vni_str[VNI_STR_LEN];
                snprintf(vni_str, VNI_STR_LEN, "%u", zvni->vni);
                json_vni = json_object_new_object();
+               json_object_int_add(json_vni, "vni", zvni->vni);
+               json_object_string_add(json_vni, "type", "L2");
                json_object_string_add(json_vni, "vxlanIf",
                                       zvni->vxlan_if ? zvni->vxlan_if->name
                                                      : "unknown");
-               json_object_string_add(json_vni, "vtepIp",
-                                      inet_ntoa(zvni->local_vtep_ip));
                json_object_int_add(json_vni, "numMacs", num_macs);
                json_object_int_add(json_vni, "numArpNd", num_neigh);
                json_object_int_add(json_vni, "numRemoteVteps", num_vteps);
+               json_object_string_add(json_vni, "tenantVrf",
+                                      vrf_id_to_name(zvni->vrf_id));
                if (num_vteps) {
                        json_vtep_list = json_object_new_array();
                        for (zvtep = zvni->vteps; zvtep; zvtep = zvtep->next) {
@@ -753,11 +1167,11 @@ static int zvni_macip_send_msg_to_client(vni_t vni,
                                         struct ipaddr *ip, u_char flags,
                                         u_int16_t cmd)
 {
-       struct zserv *client;
-       struct stream *s;
-       int ipa_len;
        char buf[ETHER_ADDR_STRLEN];
        char buf2[INET6_ADDRSTRLEN];
+       int ipa_len;
+       struct zserv *client = NULL;
+       struct stream *s = NULL;
 
        client = zebra_find_client(ZEBRA_ROUTE_BGP, 0);
        /* BGP may not be running. */
@@ -767,7 +1181,7 @@ static int zvni_macip_send_msg_to_client(vni_t vni,
        s = client->obuf;
        stream_reset(s);
 
-       zserv_create_header(s, cmd, VRF_DEFAULT);
+       zclient_create_header(s, cmd, VRF_DEFAULT);
        stream_putl(s, vni);
        stream_put(s, macaddr->octet, ETH_ALEN);
        if (ip) {
@@ -785,12 +1199,13 @@ static int zvni_macip_send_msg_to_client(vni_t vni,
 
        stream_putc(s, flags); /* sticky mac/gateway mac */
 
+
        /* Write packet size. */
        stream_putw_at(s, 0, stream_get_endp(s));
 
        if (IS_ZEBRA_DEBUG_VXLAN)
                zlog_debug(
-                       "Send MACIP %s flags 0x%x MAC %s IP %s VNI %u to %s",
+                       "Send MACIP %s flags 0x%x MAC %s IP %s L2-VNI %u to %s",
                        (cmd == ZEBRA_MACIP_ADD) ? "Add" : "Del",
                        flags, prefix_mac2str(macaddr, buf, sizeof(buf)),
                        ipaddr2str(ip, buf2, sizeof(buf2)), vni,
@@ -1000,7 +1415,7 @@ static void zvni_process_neigh_on_local_mac_add(zebra_vni_t *zvni,
                        if (IS_ZEBRA_NEIGH_INACTIVE(n)) {
                                if (IS_ZEBRA_DEBUG_VXLAN)
                                        zlog_debug(
-                                               "neigh %s (MAC %s) on VNI %u is now ACTIVE",
+                                               "neigh %s (MAC %s) on L2-VNI %u is now ACTIVE",
                                                ipaddr2str(&n->ip, buf2,
                                                           sizeof(buf2)),
                                                prefix_mac2str(&n->emac, buf,
@@ -1009,7 +1424,7 @@ static void zvni_process_neigh_on_local_mac_add(zebra_vni_t *zvni,
 
                                ZEBRA_NEIGH_SET_ACTIVE(n);
                                zvni_neigh_send_add_to_client(
-                                       zvni->vni, &n->ip, &n->emac, 0);
+                                       zvni->vni, &n->ip, &n->emac, n->flags);
                        } else {
                                if (IS_ZEBRA_DEBUG_VXLAN)
                                        zlog_debug(
@@ -1040,7 +1455,7 @@ static void zvni_process_neigh_on_local_mac_del(zebra_vni_t *zvni,
                        if (IS_ZEBRA_NEIGH_ACTIVE(n)) {
                                if (IS_ZEBRA_DEBUG_VXLAN)
                                        zlog_debug(
-                                               "neigh %s (MAC %s) on VNI %u is now INACTIVE",
+                                               "neigh %s (MAC %s) on L2-VNI %u is now INACTIVE",
                                                ipaddr2str(&n->ip, buf2,
                                                           sizeof(buf2)),
                                                prefix_mac2str(&n->emac, buf,
@@ -1077,7 +1492,7 @@ static void zvni_process_neigh_on_remote_mac_add(zebra_vni_t *zvni,
                        if (IS_ZEBRA_NEIGH_ACTIVE(n)) {
                                if (IS_ZEBRA_DEBUG_VXLAN)
                                        zlog_debug(
-                                               "neigh %s (MAC %s) on VNI %u INACTIVE",
+                                               "neigh %s (MAC %s) on L2-VNI %u is now INACTIVE",
                                                ipaddr2str(&n->ip, buf2,
                                                           sizeof(buf2)),
                                                prefix_mac2str(&n->emac, buf,
@@ -1119,8 +1534,14 @@ static void zvni_process_neigh_on_remote_mac_del(zebra_vni_t *zvni,
  */
 static int zvni_neigh_send_add_to_client(vni_t vni,
                                         struct ipaddr *ip,
-                                        struct ethaddr *macaddr, u_char flags)
+                                        struct ethaddr *macaddr,
+                                        u_char neigh_flags)
 {
+       u_char                  flags = 0;
+
+       if (CHECK_FLAG(neigh_flags, ZEBRA_NEIGH_DEF_GW))
+               SET_FLAG(flags, ZEBRA_MACIP_TYPE_GW);
+
        return zvni_macip_send_msg_to_client(vni, macaddr, ip, flags,
                                             ZEBRA_MACIP_ADD);
 }
@@ -1292,7 +1713,37 @@ static int zvni_add_macip_for_intf(struct interface *ifp, zebra_vni_t *zvni)
 
                zvni_gw_macip_add(ifp, zvni, &macaddr, &ip);
        }
+       return 0;
+}
 
+
+static int zvni_advertise_subnet(zebra_vni_t *zvni,
+                                struct interface *ifp,
+                                int advertise)
+{
+       struct listnode *cnode = NULL, *cnnode = NULL;
+       struct connected *c = NULL;
+       struct ethaddr macaddr;
+
+       memcpy(&macaddr.octet, ifp->hw_addr, ETH_ALEN);
+
+       for (ALL_LIST_ELEMENTS(ifp->connected, cnode, cnnode, c)) {
+               struct prefix p;
+
+               memcpy(&p, c->address, sizeof(struct prefix));
+
+               /* skip link local address */
+               if (IN6_IS_ADDR_LINKLOCAL(&p.u.prefix6))
+                       continue;
+
+               apply_mask(&p);
+               if (advertise)
+                       ip_prefix_send_to_client(ifp->vrf_id, &p,
+                                                    ZEBRA_IP_PREFIX_ROUTE_ADD);
+               else
+                       ip_prefix_send_to_client(ifp->vrf_id, &p,
+                                                ZEBRA_IP_PREFIX_ROUTE_DEL);
+       }
        return 0;
 }
 
@@ -1302,12 +1753,12 @@ static int zvni_add_macip_for_intf(struct interface *ifp, zebra_vni_t *zvni)
 static int zvni_gw_macip_add(struct interface *ifp, zebra_vni_t *zvni,
                             struct ethaddr *macaddr, struct ipaddr *ip)
 {
-       struct zebra_if *zif = NULL;
-       struct zebra_l2info_vxlan *vxl = NULL;
-       zebra_neigh_t *n = NULL;
-       zebra_mac_t *mac = NULL;
        char buf[ETHER_ADDR_STRLEN];
        char buf2[INET6_ADDRSTRLEN];
+       zebra_neigh_t *n = NULL;
+       zebra_mac_t *mac = NULL;
+       struct zebra_if *zif = NULL;
+       struct zebra_l2info_vxlan *vxl = NULL;
 
        zif = zvni->vxlan_if->info;
        if (!zif)
@@ -1329,6 +1780,7 @@ static int zvni_gw_macip_add(struct interface *ifp, zebra_vni_t *zvni,
        /* Set "local" forwarding info. */
        SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL);
        SET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
+       SET_FLAG(mac->flags, ZEBRA_MAC_DEF_GW);
        memset(&mac->fwd_info, 0, sizeof(mac->fwd_info));
        mac->fwd_info.local.ifindex = ifp->ifindex;
        mac->fwd_info.local.vid = vxl->access_vlan;
@@ -1348,18 +1800,23 @@ static int zvni_gw_macip_add(struct interface *ifp, zebra_vni_t *zvni,
 
        /* Set "local" forwarding info. */
        SET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL);
+       SET_FLAG(n->flags, ZEBRA_NEIGH_DEF_GW);
        memcpy(&n->emac, macaddr, ETH_ALEN);
        n->ifindex = ifp->ifindex;
 
+       /* Only advertise in BGP if the knob is enabled */
+       if (!advertise_gw_macip_enabled(zvni))
+               return 0;
+
        if (IS_ZEBRA_DEBUG_VXLAN)
                zlog_debug(
-                       "SVI %s(%u) VNI %u, sending GW MAC %s IP %s add to BGP",
+                       "SVI %s(%u) L2-VNI %u, sending GW MAC %s IP %s add to BGP",
                        ifp->name, ifp->ifindex, zvni->vni,
                        prefix_mac2str(macaddr, buf, sizeof(buf)),
                        ipaddr2str(ip, buf2, sizeof(buf2)));
 
        zvni_neigh_send_add_to_client(zvni->vni, ip, macaddr,
-                                     ZEBRA_MAC_TYPE_GW);
+                                     n->flags);
 
        return 0;
 }
@@ -1370,10 +1827,10 @@ static int zvni_gw_macip_add(struct interface *ifp, zebra_vni_t *zvni,
 static int zvni_gw_macip_del(struct interface *ifp, zebra_vni_t *zvni,
                             struct ipaddr *ip)
 {
-       zebra_neigh_t *n = NULL;
-       zebra_mac_t *mac = NULL;
        char buf1[ETHER_ADDR_STRLEN];
        char buf2[INET6_ADDRSTRLEN];
+       zebra_neigh_t *n = NULL;
+       zebra_mac_t *mac = NULL;
 
        /* If the neigh entry is not present nothing to do*/
        n = zvni_neigh_lookup(zvni, ip);
@@ -1393,16 +1850,21 @@ static int zvni_gw_macip_del(struct interface *ifp, zebra_vni_t *zvni,
        if (!CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL))
                return -1;
 
-       if (IS_ZEBRA_DEBUG_VXLAN)
-               zlog_debug(
-                       "SVI %s(%u) VNI %u, sending GW MAC %s IP %s del to BGP",
-                       ifp->name, ifp->ifindex, zvni->vni,
-                       prefix_mac2str(&(n->emac), buf1, sizeof(buf1)),
-                       ipaddr2str(ip, buf2, sizeof(buf2)));
-
-       /* Remove neighbor from BGP. */
-       zvni_neigh_send_del_to_client(zvni->vni, &n->ip, &n->emac,
-                                     ZEBRA_MAC_TYPE_GW);
+       /* only need to delete the entry from bgp if we sent it before */
+       if (advertise_gw_macip_enabled(zvni)) {
+               if (IS_ZEBRA_DEBUG_VXLAN)
+                       zlog_debug("%u:SVI %s(%u) VNI %u, sending GW MAC %s IP %s del to BGP",
+                                  ifp->vrf_id, ifp->name,
+                                  ifp->ifindex, zvni->vni,
+                                  prefix_mac2str(&(n->emac),
+                                                 NULL,
+                                                 ETHER_ADDR_STRLEN),
+                                  ipaddr2str(ip, buf2, sizeof(buf2)));
+
+               /* Remove neighbor from BGP. */
+               zvni_neigh_send_del_to_client(zvni->vni, &n->ip, &n->emac,
+                                             ZEBRA_MACIP_TYPE_GW);
+       }
 
        /* Delete this neighbor entry. */
        zvni_neigh_del(zvni, n);
@@ -1469,9 +1931,6 @@ static void zvni_gw_macip_add_for_vni_hash(struct hash_backet *backet,
        if (!zvni)
                return;
 
-       if (!advertise_gw_macip_enabled(zvni))
-               return;
-
        ifp = zvni->vxlan_if;
        if (!ifp)
                return;
@@ -1585,7 +2044,6 @@ static int zvni_mac_del_hash_entry(struct hash_backet *backet, void *arg)
 {
        struct mac_walk_ctx *wctx = arg;
        zebra_mac_t *mac = backet->data;
-       u_char sticky = 0;
 
        if (((wctx->flags & DEL_LOCAL_MAC) && (mac->flags & ZEBRA_MAC_LOCAL))
            || ((wctx->flags & DEL_REMOTE_MAC)
@@ -1595,11 +2053,9 @@ static int zvni_mac_del_hash_entry(struct hash_backet *backet, void *arg)
                && IPV4_ADDR_SAME(&mac->fwd_info.r_vtep_ip,
                                  &wctx->r_vtep_ip))) {
                if (wctx->upd_client && (mac->flags & ZEBRA_MAC_LOCAL)) {
-                       sticky = CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY) ? 1
-                                                                         : 0;
                        zvni_mac_send_del_to_client(
                                wctx->zvni->vni, &mac->macaddr,
-                               (sticky ? ZEBRA_MAC_TYPE_STICKY : 0));
+                               mac->flags);
                }
 
                if (wctx->uninstall)
@@ -1674,8 +2130,16 @@ static zebra_mac_t *zvni_mac_lookup(zebra_vni_t *zvni, struct ethaddr *mac)
  * Inform BGP about local MAC addition.
  */
 static int zvni_mac_send_add_to_client(vni_t vni,
-                                      struct ethaddr *macaddr, u_char flags)
+                                      struct ethaddr *macaddr,
+                                      u_char mac_flags)
 {
+       u_char  flags = 0;
+
+       if (CHECK_FLAG(mac_flags, ZEBRA_MAC_STICKY))
+               SET_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY);
+       if (CHECK_FLAG(mac_flags, ZEBRA_MAC_DEF_GW))
+               SET_FLAG(flags, ZEBRA_MACIP_TYPE_GW);
+
        return zvni_macip_send_msg_to_client(vni, macaddr, NULL, flags,
                                             ZEBRA_MACIP_ADD);
 }
@@ -1684,8 +2148,16 @@ static int zvni_mac_send_add_to_client(vni_t vni,
  * Inform BGP about local MAC deletion.
  */
 static int zvni_mac_send_del_to_client(vni_t vni,
-                                      struct ethaddr *macaddr, u_char flags)
+                                      struct ethaddr *macaddr,
+                                      u_char mac_flags)
 {
+       u_char  flags = 0;
+
+       if (CHECK_FLAG(mac_flags, ZEBRA_MAC_STICKY))
+               SET_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY);
+       if (CHECK_FLAG(mac_flags, ZEBRA_MAC_DEF_GW))
+               SET_FLAG(flags, ZEBRA_MACIP_TYPE_GW);
+
        return zvni_macip_send_msg_to_client(vni, macaddr, NULL, flags,
                                             ZEBRA_MACIP_DEL);
 }
@@ -1747,7 +2219,8 @@ static zebra_vni_t *zvni_map_vlan(struct interface *ifp,
  * Map SVI and associated bridge to a VNI. This is invoked upon getting
  * neighbor notifications, to see if they are of interest.
  */
-static zebra_vni_t *zvni_map_svi(struct interface *ifp, struct interface *br_if)
+static zebra_vni_t *zvni_from_svi(struct interface *ifp,
+                                 struct interface *br_if)
 {
        struct zebra_ns *zns;
        struct route_node *rn;
@@ -1992,15 +2465,13 @@ static void zvni_read_mac_neigh(zebra_vni_t *zvni,
        vlan_if = zvni_map_to_svi(vxl->access_vlan, zif->brslave_info.br_if);
        if (vlan_if) {
 
-               if (advertise_gw_macip_enabled(zvni)) {
-                       /* Add SVI MAC-IP */
-                       zvni_add_macip_for_intf(vlan_if, zvni);
+               /* Add SVI MAC-IP */
+               zvni_add_macip_for_intf(vlan_if, zvni);
 
-                       /* Add VRR MAC-IP - if any*/
-                       vrr_if = zebra_get_vrr_intf_for_svi(vlan_if);
-                       if (vrr_if)
-                               zvni_add_macip_for_intf(vrr_if, zvni);
-               }
+               /* Add VRR MAC-IP - if any*/
+               vrr_if = zebra_get_vrr_intf_for_svi(vlan_if);
+               if (vrr_if)
+                       zvni_add_macip_for_intf(vrr_if, zvni);
 
                neigh_read_for_vlan(zns, vlan_if);
        }
@@ -2130,16 +2601,18 @@ static int zvni_send_add_to_client(zebra_vni_t *zvni)
        s = client->obuf;
        stream_reset(s);
 
-       zserv_create_header(s, ZEBRA_VNI_ADD, VRF_DEFAULT);
+       zclient_create_header(s, ZEBRA_VNI_ADD, VRF_DEFAULT);
        stream_putl(s, zvni->vni);
        stream_put_in_addr(s, &zvni->local_vtep_ip);
+       stream_put(s, &zvni->vrf_id, sizeof(vrf_id_t)); /* tenant vrf */
 
        /* Write packet size. */
        stream_putw_at(s, 0, stream_get_endp(s));
 
        if (IS_ZEBRA_DEBUG_VXLAN)
-               zlog_debug("Send VNI_ADD %u %s to %s",
+               zlog_debug("Send VNI_ADD %u %s tenant vrf %s to %s",
                           zvni->vni, inet_ntoa(zvni->local_vtep_ip),
+                          vrf_id_to_name(zvni->vrf_id),
                           zebra_route_string(client->proto));
 
        client->vniadd_cnt++;
@@ -2162,7 +2635,7 @@ static int zvni_send_del_to_client(vni_t vni)
        s = client->obuf;
        stream_reset(s);
 
-       zserv_create_header(s, ZEBRA_VNI_DEL, VRF_DEFAULT);
+       zclient_create_header(s, ZEBRA_VNI_DEL, VRF_DEFAULT);
        stream_putl(s, vni);
 
        /* Write packet size. */
@@ -2189,10 +2662,11 @@ static void zvni_build_hash_table()
        /* Walk VxLAN interfaces and create VNI hash. */
        zns = zebra_ns_lookup(NS_DEFAULT);
        for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) {
+               vni_t vni;
+               zebra_vni_t *zvni = NULL;
+               zebra_l3vni_t *zl3vni = NULL;
                struct zebra_if *zif;
                struct zebra_l2info_vxlan *vxl;
-               zebra_vni_t *zvni;
-               vni_t vni;
 
                ifp = (struct interface *)rn->info;
                if (!ifp)
@@ -2200,39 +2674,74 @@ static void zvni_build_hash_table()
                zif = ifp->info;
                if (!zif || zif->zif_type != ZEBRA_IF_VXLAN)
                        continue;
-               vxl = &zif->l2info.vxl;
 
+               vxl = &zif->l2info.vxl;
                vni = vxl->vni;
 
-               if (IS_ZEBRA_DEBUG_VXLAN)
-                       zlog_debug(
-                               "Create VNI hash for intf %s(%u) VNI %u local IP %s",
-                               ifp->name, ifp->ifindex, vni,
-                               inet_ntoa(vxl->vtep_ip));
+               /* L3-VNI and L2-VNI are handled seperately */
+               zl3vni = zl3vni_lookup(vni);
+               if (zl3vni) {
 
-               /* VNI hash entry is not expected to exist. */
-               zvni = zvni_lookup(vni);
-               if (zvni) {
-                       zlog_err(
-                               "VNI hash already present for IF %s(%u) VNI %u",
-                               ifp->name, ifp->ifindex, vni);
-                       continue;
-               }
+                       if (IS_ZEBRA_DEBUG_VXLAN)
+                               zlog_debug("create L3-VNI hash for Intf %s(%u) L3-VNI %u",
+                                          ifp->name, ifp->ifindex, vni);
 
-               zvni = zvni_add(vni);
-               if (!zvni) {
-                       zlog_err(
-                               "Failed to add VNI hash, IF %s(%u) VNI %u",
-                               ifp->name, ifp->ifindex, vni);
-                       return;
-               }
+                       /* associate with vxlan_if */
+                       zl3vni->local_vtep_ip = vxl->vtep_ip;
+                       zl3vni->vxlan_if = ifp;
 
-               zvni->local_vtep_ip = vxl->vtep_ip;
-               zvni->vxlan_if = ifp;
+                       /*
+                        * we need to associate with SVI.
+                        * we can associate with svi-if only after association
+                        * with vxlan-intf is complete
+                        */
+                       zl3vni->svi_if = zl3vni_map_to_svi_if(zl3vni);
 
-               /* Inform BGP if interface is up and mapped to bridge. */
-               if (if_is_operative(ifp) && zif->brslave_info.br_if)
-                       zvni_send_add_to_client(zvni);
+                       if (is_l3vni_oper_up(zl3vni))
+                               zebra_vxlan_process_l3vni_oper_up(zl3vni);
+
+               } else {
+                       struct interface *vlan_if = NULL;
+
+                       if (IS_ZEBRA_DEBUG_VXLAN)
+                               zlog_debug(
+                                       "Create L2-VNI hash for intf %s(%u) L2-VNI %u local IP %s",
+                                       ifp->name, ifp->ifindex, vni,
+                                       inet_ntoa(vxl->vtep_ip));
+
+                       /* VNI hash entry is not expected to exist. */
+                       zvni = zvni_lookup(vni);
+                       if (zvni) {
+                               zlog_err(
+                                       "VNI hash already present for IF %s(%u) L2-VNI %u",
+                                       ifp->name, ifp->ifindex, vni);
+                               continue;
+                       }
+
+                       zvni = zvni_add(vni);
+                       if (!zvni) {
+                               zlog_err(
+                                       "Failed to add VNI hash, IF %s(%u) L2-VNI %u",
+                                       ifp->name, ifp->ifindex, vni);
+                               return;
+                       }
+
+                       zvni->local_vtep_ip = vxl->vtep_ip;
+                       zvni->vxlan_if = ifp;
+                       vlan_if = zvni_map_to_svi(vxl->access_vlan,
+                                                 zif->brslave_info.br_if);
+                       if (vlan_if) {
+                               zvni->vrf_id = vlan_if->vrf_id;
+                               zl3vni = zl3vni_from_vrf(vlan_if->vrf_id);
+                               if (zl3vni)
+                                       listnode_add_sort(zl3vni->l2vnis, zvni);
+                       }
+
+
+                       /* Inform BGP if intf is up and mapped to bridge. */
+                       if (if_is_operative(ifp) && zif->brslave_info.br_if)
+                               zvni_send_add_to_client(zvni);
+               }
        }
 }
 
@@ -2349,27 +2858,1356 @@ static int zvni_vtep_uninstall(zebra_vni_t *zvni, struct in_addr *vtep_ip)
 /*
  * Cleanup VNI/VTEP and update kernel
  */
-static void zvni_cleanup_all(struct hash_backet *backet, void *zvrf)
+static void zvni_cleanup_all(struct hash_backet *backet, void *arg)
 {
-       zebra_vni_t *zvni;
+       zebra_vni_t *zvni = NULL;
+       zebra_l3vni_t *zl3vni = NULL;
+       struct zebra_vrf *zvrf = (struct zebra_vrf *)arg;
 
        zvni = (zebra_vni_t *)backet->data;
        if (!zvni)
                return;
 
+       /* remove from l3-vni list */
+       if (zvrf->l3vni)
+               zl3vni = zl3vni_lookup(zvrf->l3vni);
+       if (zl3vni)
+               listnode_delete(zl3vni->l2vnis, zvni);
+
        /* Free up all neighbors and MACs, if any. */
        zvni_neigh_del_all(zvni, 1, 0, DEL_ALL_NEIGH);
        zvni_mac_del_all(zvni, 1, 0, DEL_ALL_MAC);
 
-       /* Free up all remote VTEPs, if any. */
-       zvni_vtep_del_all(zvni, 1);
+       /* Free up all remote VTEPs, if any. */
+       zvni_vtep_del_all(zvni, 1);
+
+       /* Delete the hash entry. */
+       zvni_del(zvni);
+}
+
+/* cleanup L3VNI */
+static void zl3vni_cleanup_all(struct hash_backet *backet,
+                              void *args)
+{
+       zebra_l3vni_t *zl3vni = NULL;
+
+       zl3vni = (zebra_l3vni_t *)backet->data;
+       if (!zl3vni)
+               return;
+
+       zebra_vxlan_process_l3vni_oper_down(zl3vni);
+}
+
+static int is_host_present_in_host_list(struct list *list,
+                                       struct prefix *host)
+{
+       struct listnode *node = NULL;
+       struct prefix *p = NULL;
+
+       for (ALL_LIST_ELEMENTS_RO(list, node, p)) {
+               if (prefix_same(p, host))
+                       return 1;
+       }
+       return 0;
+}
+
+static void host_list_add_host(struct list *list,
+                              struct prefix *host)
+{
+       struct prefix *p = NULL;
+
+       p = XCALLOC(MTYPE_HOST_PREFIX, sizeof(struct prefix));
+       memcpy(p, host, sizeof(struct prefix));
+
+       listnode_add_sort(list, p);
+}
+
+static void host_list_delete_host(struct list *list,
+                                 struct prefix *host)
+{
+       struct listnode *node = NULL, *nnode = NULL, *node_to_del = NULL;
+       struct prefix *p = NULL;
+
+       for (ALL_LIST_ELEMENTS(list, node, nnode, p)) {
+               if (prefix_same(p, host)) {
+                       XFREE(MTYPE_HOST_PREFIX, p);
+                       node_to_del = node;
+               }
+       }
+
+       if (node_to_del)
+               list_delete_node(list, node_to_del);
+}
+
+/*
+ * Look up MAC hash entry.
+ */
+static zebra_mac_t *zl3vni_rmac_lookup(zebra_l3vni_t *zl3vni,
+                                      struct ethaddr *rmac)
+{
+       zebra_mac_t tmp;
+       zebra_mac_t *pmac;
+
+       memset(&tmp, 0, sizeof(tmp));
+       memcpy(&tmp.macaddr, rmac, ETH_ALEN);
+       pmac = hash_lookup(zl3vni->rmac_table, &tmp);
+
+       return pmac;
+}
+
+/*
+ * Callback to allocate RMAC hash entry.
+ */
+static void *zl3vni_rmac_alloc(void *p)
+{
+       const zebra_mac_t *tmp_rmac = p;
+       zebra_mac_t *zrmac;
+
+       zrmac = XCALLOC(MTYPE_MAC, sizeof(zebra_mac_t));
+       *zrmac = *tmp_rmac;
+
+       return ((void *)zrmac);
+}
+
+/*
+ * Add RMAC entry to l3-vni
+ */
+static zebra_mac_t *zl3vni_rmac_add(zebra_l3vni_t *zl3vni,
+                                   struct ethaddr *rmac)
+{
+       zebra_mac_t tmp_rmac;
+       zebra_mac_t *zrmac = NULL;
+
+       memset(&tmp_rmac, 0, sizeof(zebra_mac_t));
+       memcpy(&tmp_rmac.macaddr, rmac, ETH_ALEN);
+       zrmac = hash_get(zl3vni->rmac_table, &tmp_rmac, zl3vni_rmac_alloc);
+       assert(zrmac);
+
+       zrmac->host_list = list_new();
+       zrmac->host_list->cmp = (int (*)(void *, void *))prefix_cmp;
+
+       SET_FLAG(zrmac->flags, ZEBRA_MAC_REMOTE);
+       SET_FLAG(zrmac->flags, ZEBRA_MAC_REMOTE_RMAC);
+
+       return zrmac;
+}
+
+/*
+ * Delete MAC entry.
+ */
+static int zl3vni_rmac_del(zebra_l3vni_t *zl3vni,
+                          zebra_mac_t *zrmac)
+{
+       zebra_mac_t *tmp_rmac;
+
+       if (zrmac->host_list)
+               list_delete_and_null(&zrmac->host_list);
+       zrmac->host_list = NULL;
+
+       tmp_rmac = hash_release(zl3vni->rmac_table, zrmac);
+       if (tmp_rmac)
+               XFREE(MTYPE_MAC, tmp_rmac);
+
+       return 0;
+}
+
+/*
+ * Install remote RMAC into the kernel.
+ */
+static int zl3vni_rmac_install(zebra_l3vni_t *zl3vni,
+                              zebra_mac_t *zrmac)
+{
+       struct zebra_if *zif = NULL;
+       struct zebra_l2info_vxlan *vxl = NULL;
+
+       if (!(CHECK_FLAG(zrmac->flags, ZEBRA_MAC_REMOTE)) ||
+           !(CHECK_FLAG(zrmac->flags, ZEBRA_MAC_REMOTE_RMAC)))
+               return 0;
+
+       zif = zl3vni->vxlan_if->info;
+       if (!zif)
+               return -1;
+
+       vxl = &zif->l2info.vxl;
+
+       return kernel_add_mac(zl3vni->vxlan_if, vxl->access_vlan,
+                             &zrmac->macaddr,
+                             zrmac->fwd_info.r_vtep_ip, 0);
+}
+
+/*
+ * Uninstall remote RMAC from the kernel.
+ */
+static int zl3vni_rmac_uninstall(zebra_l3vni_t *zl3vni,
+                                zebra_mac_t *zrmac)
+{
+       char buf[ETHER_ADDR_STRLEN];
+       struct zebra_if *zif = NULL;
+       struct zebra_l2info_vxlan *vxl = NULL;
+
+       if (!(CHECK_FLAG(zrmac->flags, ZEBRA_MAC_REMOTE)) ||
+           !(CHECK_FLAG(zrmac->flags, ZEBRA_MAC_REMOTE_RMAC)))
+               return 0;
+
+       if (!zl3vni->vxlan_if) {
+               zlog_err(
+                        "RMAC %s on L3-VNI %u hash %p couldn't be uninstalled - no vxlan_if",
+                        prefix_mac2str(&zrmac->macaddr, buf, sizeof(buf)),
+                        zl3vni->vni, zl3vni);
+               return -1;
+       }
+
+       zif = zl3vni->vxlan_if->info;
+       if (!zif)
+               return -1;
+
+       vxl = &zif->l2info.vxl;
+
+       return kernel_del_mac(zl3vni->vxlan_if, vxl->access_vlan,
+                             &zrmac->macaddr, zrmac->fwd_info.r_vtep_ip, 0);
+}
+
+/* handle rmac add */
+static int zl3vni_remote_rmac_add(zebra_l3vni_t *zl3vni,
+                                 struct ethaddr *rmac,
+                                 struct ipaddr *vtep_ip,
+                                 struct prefix *host_prefix)
+{
+       char buf[ETHER_ADDR_STRLEN];
+       char buf1[INET6_ADDRSTRLEN];
+       zebra_mac_t *zrmac = NULL;
+
+       zrmac = zl3vni_rmac_lookup(zl3vni, rmac);
+       if (!zrmac) {
+
+               zrmac = zl3vni_rmac_add(zl3vni, rmac);
+               if (!zrmac) {
+                       zlog_warn(
+                               "Failed to add RMAC %s L3VNI %u Remote VTEP %s",
+                               prefix_mac2str(rmac, buf,
+                                              sizeof(buf)),
+                               zl3vni->vni, ipaddr2str(vtep_ip, buf1,
+                                                       sizeof(buf1)));
+                       return -1;
+               }
+               memset(&zrmac->fwd_info, 0, sizeof(zrmac->fwd_info));
+               zrmac->fwd_info.r_vtep_ip = vtep_ip->ipaddr_v4;
+
+               /* install rmac in kernel */
+               zl3vni_rmac_install(zl3vni, zrmac);
+       }
+
+       if (!is_host_present_in_host_list(zrmac->host_list, host_prefix))
+               host_list_add_host(zrmac->host_list, host_prefix);
+       return 0;
+}
+
+
+/* handle rmac delete */
+static int zl3vni_remote_rmac_del(zebra_l3vni_t *zl3vni,
+                                 struct ethaddr *rmac,
+                                 struct prefix *host_prefix)
+{
+       zebra_mac_t *zrmac = NULL;
+
+       zrmac = zl3vni_rmac_lookup(zl3vni, rmac);
+       if (!zrmac)
+               return -1;
+
+       host_list_delete_host(zrmac->host_list, host_prefix);
+       if (list_isempty(zrmac->host_list)) {
+
+               /* uninstall from kernel */
+               zl3vni_rmac_uninstall(zl3vni, zrmac);
+
+               /* del the rmac entry */
+               zl3vni_rmac_del(zl3vni, zrmac);
+       }
+       return 0;
+}
+
+/*
+ * Look up nh hash entry on a l3-vni.
+ */
+static zebra_neigh_t *zl3vni_nh_lookup(zebra_l3vni_t *zl3vni,
+                                      struct ipaddr *ip)
+{
+       zebra_neigh_t tmp;
+       zebra_neigh_t *n;
+
+       memset(&tmp, 0, sizeof(tmp));
+       memcpy(&tmp.ip, ip, sizeof(struct ipaddr));
+       n = hash_lookup(zl3vni->nh_table, &tmp);
+
+       return n;
+}
+
+
+/*
+ * Callback to allocate NH hash entry on L3-VNI.
+ */
+static void *zl3vni_nh_alloc(void *p)
+{
+       const zebra_neigh_t *tmp_n = p;
+       zebra_neigh_t *n;
+
+       n = XCALLOC(MTYPE_NEIGH, sizeof(zebra_neigh_t));
+       *n = *tmp_n;
+
+       return ((void *)n);
+}
+
+/*
+ * Add neighbor entry.
+ */
+static zebra_neigh_t *zl3vni_nh_add(zebra_l3vni_t *zl3vni,
+                                   struct ipaddr *ip,
+                                   struct ethaddr *mac)
+{
+       zebra_neigh_t tmp_n;
+       zebra_neigh_t *n = NULL;
+
+       memset(&tmp_n, 0, sizeof(zebra_neigh_t));
+       memcpy(&tmp_n.ip, ip, sizeof(struct ipaddr));
+       n = hash_get(zl3vni->nh_table, &tmp_n, zl3vni_nh_alloc);
+       assert(n);
+
+       n->host_list = list_new();
+       n->host_list->cmp = (int (*)(void *, void *))prefix_cmp;
+
+       memcpy(&n->emac, mac, ETH_ALEN);
+       SET_FLAG(n->flags, ZEBRA_NEIGH_REMOTE);
+       SET_FLAG(n->flags, ZEBRA_NEIGH_REMOTE_NH);
+
+       return n;
+}
+
+/*
+ * Delete neighbor entry.
+ */
+static int zl3vni_nh_del(zebra_l3vni_t *zl3vni,
+                        zebra_neigh_t *n)
+{
+       zebra_neigh_t *tmp_n;
+
+       if (n->host_list)
+               list_delete_and_null(&n->host_list);
+       n->host_list = NULL;
+
+       tmp_n = hash_release(zl3vni->nh_table, n);
+       if (tmp_n)
+               XFREE(MTYPE_NEIGH, tmp_n);
+
+       return 0;
+}
+
+/*
+ * Install remote nh as neigh into the kernel.
+ */
+static int zl3vni_nh_install(zebra_l3vni_t *zl3vni,
+                            zebra_neigh_t *n)
+{
+       if (!is_l3vni_oper_up(zl3vni))
+               return -1;
+
+       if (!(n->flags & ZEBRA_NEIGH_REMOTE) ||
+           !(n->flags & ZEBRA_NEIGH_REMOTE_NH))
+               return 0;
+
+       return kernel_add_neigh(zl3vni->svi_if, &n->ip, &n->emac);
+}
+
+/*
+ * Uninstall remote nh from the kernel.
+ */
+static int zl3vni_nh_uninstall(zebra_l3vni_t *zl3vni,
+                              zebra_neigh_t *n)
+{
+       if (!(n->flags & ZEBRA_NEIGH_REMOTE) ||
+           !(n->flags & ZEBRA_NEIGH_REMOTE_NH))
+               return 0;
+
+       if (!zl3vni->svi_if || !if_is_operative(zl3vni->svi_if))
+               return 0;
+
+       return kernel_del_neigh(zl3vni->svi_if, &n->ip);
+}
+
+/* add remote vtep as a neigh entry */
+static int zl3vni_remote_nh_add(zebra_l3vni_t *zl3vni,
+                               struct ipaddr *vtep_ip,
+                               struct ethaddr *rmac,
+                               struct prefix *host_prefix)
+{
+       char buf[ETHER_ADDR_STRLEN];
+       char buf1[INET6_ADDRSTRLEN];
+       zebra_neigh_t *nh = NULL;
+
+       nh = zl3vni_nh_lookup(zl3vni, vtep_ip);
+       if (!nh) {
+               nh = zl3vni_nh_add(zl3vni, vtep_ip, rmac);
+               if (!nh) {
+
+                       zlog_warn(
+                               "Failed to add NH as Neigh (IP %s MAC %s L3-VNI %u)",
+                               ipaddr2str(vtep_ip, buf1,
+                                          sizeof(buf1)),
+                               prefix_mac2str(rmac, buf,
+                                              sizeof(buf)),
+                               zl3vni->vni);
+                       return -1;
+               }
+
+               /* install the nh neigh in kernel */
+               zl3vni_nh_install(zl3vni, nh);
+       }
+
+       if (!is_host_present_in_host_list(nh->host_list, host_prefix))
+               host_list_add_host(nh->host_list, host_prefix);
+
+       return 0;
+}
+
+/* handle nh neigh delete */
+static int zl3vni_remote_nh_del(zebra_l3vni_t *zl3vni,
+                               struct ipaddr *vtep_ip,
+                               struct prefix *host_prefix)
+{
+       zebra_neigh_t *nh = NULL;
+
+       nh = zl3vni_nh_lookup(zl3vni, vtep_ip);
+       if (!nh)
+               return -1;
+
+       host_list_delete_host(nh->host_list, host_prefix);
+       if (list_isempty(nh->host_list)) {
+
+               /* uninstall from kernel */
+               zl3vni_nh_uninstall(zl3vni, nh);
+
+               /* delete the nh entry */
+               zl3vni_nh_del(zl3vni, nh);
+       }
+
+       return 0;
+}
+
+/* handle neigh update from kernel - the only thing of interest is to
+ * readd stale entries.
+ */
+static int zl3vni_local_nh_add_update(zebra_l3vni_t *zl3vni,
+                                     struct ipaddr *ip, u_int16_t state)
+{
+#ifdef GNU_LINUX
+       zebra_neigh_t *n = NULL;
+
+       n = zl3vni_nh_lookup(zl3vni, ip);
+       if (!n)
+               return 0;
+
+       /* all next hop neigh are remote and installed by frr.
+        * If the kernel has aged this entry, re-install.
+        */
+       if (state & NUD_STALE)
+               zl3vni_nh_install(zl3vni, n);
+#endif
+       return 0;
+}
+
+/* handle neigh delete from kernel */
+static int zl3vni_local_nh_del(zebra_l3vni_t *zl3vni,
+                              struct ipaddr *ip)
+{
+       zebra_neigh_t *n = NULL;
+
+       n = zl3vni_nh_lookup(zl3vni, ip);
+       if (!n)
+               return 0;
+
+       /* all next hop neigh are remote and installed by frr.
+        * If we get an age out notification for these neigh entries, we have to
+        * install it back
+        */
+       zl3vni_nh_install(zl3vni, n);
+
+       return 0;
+}
+
+/*
+ * Hash function for L3 VNI.
+ */
+static unsigned int l3vni_hash_keymake(void *p)
+{
+       const zebra_l3vni_t *zl3vni = p;
+
+       return jhash_1word(zl3vni->vni, 0);
+}
+
+/*
+ * Compare 2 L3 VNI hash entries.
+ */
+static int l3vni_hash_cmp(const void *p1, const void *p2)
+{
+       const zebra_l3vni_t *zl3vni1 = p1;
+       const zebra_l3vni_t *zl3vni2 = p2;
+
+       return (zl3vni1->vni == zl3vni2->vni);
+}
+
+/*
+ * Callback to allocate L3 VNI hash entry.
+ */
+static void *zl3vni_alloc(void *p)
+{
+       zebra_l3vni_t *zl3vni = NULL;
+       const zebra_l3vni_t *tmp_l3vni = p;
+
+       zl3vni = XCALLOC(MTYPE_ZL3VNI, sizeof(zebra_l3vni_t));
+       zl3vni->vni = tmp_l3vni->vni;
+       return ((void *)zl3vni);
+}
+
+/*
+ * Look up L3 VNI hash entry.
+ */
+static zebra_l3vni_t *zl3vni_lookup(vni_t vni)
+{
+       struct zebra_ns *zns;
+       zebra_l3vni_t tmp_l3vni;
+       zebra_l3vni_t *zl3vni = NULL;
+
+       zns = zebra_ns_lookup(NS_DEFAULT);
+       assert(zns);
+       memset(&tmp_l3vni, 0, sizeof(zebra_l3vni_t));
+       tmp_l3vni.vni = vni;
+       zl3vni = hash_lookup(zns->l3vni_table, &tmp_l3vni);
+
+       return zl3vni;
+}
+
+/*
+ * Add L3 VNI hash entry.
+ */
+static zebra_l3vni_t *zl3vni_add(vni_t vni, vrf_id_t vrf_id)
+{
+       zebra_l3vni_t tmp_zl3vni;
+       struct zebra_ns *zns = NULL;
+       zebra_l3vni_t *zl3vni = NULL;
+
+       zns = zebra_ns_lookup(NS_DEFAULT);
+       assert(zns);
+
+       memset(&tmp_zl3vni, 0, sizeof(zebra_l3vni_t));
+       tmp_zl3vni.vni = vni;
+
+       zl3vni = hash_get(zns->l3vni_table, &tmp_zl3vni, zl3vni_alloc);
+       assert(zl3vni);
+
+       zl3vni->vrf_id = vrf_id;
+       zl3vni->svi_if = NULL;
+       zl3vni->vxlan_if = NULL;
+       zl3vni->l2vnis = list_new();
+       zl3vni->l2vnis->cmp = (int (*)(void *, void *))vni_hash_cmp;
+
+       /* Create hash table for remote RMAC */
+       zl3vni->rmac_table =
+               hash_create(mac_hash_keymake, mac_cmp,
+                           "Zebra L3-VNI RMAC-Table");
+
+       /* Create hash table for neighbors */
+       zl3vni->nh_table = hash_create(neigh_hash_keymake, neigh_cmp,
+                                    "Zebra L3-VNI next-hop table");
+
+       return zl3vni;
+}
+
+/*
+ * Delete L3 VNI hash entry.
+ */
+static int zl3vni_del(zebra_l3vni_t *zl3vni)
+{
+       struct zebra_ns *zns;
+       zebra_l3vni_t *tmp_zl3vni;
+
+       zns = zebra_ns_lookup(NS_DEFAULT);
+       assert(zns);
+
+       /* free the list of l2vnis */
+       list_delete_and_null(&zl3vni->l2vnis);
+       zl3vni->l2vnis = NULL;
+
+       /* Free the rmac table */
+       hash_free(zl3vni->rmac_table);
+       zl3vni->rmac_table = NULL;
+
+       /* Free the nh table */
+       hash_free(zl3vni->nh_table);
+       zl3vni->nh_table = NULL;
+
+       /* Free the VNI hash entry and allocated memory. */
+       tmp_zl3vni = hash_release(zns->l3vni_table, zl3vni);
+       if (tmp_zl3vni)
+               XFREE(MTYPE_ZL3VNI, tmp_zl3vni);
+
+       return 0;
+}
+
+static struct interface *zl3vni_map_to_vxlan_if(zebra_l3vni_t *zl3vni)
+{
+       struct zebra_ns *zns = NULL;
+       struct route_node *rn = NULL;
+       struct interface *ifp = NULL;
+
+       /* loop through all vxlan-interface */
+       zns = zebra_ns_lookup(NS_DEFAULT);
+       for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) {
+
+               struct zebra_if *zif = NULL;
+               struct zebra_l2info_vxlan *vxl = NULL;
+
+               ifp = (struct interface *)rn->info;
+               if (!ifp)
+                       continue;
+
+               zif = ifp->info;
+               if (!zif || zif->zif_type != ZEBRA_IF_VXLAN)
+                       continue;
+
+               vxl = &zif->l2info.vxl;
+               if (vxl->vni == zl3vni->vni) {
+                       zl3vni->local_vtep_ip = vxl->vtep_ip;
+                       return ifp;
+               }
+       }
+
+       return NULL;
+}
+
+static struct interface *zl3vni_map_to_svi_if(zebra_l3vni_t *zl3vni)
+{
+       struct zebra_if *zif = NULL; /* zebra_if for vxlan_if */
+       struct zebra_l2info_vxlan *vxl = NULL; /* l2 info for vxlan_if */
+
+       if (!zl3vni)
+               return NULL;
+
+       if (!zl3vni->vxlan_if)
+               return NULL;
+
+       zif = zl3vni->vxlan_if->info;
+       if (!zif)
+               return NULL;
+
+       vxl = &zif->l2info.vxl;
+
+       return zvni_map_to_svi(vxl->access_vlan, zif->brslave_info.br_if);
+}
+
+static zebra_l3vni_t *zl3vni_from_vrf(vrf_id_t vrf_id)
+{
+       struct zebra_vrf *zvrf = NULL;
+
+       zvrf = zebra_vrf_lookup_by_id(vrf_id);
+       if (!zvrf)
+               return NULL;
+
+       return zl3vni_lookup(zvrf->l3vni);
+}
+
+/*
+ * Map SVI and associated bridge to a VNI. This is invoked upon getting
+ * neighbor notifications, to see if they are of interest.
+ */
+static zebra_l3vni_t *zl3vni_from_svi(struct interface *ifp,
+                                     struct interface *br_if)
+{
+       int found = 0;
+       vlanid_t vid = 0;
+       u_char bridge_vlan_aware = 0;
+       zebra_l3vni_t *zl3vni = NULL;
+       struct zebra_ns *zns = NULL;
+       struct route_node *rn = NULL;
+       struct zebra_if *zif = NULL;
+       struct interface *tmp_if = NULL;
+       struct zebra_l2info_bridge *br = NULL;
+       struct zebra_l2info_vxlan *vxl = NULL;
+
+       if (!br_if)
+               return NULL;
+
+       /* Make sure the linked interface is a bridge. */
+       if (!IS_ZEBRA_IF_BRIDGE(br_if))
+               return NULL;
+
+       /* Determine if bridge is VLAN-aware or not */
+       zif = br_if->info;
+       assert(zif);
+       br = &zif->l2info.br;
+       bridge_vlan_aware = br->vlan_aware;
+       if (bridge_vlan_aware) {
+               struct zebra_l2info_vlan *vl;
+
+               if (!IS_ZEBRA_IF_VLAN(ifp))
+                       return NULL;
+
+               zif = ifp->info;
+               assert(zif);
+               vl = &zif->l2info.vl;
+               vid = vl->vid;
+       }
+
+       /* See if this interface (or interface plus VLAN Id) maps to a VxLAN */
+       /* TODO: Optimize with a hash. */
+       zns = zebra_ns_lookup(NS_DEFAULT);
+       for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) {
+               tmp_if = (struct interface *)rn->info;
+               if (!tmp_if)
+                       continue;
+               zif = tmp_if->info;
+               if (!zif || zif->zif_type != ZEBRA_IF_VXLAN)
+                       continue;
+               if (!if_is_operative(tmp_if))
+                       continue;
+               vxl = &zif->l2info.vxl;
+
+               if (zif->brslave_info.br_if != br_if)
+                       continue;
+
+               if (!bridge_vlan_aware || vxl->access_vlan == vid) {
+                       found = 1;
+                       break;
+               }
+       }
+
+       if (!found)
+               return NULL;
+
+       zl3vni = zl3vni_lookup(vxl->vni);
+       return zl3vni;
+}
+
+/*
+ * Inform BGP about l3-vni.
+ */
+static int zl3vni_send_add_to_client(zebra_l3vni_t *zl3vni)
+{
+       struct stream *s = NULL;
+       struct zserv *client = NULL;
+       struct ethaddr rmac;
+       char buf[ETHER_ADDR_STRLEN];
+
+       client = zebra_find_client(ZEBRA_ROUTE_BGP, 0);
+       /* BGP may not be running. */
+       if (!client)
+               return 0;
+
+       /* get the rmac */
+       memset(&rmac, 0, sizeof(struct ethaddr));
+       zl3vni_get_rmac(zl3vni, &rmac);
+
+       s = client->obuf;
+       stream_reset(s);
+
+       zclient_create_header(s, ZEBRA_L3VNI_ADD,
+                           zl3vni_vrf_id(zl3vni));
+       stream_putl(s, zl3vni->vni);
+       stream_put(s, &rmac, sizeof(struct ethaddr));
+       stream_put_in_addr(s, &zl3vni->local_vtep_ip);
+
+       /* Write packet size. */
+       stream_putw_at(s, 0, stream_get_endp(s));
+
+       if (IS_ZEBRA_DEBUG_VXLAN)
+               zlog_debug("Send L3_VNI_ADD %u VRF %s RMAC %s local-ip %s to %s",
+                          zl3vni->vni, vrf_id_to_name(zl3vni_vrf_id(zl3vni)),
+                          prefix_mac2str(&rmac, buf, sizeof(buf)),
+                          inet_ntoa(zl3vni->local_vtep_ip),
+                          zebra_route_string(client->proto));
+
+       client->l3vniadd_cnt++;
+       return zebra_server_send_message(client);
+}
+
+/*
+ * Inform BGP about local l3-VNI deletion.
+ */
+static int zl3vni_send_del_to_client(zebra_l3vni_t *zl3vni)
+{
+       struct stream *s = NULL;
+       struct zserv *client = NULL;
+
+       client = zebra_find_client(ZEBRA_ROUTE_BGP, 0);
+       /* BGP may not be running. */
+       if (!client)
+               return 0;
+
+       s = client->obuf;
+       stream_reset(s);
+
+       zclient_create_header(s, ZEBRA_L3VNI_DEL,
+                           zl3vni_vrf_id(zl3vni));
+       stream_putl(s, zl3vni->vni);
+
+       /* Write packet size. */
+       stream_putw_at(s, 0, stream_get_endp(s));
+
+       if (IS_ZEBRA_DEBUG_VXLAN)
+               zlog_debug("Send L3_VNI_DEL %u VRF %s to %s",
+                          zl3vni->vni,
+                          vrf_id_to_name(zl3vni_vrf_id(zl3vni)),
+                          zebra_route_string(client->proto));
+
+       client->l3vnidel_cnt++;
+       return zebra_server_send_message(client);
+}
+
+static void zebra_vxlan_process_l3vni_oper_up(zebra_l3vni_t *zl3vni)
+{
+       if (!zl3vni)
+               return;
+
+       if (IS_ZEBRA_DEBUG_VXLAN)
+               zlog_debug("L3-VNI %u is UP - send add to BGP",
+                          zl3vni->vni);
+
+       /* send l3vni add to BGP */
+       zl3vni_send_add_to_client(zl3vni);
+}
+
+static void zebra_vxlan_process_l3vni_oper_down(zebra_l3vni_t *zl3vni)
+{
+       if (!zl3vni)
+               return;
+
+       if (IS_ZEBRA_DEBUG_VXLAN)
+               zlog_debug("L3-VNI %u is Down - Send del to BGP",
+                          zl3vni->vni);
+
+       /* send l3-vni del to BGP*/
+       zl3vni_send_del_to_client(zl3vni);
+}
+
+static void zvni_add_to_l3vni_list(struct hash_backet *backet,
+                                  void *ctxt)
+{
+       zebra_vni_t *zvni = (zebra_vni_t *) backet->data;
+       zebra_l3vni_t *zl3vni = (zebra_l3vni_t *) ctxt;
+
+       if (zvni->vrf_id == zl3vni_vrf_id(zl3vni))
+               listnode_add_sort(zl3vni->l2vnis, zvni);
+}
+
+/*
+ *  handle transition of vni from l2 to l3 and vice versa
+ */
+static int zebra_vxlan_handle_vni_transition(struct zebra_vrf *zvrf,
+                                             vni_t vni, int add)
+{
+       zebra_vni_t *zvni = NULL;
+
+       /* There is a possibility that VNI notification was already received
+        * from kernel and we programmed it as L2-VNI
+        * In such a case we need to delete this L2-VNI first, so
+        * that it can be reprogrammed as L3-VNI in the system. It is also
+        * possible that the vrf-vni mapping is removed from FRR while the vxlan
+        * interface is still present in kernel. In this case to keep it
+        * symmetric, we will delete the l3-vni and reprogram it as l2-vni
+        */
+       if (add) {
+               /* Locate hash entry */
+               zvni = zvni_lookup(vni);
+               if (!zvni)
+                       return 0;
+
+               if (IS_ZEBRA_DEBUG_VXLAN)
+                       zlog_debug("Del L2-VNI %u - transition to L3-VNI",
+                                  vni);
+
+               /* Delete VNI from BGP. */
+               zvni_send_del_to_client(zvni->vni);
+
+               /* Free up all neighbors and MAC, if any. */
+               zvni_neigh_del_all(zvni, 0, 0, DEL_ALL_NEIGH);
+               zvni_mac_del_all(zvni, 0, 0, DEL_ALL_MAC);
+
+               /* Free up all remote VTEPs, if any. */
+               zvni_vtep_del_all(zvni, 0);
+
+               /* Delete the hash entry. */
+               if (zvni_del(zvni)) {
+                       zlog_err("Failed to del VNI hash %p, VNI %u",
+                                zvni, zvni->vni);
+                       return -1;
+               }
+       } else {
+               /* TODO_MITESH: This needs to be thought through. We don't have
+                * enough information at this point to reprogram the vni as
+                * l2-vni. One way is to store the required info in l3-vni and
+                * used it solely for this purpose
+                */
+       }
+
+       return 0;
+}
+
+/* delete and uninstall rmac hash entry */
+static void zl3vni_del_rmac_hash_entry(struct hash_backet *backet,
+                                      void *ctx)
+{
+       zebra_mac_t *zrmac = NULL;
+       zebra_l3vni_t *zl3vni = NULL;
+
+       zrmac = (zebra_mac_t *)backet->data;
+       zl3vni = (zebra_l3vni_t *)ctx;
+       zl3vni_rmac_uninstall(zl3vni, zrmac);
+       zl3vni_rmac_del(zl3vni, zrmac);
+}
+
+/* delete and uninstall nh hash entry */
+static void zl3vni_del_nh_hash_entry(struct hash_backet *backet,
+                                    void *ctx)
+{
+       zebra_neigh_t *n = NULL;
+       zebra_l3vni_t *zl3vni = NULL;
+
+       n = (zebra_neigh_t *)backet->data;
+       zl3vni = (zebra_l3vni_t *)ctx;
+       zl3vni_nh_uninstall(zl3vni, n);
+       zl3vni_nh_del(zl3vni, n);
+}
+
+static int ip_prefix_send_to_client(vrf_id_t vrf_id,
+                                            struct prefix *p,
+                                            uint16_t cmd)
+{
+       struct zserv *client = NULL;
+       struct stream *s = NULL;
+       char buf[PREFIX_STRLEN];
+
+       client = zebra_find_client(ZEBRA_ROUTE_BGP, 0);
+       /* BGP may not be running. */
+       if (!client)
+               return 0;
+
+       s = client->obuf;
+       stream_reset(s);
+
+       zclient_create_header(s, cmd, vrf_id);
+       stream_put(s, p, sizeof(struct prefix));
+
+       /* Write packet size. */
+       stream_putw_at(s, 0, stream_get_endp(s));
+
+       if (IS_ZEBRA_DEBUG_VXLAN)
+               zlog_debug(
+                          "Send ip prefix %s %s on vrf %s",
+                          prefix2str(p, buf, sizeof(buf)),
+                          (cmd == ZEBRA_IP_PREFIX_ROUTE_ADD) ? "ADD" : "DEL",
+                          vrf_id_to_name(vrf_id));
+
+       if (cmd == ZEBRA_IP_PREFIX_ROUTE_ADD)
+               client->prefixadd_cnt++;
+       else
+               client->prefixdel_cnt++;
+
+       return zebra_server_send_message(client);
+}
+
+/* re-add remote rmac if needed */
+static int zebra_vxlan_readd_remote_rmac(zebra_l3vni_t *zl3vni,
+                                 struct ethaddr *rmac)
+{
+       char buf[ETHER_ADDR_STRLEN];
+       zebra_mac_t *zrmac = NULL;
+
+       zrmac = zl3vni_rmac_lookup(zl3vni, rmac);
+       if (!zrmac)
+               return 0;
+
+       if (IS_ZEBRA_DEBUG_VXLAN)
+               zlog_debug("Del remote RMAC %s L3VNI %u - readd",
+                          prefix_mac2str(rmac, buf, sizeof(buf)),
+                          zl3vni->vni);
+
+       zl3vni_rmac_install(zl3vni, zrmac);
+       return 0;
+}
+
+/* Public functions */
+
+/* handle evpn route in vrf table */
+void zebra_vxlan_evpn_vrf_route_add(vrf_id_t vrf_id,
+                                  struct ethaddr *rmac,
+                                  struct ipaddr *vtep_ip,
+                                  struct prefix *host_prefix)
+{
+       zebra_l3vni_t *zl3vni = NULL;
+
+       zl3vni = zl3vni_from_vrf(vrf_id);
+       if (!zl3vni || !is_l3vni_oper_up(zl3vni))
+               return;
+
+       /* add the next hop neighbor */
+       zl3vni_remote_nh_add(zl3vni, vtep_ip, rmac, host_prefix);
+
+       /* add the rmac */
+       zl3vni_remote_rmac_add(zl3vni, rmac, vtep_ip, host_prefix);
+}
+
+/* handle evpn vrf route delete */
+void zebra_vxlan_evpn_vrf_route_del(vrf_id_t vrf_id,
+                                  struct ethaddr *rmac,
+                                  struct ipaddr *vtep_ip,
+                                  struct prefix *host_prefix)
+{
+       zebra_l3vni_t *zl3vni = NULL;
+
+       zl3vni = zl3vni_from_vrf(vrf_id);
+       if (!zl3vni)
+               return;
+
+       /* delete the next hop entry */
+       zl3vni_remote_nh_del(zl3vni, vtep_ip, host_prefix);
+
+       /* delete the rmac entry */
+       zl3vni_remote_rmac_del(zl3vni, rmac, host_prefix);
+}
+
+void zebra_vxlan_print_specific_rmac_l3vni(struct vty *vty,
+                                          vni_t l3vni,
+                                          struct ethaddr *rmac,
+                                          u_char use_json)
+{
+       zebra_l3vni_t *zl3vni = NULL;
+       zebra_mac_t *zrmac = NULL;
+       json_object *json = NULL;
+
+       if (!is_evpn_enabled()) {
+               if (use_json)
+                       vty_out(vty, "{}\n");
+               return;
+       }
+
+       if (use_json)
+               json = json_object_new_object();
+
+       zl3vni = zl3vni_lookup(l3vni);
+       if (!zl3vni) {
+               if (use_json)
+                       vty_out(vty, "{}\n");
+               else
+                       vty_out(vty, "%% L3-VNI %u doesnt exist\n",
+                               l3vni);
+               return;
+       }
+
+       zrmac = zl3vni_rmac_lookup(zl3vni, rmac);
+       if (!zrmac) {
+               if (use_json)
+                       vty_out(vty, "{}\n");
+               else
+                       vty_out(vty,
+                               "%% Requested RMAC doesnt exist in L3-VNI %u",
+                               l3vni);
+               return;
+       }
+
+       zl3vni_print_rmac(zrmac, vty, json);
+
+       if (use_json) {
+               vty_out(vty, "%s\n", json_object_to_json_string_ext(
+                                            json, JSON_C_TO_STRING_PRETTY));
+               json_object_free(json);
+       }
+}
+
+void zebra_vxlan_print_rmacs_l3vni(struct vty *vty,
+                                  vni_t l3vni,
+                                  u_char use_json)
+{
+       zebra_l3vni_t *zl3vni;
+       u_int32_t num_rmacs;
+       struct rmac_walk_ctx wctx;
+       json_object *json = NULL;
+
+       if (!is_evpn_enabled())
+               return;
+
+       zl3vni = zl3vni_lookup(l3vni);
+       if (!zl3vni) {
+               if (use_json)
+                       vty_out(vty, "{}\n");
+               else
+                       vty_out(vty, "%% L3-VNI %u does not exist\n", l3vni);
+               return;
+       }
+       num_rmacs = hashcount(zl3vni->rmac_table);
+       if (!num_rmacs)
+               return;
+
+       if (use_json)
+               json = json_object_new_object();
+
+       memset(&wctx, 0, sizeof(struct rmac_walk_ctx));
+       wctx.vty = vty;
+       wctx.json = json;
+       if (!use_json) {
+               vty_out(vty,
+                       "Number of Remote RMACs known for this VNI: %u\n",
+                       num_rmacs);
+               vty_out(vty, "%-17s %-21s\n", "MAC", "Remote VTEP");
+       } else
+               json_object_int_add(json, "numRmacs", num_rmacs);
+
+       hash_iterate(zl3vni->rmac_table, zl3vni_print_rmac_hash, &wctx);
+
+       if (use_json) {
+               vty_out(vty, "%s\n", json_object_to_json_string_ext(
+                                            json, JSON_C_TO_STRING_PRETTY));
+               json_object_free(json);
+       }
+}
+
+void zebra_vxlan_print_rmacs_all_l3vni(struct vty *vty,
+                                      u_char use_json)
+{
+       struct zebra_ns *zns = NULL;
+       json_object *json = NULL;
+       void *args[2];
+
+       if (!is_evpn_enabled()) {
+               if (use_json)
+                       vty_out(vty, "{}\n");
+               return;
+       }
+
+       zns = zebra_ns_lookup(NS_DEFAULT);
+       if (!zns) {
+               if (use_json)
+                       vty_out(vty, "{}\n");
+               return;
+       }
 
-       /* Delete the hash entry. */
-       zvni_del(zvni);
+       if (use_json)
+               json = json_object_new_object();
+
+       args[0] = vty;
+       args[1] = json;
+       hash_iterate(zns->l3vni_table,
+                    (void (*)(struct hash_backet *,
+                              void *))zl3vni_print_rmac_hash_all_vni,
+                    args);
+
+       if (use_json) {
+               vty_out(vty, "%s\n", json_object_to_json_string_ext(
+                                            json, JSON_C_TO_STRING_PRETTY));
+               json_object_free(json);
+       }
 }
 
+void zebra_vxlan_print_specific_nh_l3vni(struct vty *vty,
+                                        vni_t l3vni,
+                                        struct ipaddr *ip,
+                                        u_char use_json)
+{
+       zebra_l3vni_t *zl3vni = NULL;
+       zebra_neigh_t *n = NULL;
+       json_object *json = NULL;
 
-/* Public functions */
+       if (!is_evpn_enabled()) {
+               if (use_json)
+                       vty_out(vty, "{}\n");
+               return;
+       }
+
+       if (use_json)
+               json = json_object_new_object();
+
+       zl3vni = zl3vni_lookup(l3vni);
+       if (!zl3vni) {
+               if (use_json)
+                       vty_out(vty, "{}\n");
+               else
+                       vty_out(vty, "%% L3-VNI %u does not exist\n", l3vni);
+               return;
+       }
+
+       n = zl3vni_nh_lookup(zl3vni, ip);
+       if (!n) {
+               if (use_json)
+                       vty_out(vty, "{}\n");
+               else
+                       vty_out(vty,
+                               "%% Requested next-hop not present for L3-VNI %u",
+                               l3vni);
+               return;
+       }
+
+       zl3vni_print_nh(n, vty, json);
+
+       if (use_json) {
+               vty_out(vty, "%s\n", json_object_to_json_string_ext(
+                                            json, JSON_C_TO_STRING_PRETTY));
+               json_object_free(json);
+       }
+}
+
+void zebra_vxlan_print_nh_l3vni(struct vty *vty,
+                               vni_t l3vni,
+                               u_char use_json)
+{
+       u_int32_t num_nh;
+       struct nh_walk_ctx wctx;
+       json_object *json = NULL;
+       zebra_l3vni_t *zl3vni = NULL;
+
+       if (!is_evpn_enabled())
+               return;
+
+       zl3vni = zl3vni_lookup(l3vni);
+       if (!zl3vni) {
+               if (use_json)
+                       vty_out(vty, "{}\n");
+               else
+                       vty_out(vty, "%% L3-VNI %u does not exist\n", l3vni);
+               return;
+       }
+
+       num_nh = hashcount(zl3vni->nh_table);
+       if (!num_nh)
+               return;
+
+       if (use_json)
+               json = json_object_new_object();
+
+       wctx.vty = vty;
+       wctx.json = json;
+       if (!use_json) {
+               vty_out(vty,
+                       "Number of NH Neighbors known for this VNI: %u\n",
+                       num_nh);
+               vty_out(vty, "%-15s %-17s\n", "IP", "RMAC");
+       } else
+               json_object_int_add(json, "numNextHops", num_nh);
+
+       hash_iterate(zl3vni->nh_table, zl3vni_print_nh_hash, &wctx);
+
+       if (use_json) {
+               vty_out(vty, "%s\n", json_object_to_json_string_ext(
+                                            json, JSON_C_TO_STRING_PRETTY));
+               json_object_free(json);
+       }
+}
+
+void zebra_vxlan_print_nh_all_l3vni(struct vty *vty,
+                                   u_char use_json)
+{
+       struct zebra_ns *zns = NULL;
+       json_object *json = NULL;
+       void *args[2];
+
+       if (!is_evpn_enabled()) {
+               if (use_json)
+                       vty_out(vty, "{}\n");
+               return;
+       }
+
+       zns = zebra_ns_lookup(NS_DEFAULT);
+       if (!zns)
+               return;
+
+       if (use_json)
+               json = json_object_new_object();
+
+       args[0] = vty;
+       args[1] = json;
+       hash_iterate(zns->l3vni_table,
+                    (void (*)(struct hash_backet *,
+                              void *))zl3vni_print_nh_hash_all_vni,
+                    args);
+
+       if (use_json) {
+               vty_out(vty, "%s\n", json_object_to_json_string_ext(
+                                            json, JSON_C_TO_STRING_PRETTY));
+               json_object_free(json);
+       }
+       return;
+}
+
+/*
+ * Display L3 VNI information (VTY command handler).
+ */
+void zebra_vxlan_print_l3vni(struct vty *vty, vni_t vni, u_char use_json)
+{
+       void *args[2];
+       json_object *json = NULL;
+       zebra_l3vni_t *zl3vni = NULL;
+
+       if (!is_evpn_enabled()) {
+               if (use_json)
+                       vty_out(vty, "{}\n");
+               return;
+       }
+
+       zl3vni = zl3vni_lookup(vni);
+       if (!zl3vni) {
+               if (use_json)
+                       vty_out(vty, "{}\n");
+               else
+                       vty_out(vty, "%% VNI %u does not exist\n", vni);
+               return;
+       }
+
+       if (use_json)
+               json = json_object_new_object();
+
+       args[0] = vty;
+       args[1] = json;
+       zl3vni_print(zl3vni, (void *)args);
+
+       if (use_json) {
+               vty_out(vty, "%s\n", json_object_to_json_string_ext(
+                                            json, JSON_C_TO_STRING_PRETTY));
+               json_object_free(json);
+       }
+}
+
+void zebra_vxlan_print_vrf_vni(struct vty *vty, struct zebra_vrf *zvrf,
+                              json_object *json_vrfs)
+{
+       char buf[ETHER_ADDR_STRLEN];
+       zebra_l3vni_t *zl3vni = NULL;
+
+       zl3vni = zl3vni_lookup(zvrf->l3vni);
+       if (!zl3vni)
+               return;
+
+       if (!json_vrfs) {
+               vty_out(vty, "%-37s %-10u %-20s %-20s %-5s %-18s\n",
+                       zvrf_name(zvrf),
+                       zl3vni->vni,
+                       zl3vni_vxlan_if_name(zl3vni),
+                       zl3vni_svi_if_name(zl3vni),
+                       zl3vni_state2str(zl3vni),
+                       zl3vni_rmac2str(zl3vni, buf, sizeof(buf)));
+       } else {
+               json_object *json_vrf = NULL;
+               json_vrf = json_object_new_object();
+               json_object_string_add(json_vrf, "vrf",
+                                      zvrf_name(zvrf));
+               json_object_int_add(json_vrf, "vni", zl3vni->vni);
+               json_object_string_add(json_vrf, "vxlanIntf",
+                                      zl3vni_vxlan_if_name(zl3vni));
+               json_object_string_add(json_vrf, "sviIntf",
+                                      zl3vni_svi_if_name(zl3vni));
+               json_object_string_add(json_vrf, "state",
+                                      zl3vni_state2str(zl3vni));
+               json_object_string_add(json_vrf, "routerMac",
+                                      zl3vni_rmac2str(zl3vni, buf,
+                                                      sizeof(buf)));
+               json_object_array_add(json_vrfs, json_vrf);
+       }
+}
 
 /*
  * Display Neighbors for a VNI (VTY command handler).
@@ -2736,25 +4574,35 @@ void zebra_vxlan_print_macs_vni_vtep(struct vty *vty, struct zebra_vrf *zvrf,
 void zebra_vxlan_print_vni(struct vty *vty, struct zebra_vrf *zvrf, vni_t vni,
                           u_char use_json)
 {
-       zebra_vni_t *zvni;
        json_object *json = NULL;
        void *args[2];
+       zebra_l3vni_t *zl3vni = NULL;
+       zebra_vni_t *zvni = NULL;
 
        if (!is_evpn_enabled())
                return;
-       zvni = zvni_lookup(vni);
-       if (!zvni) {
-               if (use_json)
-                       vty_out(vty, "{}\n");
-               else
-                       vty_out(vty, "%% VNI %u does not exist\n", vni);
-               return;
-       }
+
        if (use_json)
                json = json_object_new_object();
        args[0] = vty;
        args[1] = json;
-       zvni_print(zvni, (void *)args);
+
+       zl3vni = zl3vni_lookup(vni);
+       if (zl3vni) {
+               zl3vni_print(zl3vni, (void *)args);
+       } else {
+               zvni = zvni_lookup(vni);
+               if (!zvni) {
+                       if (use_json)
+                               vty_out(vty, "{}\n");
+                       else
+                               vty_out(vty, "%% VNI %u does not exist\n", vni);
+                       return;
+               }
+
+               zvni_print(zvni, (void *)args);
+       }
+
        if (use_json) {
                vty_out(vty, "%s\n", json_object_to_json_string_ext(
                                             json, JSON_C_TO_STRING_PRETTY));
@@ -2762,44 +4610,91 @@ void zebra_vxlan_print_vni(struct vty *vty, struct zebra_vrf *zvrf, vni_t vni,
        }
 }
 
-/*
- * Display VNI hash table (VTY command handler).
- */
-void zebra_vxlan_print_vnis(struct vty *vty, struct zebra_vrf *zvrf,
-                           u_char use_json)
+/* Display all global details for EVPN */
+void zebra_vxlan_print_evpn(struct vty *vty, u_char uj)
 {
-       u_int32_t num_vnis;
+       int num_l2vnis = 0;
+       int num_l3vnis = 0;
+       int num_vnis = 0;
        json_object *json = NULL;
-       void *args[2];
+       struct zebra_ns *zns = NULL;
+       struct zebra_vrf *zvrf = NULL;
 
        if (!is_evpn_enabled())
                return;
-       num_vnis = hashcount(zvrf->vni_table);
-       if (!num_vnis) {
-               if (use_json)
-                       vty_out(vty, "{}\n");
+
+       zns = zebra_ns_lookup(NS_DEFAULT);
+       if (!zns)
                return;
-       }
-       if (use_json) {
+
+       zvrf = vrf_info_lookup(VRF_DEFAULT);
+       if (!zvrf)
+               return;
+
+       num_l3vnis = hashcount(zns->l3vni_table);
+       num_l2vnis = hashcount(zvrf->vni_table);
+       num_vnis = num_l2vnis + num_l3vnis;
+
+       if (uj) {
                json = json_object_new_object();
                json_object_string_add(json, "advertiseGatewayMacip",
                                       zvrf->advertise_gw_macip ? "Yes" : "No");
                json_object_int_add(json, "numVnis", num_vnis);
+               json_object_int_add(json, "numL2Vnis", num_l2vnis);
+               json_object_int_add(json, "numL3Vnis", num_l3vnis);
        } else {
+               vty_out(vty, "L2 VNIs: %u\n", num_l2vnis);
+               vty_out(vty, "L3 VNIs: %u\n", num_l3vnis);
                vty_out(vty, "Advertise gateway mac-ip: %s\n",
                        zvrf->advertise_gw_macip ? "Yes" : "No");
-               vty_out(vty, "Number of VNIs: %u\n", num_vnis);
-               vty_out(vty, "%-10s %-21s %-15s %-8s %-8s %-15s\n", "VNI",
-                       "VxLAN IF", "VTEP IP", "# MACs", "# ARPs",
-                       "# Remote VTEPs");
        }
+
+       if (uj) {
+               vty_out(vty, "%s\n", json_object_to_json_string_ext(
+                                            json, JSON_C_TO_STRING_PRETTY));
+               json_object_free(json);
+       }
+}
+
+/*
+ * Display VNI hash table (VTY command handler).
+ */
+void zebra_vxlan_print_vnis(struct vty *vty, struct zebra_vrf *zvrf,
+                           u_char use_json)
+{
+       json_object *json = NULL;
+       struct zebra_ns *zns = NULL;
+       void *args[2];
+
+       if (!is_evpn_enabled())
+               return;
+
+       zns = zebra_ns_lookup(NS_DEFAULT);
+       if (!zns)
+               return;
+
+
+       if (use_json)
+               json = json_object_new_object();
+       else
+               vty_out(vty,
+                       "%-10s %-4s %-21s %-8s %-8s %-15s %-37s\n",
+                       "VNI", "Type", "VxLAN IF", "# MACs",
+                       "# ARPs", "# Remote VTEPs", "Tenant VRF");
+
        args[0] = vty;
        args[1] = json;
 
+       /* Display all L2-VNIs */
        hash_iterate(zvrf->vni_table,
                     (void (*)(struct hash_backet *, void *))zvni_print_hash,
                     args);
 
+       /* Display all L3-VNIs */
+       hash_iterate(zns->l3vni_table,
+                    (void (*)(struct hash_backet *, void *))zl3vni_print_hash,
+                    args);
+
        if (use_json) {
                vty_out(vty, "%s\n", json_object_to_json_string_ext(
                                             json, JSON_C_TO_STRING_PRETTY));
@@ -2816,18 +4711,27 @@ void zebra_vxlan_print_vnis(struct vty *vty, struct zebra_vrf *zvrf,
 int zebra_vxlan_local_neigh_del(struct interface *ifp,
                                struct interface *link_if, struct ipaddr *ip)
 {
-       zebra_vni_t *zvni;
-       zebra_neigh_t *n;
        char buf[INET6_ADDRSTRLEN];
        char buf2[ETHER_ADDR_STRLEN];
-       zebra_mac_t *zmac;
+       zebra_neigh_t *n = NULL;
+       zebra_vni_t *zvni = NULL;
+       zebra_mac_t *zmac = NULL;
+       zebra_l3vni_t *zl3vni = NULL;
+
+       /* check if this is a remote neigh entry corresponding to remote
+        * next-hop
+        */
+       zl3vni = zl3vni_from_svi(ifp, link_if);
+       if (zl3vni)
+               return zl3vni_local_nh_del(zl3vni, ip);
 
        /* We are only interested in neighbors on an SVI that resides on top
         * of a VxLAN bridge.
         */
-       zvni = zvni_map_svi(ifp, link_if);
+       zvni = zvni_from_svi(ifp, link_if);
        if (!zvni)
                return 0;
+
        if (!zvni->vxlan_if) {
                zlog_err(
                        "VNI %u hash %p doesn't have intf upon local neighbor DEL",
@@ -2836,7 +4740,7 @@ int zebra_vxlan_local_neigh_del(struct interface *ifp,
        }
 
        if (IS_ZEBRA_DEBUG_VXLAN)
-               zlog_debug("Del neighbor %s intf %s(%u) -> VNI %u",
+               zlog_debug("Del neighbor %s intf %s(%u) -> L2-VNI %u",
                           ipaddr2str(ip, buf, sizeof(buf)),
                           ifp->name, ifp->ifindex, zvni->vni);
 
@@ -2891,23 +4795,30 @@ int zebra_vxlan_local_neigh_add_update(struct interface *ifp,
                                       struct ethaddr *macaddr, u_int16_t state,
                                       u_char ext_learned)
 {
-       zebra_vni_t *zvni;
-       zebra_neigh_t *n;
-       zebra_mac_t *zmac, *old_zmac;
        char buf[ETHER_ADDR_STRLEN];
        char buf2[INET6_ADDRSTRLEN];
+       zebra_vni_t *zvni = NULL;
+       zebra_neigh_t *n = NULL;
+       zebra_mac_t *zmac = NULL, *old_zmac = NULL;
+       zebra_l3vni_t *zl3vni = NULL;
+
+       /* check if this is a remote neigh entry corresponding to remote
+        * next-hop
+        */
+       zl3vni = zl3vni_from_svi(ifp, link_if);
+       if (zl3vni)
+               return zl3vni_local_nh_add_update(zl3vni, ip, state);
 
        /* We are only interested in neighbors on an SVI that resides on top
         * of a VxLAN bridge.
         */
-       zvni = zvni_map_svi(ifp, link_if);
+       zvni = zvni_from_svi(ifp, link_if);
        if (!zvni)
                return 0;
 
        if (IS_ZEBRA_DEBUG_VXLAN)
                zlog_debug(
-                       "Add/Update neighbor %s MAC %s intf %s(%u) state 0x%x "
-                       "%s-> VNI %u",
+                       "Add/Update neighbor %s MAC %s intf %s(%u) state 0x%x %s-> L2-VNI %u",
                        ipaddr2str(ip, buf2, sizeof(buf2)),
                        prefix_mac2str(macaddr, buf, sizeof(buf)), ifp->name,
                        ifp->ifindex, state, ext_learned ? "ext-learned " : "",
@@ -3015,13 +4926,13 @@ int zebra_vxlan_local_neigh_add_update(struct interface *ifp,
 
        /* Inform BGP. */
        if (IS_ZEBRA_DEBUG_VXLAN)
-               zlog_debug("neigh %s (MAC %s) is now ACTIVE on VNI %u",
+               zlog_debug("neigh %s (MAC %s) is now ACTIVE on L2-VNI %u",
                           ipaddr2str(ip, buf2, sizeof(buf2)),
                           prefix_mac2str(macaddr, buf, sizeof(buf)),
                           zvni->vni);
-
        ZEBRA_NEIGH_SET_ACTIVE(n);
-       return zvni_neigh_send_add_to_client(zvni->vni, ip, macaddr, 0);
+
+       return zvni_neigh_send_add_to_client(zvni->vni, ip, macaddr, n->flags);
 }
 
 
@@ -3045,6 +4956,10 @@ int zebra_vxlan_remote_macip_del(struct zserv *client, u_short length,
        struct interface *ifp = NULL;
        struct zebra_if *zif = NULL;
 
+       memset(&macaddr, 0, sizeof(struct ethaddr));
+       memset(&ip, 0, sizeof(struct ipaddr));
+       memset(&vtep_ip, 0, sizeof(struct in_addr));
+
        s = client->ibuf;
 
        while (l < length) {
@@ -3128,6 +5043,17 @@ int zebra_vxlan_remote_macip_del(struct zserv *client, u_short length,
                if (!mac && !n)
                        continue;
 
+               /* Ignore the delete if this mac is a gateway mac-ip */
+               if (mac && CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL) &&
+                   CHECK_FLAG(mac->flags, ZEBRA_MAC_DEF_GW)) {
+                       zlog_err("%u: Ignore Del for  MAC %s neigh %s on VNI %u as it is configured as a default gateway",
+                                zvrf_id(zvrf),
+                                prefix_mac2str(&macaddr, buf, sizeof(buf)),
+                                ipaddr2str(&ip, buf1, sizeof(buf1)),
+                                vni);
+                       continue;
+               }
+
                /* Uninstall remote neighbor or MAC. */
                if (n) {
                        /* When the MAC changes for an IP, it is possible the
@@ -3185,10 +5111,15 @@ int zebra_vxlan_remote_macip_add(struct zserv *client, u_short length,
        int update_mac = 0, update_neigh = 0;
        char buf[ETHER_ADDR_STRLEN];
        char buf1[INET6_ADDRSTRLEN];
-       u_char sticky;
+       u_char sticky = 0;
+       u_char flags = 0;
        struct interface *ifp = NULL;
        struct zebra_if *zif = NULL;
 
+       memset(&macaddr, 0, sizeof(struct ethaddr));
+       memset(&ip, 0, sizeof(struct ipaddr));
+       memset(&vtep_ip, 0, sizeof(struct in_addr));
+
        if (!EVPN_ENABLED(zvrf)) {
                zlog_warn("%s: EVPN Not turned on yet we have received a remote_macip add zapi callback",
                          __PRETTY_FUNCTION__);
@@ -3218,17 +5149,17 @@ int zebra_vxlan_remote_macip_add(struct zserv *client, u_short length,
                STREAM_GET(&vtep_ip.s_addr, s, IPV4_MAX_BYTELEN);
                l += IPV4_MAX_BYTELEN;
 
-               /* Get 'sticky' flag. */
-               STREAM_GETC(s, sticky);
+               /* Get flags - sticky mac and/or gateway mac */
+               flags = stream_getc(s);
+               sticky = CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY);
                l++;
 
                if (IS_ZEBRA_DEBUG_VXLAN)
                        zlog_debug(
-                               "Recv MACIP Add %sMAC %s IP %s VNI %u Remote VTEP %s from %s",
-                               sticky ? "sticky " : "",
+                               "Recv MACIP Add MAC %s IP %s VNI %u Remote VTEP %s with flags 0x%x from %s",
                                prefix_mac2str(&macaddr, buf, sizeof(buf)),
                                ipaddr2str(&ip, buf1, sizeof(buf1)), vni,
-                               inet_ntoa(vtep_ip),
+                               inet_ntoa(vtep_ip), flags,
                                zebra_route_string(client->proto));
 
                /* Locate VNI hash entry - expected to exist. */
@@ -3270,13 +5201,26 @@ int zebra_vxlan_remote_macip_add(struct zserv *client, u_short length,
                        zvni_vtep_install(zvni, &vtep_ip);
                }
 
-               /* First, check if the remote MAC is unknown or has a change. If
-                * so,
-                * that needs to be updated first. Note that client could
-                * install
-                * MAC and MACIP separately or just install the latter.
-                */
                mac = zvni_mac_lookup(zvni, &macaddr);
+
+               /* Ignore the update if the mac is already present
+                  as a gateway mac */
+               if (mac && CHECK_FLAG(mac->flags, ZEBRA_MAC_DEF_GW) &&
+                   CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_GW)) {
+                       if (IS_ZEBRA_DEBUG_VXLAN)
+                               zlog_debug("%u:Ignore MAC %s IP %s on VNI %u as MAC is already configured as gateway mac", 
+                                          zvrf_id(zvrf),
+                                          prefix_mac2str(&macaddr,
+                                                         buf, sizeof(buf)),
+                                          ipaddr2str(&ip, buf1,
+                                                     sizeof(buf1)), vni);
+                       continue;
+               }
+
+               /* check if the remote MAC is unknown or has a change.
+                * If so, that needs to be updated first. Note that client could
+                * install MAC and MACIP separately or just install the latter.
+                */
                if (!mac || !CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)
                    || (CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY) ? 1 : 0)
                               != sticky
@@ -3391,7 +5335,6 @@ int zebra_vxlan_check_del_local_mac(struct interface *ifp,
        zebra_vni_t *zvni;
        zebra_mac_t *mac;
        char buf[ETHER_ADDR_STRLEN];
-       u_char sticky;
 
        zif = ifp->info;
        assert(zif);
@@ -3423,9 +5366,7 @@ int zebra_vxlan_check_del_local_mac(struct interface *ifp,
                        ifp->name, ifp->ifindex, vni);
 
        /* Remove MAC from BGP. */
-       sticky = CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY) ? 1 : 0;
-       zvni_mac_send_del_to_client(zvni->vni, macaddr,
-                                   (sticky ? ZEBRA_MAC_TYPE_STICKY : 0));
+       zvni_mac_send_del_to_client(zvni->vni, macaddr, mac->flags);
 
        /*
         * If there are no neigh associated with the mac delete the mac
@@ -3450,11 +5391,12 @@ int zebra_vxlan_check_readd_remote_mac(struct interface *ifp,
                                       struct interface *br_if,
                                       struct ethaddr *macaddr, vlanid_t vid)
 {
-       struct zebra_if *zif;
-       struct zebra_l2info_vxlan *vxl;
+       struct zebra_if *zif = NULL;
+       struct zebra_l2info_vxlan *vxl = NULL;
        vni_t vni;
-       zebra_vni_t *zvni;
-       zebra_mac_t *mac;
+       zebra_vni_t *zvni = NULL;
+       zebra_l3vni_t *zl3vni = NULL;
+       zebra_mac_t *mac = NULL;
        char buf[ETHER_ADDR_STRLEN];
 
        zif = ifp->info;
@@ -3466,6 +5408,11 @@ int zebra_vxlan_check_readd_remote_mac(struct interface *ifp,
        if (!is_evpn_enabled())
                return 0;
 
+       /* check if this is a remote RMAC and readd simillar to remote macs */
+       zl3vni = zl3vni_lookup(vni);
+       if (zl3vni)
+               return zebra_vxlan_readd_remote_rmac(zl3vni, macaddr);
+
        /* Locate hash entry; it is expected to exist. */
        zvni = zvni_lookup(vni);
        if (!zvni)
@@ -3498,7 +5445,6 @@ int zebra_vxlan_local_mac_del(struct interface *ifp, struct interface *br_if,
        zebra_vni_t *zvni;
        zebra_mac_t *mac;
        char buf[ETHER_ADDR_STRLEN];
-       u_char sticky;
 
        /* We are interested in MACs only on ports or (port, VLAN) that
         * map to a VNI.
@@ -3527,9 +5473,7 @@ int zebra_vxlan_local_mac_del(struct interface *ifp, struct interface *br_if,
                return 0;
 
        /* Remove MAC from BGP. */
-       sticky = CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY) ? 1 : 0;
-       zvni_mac_send_del_to_client(zvni->vni, macaddr,
-                                   (sticky ? ZEBRA_MAC_TYPE_STICKY : 0));
+       zvni_mac_send_del_to_client(zvni->vni, macaddr, mac->flags);
 
        /* Update all the neigh entries associated with this mac */
        zvni_process_neigh_on_local_mac_del(zvni, mac);
@@ -3668,7 +5612,7 @@ int zebra_vxlan_local_mac_add_update(struct interface *ifp,
        if (add) {
                zvni_process_neigh_on_local_mac_add(zvni, mac);
                return zvni_mac_send_add_to_client(zvni->vni, macaddr,
-                                                  sticky);
+                                                  mac->flags);
        }
 
        return 0;
@@ -3898,14 +5842,14 @@ int zebra_vxlan_add_del_gw_macip(struct interface *ifp, struct prefix *p,
                                svi_if_link = if_lookup_by_index_per_ns(
                                        zebra_ns_lookup(NS_DEFAULT),
                                        svi_if_zif->link_ifindex);
-                               zvni = zvni_map_svi(svi_if, svi_if_link);
+                               zvni = zvni_from_svi(svi_if, svi_if_link);
                        }
                } else if (IS_ZEBRA_IF_BRIDGE(svi_if)) {
                        /*
                         * If it is a vlan unaware bridge then svi is the bridge
                         * itself
                         */
-                       zvni = zvni_map_svi(svi_if, svi_if);
+                       zvni = zvni_from_svi(svi_if, svi_if);
                }
        } else if (IS_ZEBRA_IF_VLAN(ifp)) {
                struct zebra_if *svi_if_zif =
@@ -3917,9 +5861,9 @@ int zebra_vxlan_add_del_gw_macip(struct interface *ifp, struct prefix *p,
                svi_if_link = if_lookup_by_index_per_ns(
                        zebra_ns_lookup(NS_DEFAULT), svi_if_zif->link_ifindex);
                if (svi_if_zif && svi_if_link)
-                       zvni = zvni_map_svi(ifp, svi_if_link);
+                       zvni = zvni_from_svi(ifp, svi_if_link);
        } else if (IS_ZEBRA_IF_BRIDGE(ifp)) {
-               zvni = zvni_map_svi(ifp, ifp);
+               zvni = zvni_from_svi(ifp, ifp);
        }
 
        if (!zvni)
@@ -3932,10 +5876,6 @@ int zebra_vxlan_add_del_gw_macip(struct interface *ifp, struct prefix *p,
        }
 
 
-       /* check if we are advertising gw macip routes */
-       if (!advertise_gw_macip_enabled(zvni))
-               return 0;
-
        memcpy(&macaddr.octet, ifp->hw_addr, ETH_ALEN);
 
        if (p->family == AF_INET) {
@@ -3958,56 +5898,454 @@ int zebra_vxlan_add_del_gw_macip(struct interface *ifp, struct prefix *p,
 }
 
 /*
- * Handle SVI interface going down. At this point, this is a NOP since
- * the kernel deletes the neighbor entries on this SVI (if any).
+ * Handle SVI interface going down.
+ * SVI can be associated to either L3-VNI or L2-VNI.
+ * For L2-VNI: At this point, this is a NOP since
+ *     the kernel deletes the neighbor entries on this SVI (if any).
+ *      We only need to update the vrf corresponding to zvni.
+ * For L3-VNI: L3-VNI is operationally down, update mac-ip routes and delete
+ *     from bgp
  */
 int zebra_vxlan_svi_down(struct interface *ifp, struct interface *link_if)
 {
+       zebra_l3vni_t *zl3vni = NULL;
+
+       zl3vni = zl3vni_from_svi(ifp, link_if);
+       if (zl3vni) {
+
+               /* process l3-vni down */
+               zebra_vxlan_process_l3vni_oper_down(zl3vni);
+
+               /* remove association with svi-if */
+               zl3vni->svi_if = NULL;
+       } else {
+               zebra_vni_t *zvni = NULL;
+
+               /* since we dont have svi corresponding to zvni, we associate it
+                * to default vrf. Note: the corresponding neigh entries on the
+                * SVI would have already been deleted */
+               zvni = zvni_from_svi(ifp, link_if);
+               if (zvni) {
+                       zvni->vrf_id = VRF_DEFAULT;
+
+                       /* update the tenant vrf in BGP */
+                       zvni_send_add_to_client(zvni);
+               }
+       }
        return 0;
 }
 
 /*
- * Handle SVI interface coming up. This may or may not be of interest,
- * but if this is a SVI on a VxLAN bridge, we need to install any remote
- * neighbor entries (which will be used for EVPN ARP suppression).
+ * Handle SVI interface coming up.
+ * SVI can be associated to L3-VNI (l3vni vxlan interface) or L2-VNI (l2-vni
+ * vxlan intf).
+ * For L2-VNI: we need to install any remote neighbors entried (used for
+ * apr-suppression)
+ * For L3-VNI: SVI will be used to get the rmac to be used with L3-VNI
  */
 int zebra_vxlan_svi_up(struct interface *ifp, struct interface *link_if)
 {
+       zebra_vni_t *zvni = NULL;
+       zebra_l3vni_t *zl3vni = NULL;
+
+       zl3vni = zl3vni_from_svi(ifp, link_if);
+       if (zl3vni) {
+
+               /* associate with svi */
+               zl3vni->svi_if = ifp;
+
+               /* process oper-up */
+               if (is_l3vni_oper_up(zl3vni))
+                       zebra_vxlan_process_l3vni_oper_up(zl3vni);
+       } else {
+
+               /* process SVI up for l2-vni */
+               struct neigh_walk_ctx n_wctx;
+
+               zvni = zvni_from_svi(ifp, link_if);
+               if (!zvni)
+                       return 0;
+
+               if (!zvni->vxlan_if) {
+                       zlog_err("VNI %u hash %p doesn't have intf upon SVI up",
+                                zvni->vni, zvni);
+                       return -1;
+               }
+
+               if (IS_ZEBRA_DEBUG_VXLAN)
+                       zlog_debug("SVI %s(%u) VNI %u VRF %s is UP, installing neighbors",
+                                  ifp->name, ifp->ifindex, zvni->vni,
+                                  vrf_id_to_name(ifp->vrf_id));
+
+               /* update the vrf information for l2-vni and inform bgp */
+               zvni->vrf_id = ifp->vrf_id;
+               zvni_send_add_to_client(zvni);
+
+               /* Install any remote neighbors for this VNI. */
+               memset(&n_wctx, 0, sizeof(struct neigh_walk_ctx));
+               n_wctx.zvni = zvni;
+               hash_iterate(zvni->neigh_table,
+                            zvni_install_neigh_hash,
+                            &n_wctx);
+       }
+
+       return 0;
+}
+
+/*
+ * Handle VxLAN interface down
+ */
+int zebra_vxlan_if_down(struct interface *ifp)
+{
+       vni_t vni;
+       struct zebra_if *zif = NULL;
+       struct zebra_l2info_vxlan *vxl = NULL;
+       zebra_l3vni_t *zl3vni = NULL;
        zebra_vni_t *zvni;
-       struct neigh_walk_ctx n_wctx;
 
-       zvni = zvni_map_svi(ifp, link_if);
-       if (!zvni)
+       /* Check if EVPN is enabled. */
+       if (!is_evpn_enabled())
                return 0;
 
-       if (!zvni->vxlan_if) {
-               zlog_err("VNI %u hash %p doesn't have intf upon SVI up",
-                        zvni->vni, zvni);
-               return -1;
+       zif = ifp->info;
+       assert(zif);
+       vxl = &zif->l2info.vxl;
+       vni = vxl->vni;
+
+       zl3vni = zl3vni_lookup(vni);
+       if (zl3vni) {
+               /* process-if-down for l3-vni */
+               if (IS_ZEBRA_DEBUG_VXLAN)
+                       zlog_debug("Intf %s(%u) L3-VNI %u is DOWN",
+                                  ifp->name, ifp->ifindex, vni);
+
+               zebra_vxlan_process_l3vni_oper_down(zl3vni);
+       } else {
+               /* process if-down for l2-vni */
+               if (IS_ZEBRA_DEBUG_VXLAN)
+                       zlog_debug("Intf %s(%u) L2-VNI %u is DOWN",
+                                  ifp->name, ifp->ifindex, vni);
+
+               /* Locate hash entry; it is expected to exist. */
+               zvni = zvni_lookup(vni);
+               if (!zvni) {
+                       zlog_err(
+                               "Failed to locate VNI hash at DOWN, IF %s(%u) VNI %u",
+                               ifp->name, ifp->ifindex, vni);
+                       return -1;
+               }
+
+               assert(zvni->vxlan_if == ifp);
+
+               /* Delete this VNI from BGP. */
+               zvni_send_del_to_client(zvni->vni);
+
+               /* Free up all neighbors and MACs, if any. */
+               zvni_neigh_del_all(zvni, 1, 0, DEL_ALL_NEIGH);
+               zvni_mac_del_all(zvni, 1, 0, DEL_ALL_MAC);
+
+               /* Free up all remote VTEPs, if any. */
+               zvni_vtep_del_all(zvni, 1);
        }
+       return 0;
+}
 
-       if (IS_ZEBRA_DEBUG_VXLAN)
-               zlog_debug("SVI %s(%u) VNI %u is UP, installing neighbors",
-                          ifp->name, ifp->ifindex, zvni->vni);
+/*
+ * Handle VxLAN interface up - update BGP if required.
+ */
+int zebra_vxlan_if_up(struct interface *ifp)
+{
+       vni_t vni;
+       struct zebra_if *zif = NULL;
+       struct zebra_l2info_vxlan *vxl = NULL;
+       zebra_vni_t *zvni = NULL;
+       zebra_l3vni_t *zl3vni = NULL;
+
+       /* Check if EVPN is enabled. */
+       if (!is_evpn_enabled())
+               return 0;
+
+       zif = ifp->info;
+       assert(zif);
+       vxl = &zif->l2info.vxl;
+       vni = vxl->vni;
+
+       zl3vni = zl3vni_lookup(vni);
+       if (zl3vni) {
+
+               if (IS_ZEBRA_DEBUG_VXLAN)
+                       zlog_debug("Intf %s(%u) L3-VNI %u is UP",
+                                  ifp->name, ifp->ifindex, vni);
 
-       /* Install any remote neighbors for this VNI. */
-       memset(&n_wctx, 0, sizeof(struct neigh_walk_ctx));
-       n_wctx.zvni = zvni;
-       hash_iterate(zvni->neigh_table, zvni_install_neigh_hash, &n_wctx);
+               /* we need to associate with SVI, if any, we can associate with
+                * svi-if only after association with vxlan-intf is complete
+                */
+               zl3vni->svi_if = zl3vni_map_to_svi_if(zl3vni);
+
+               if (is_l3vni_oper_up(zl3vni))
+                       zebra_vxlan_process_l3vni_oper_up(zl3vni);
+       } else {
+               /* Handle L2-VNI add */
+               struct interface *vlan_if = NULL;
+
+               if (IS_ZEBRA_DEBUG_VXLAN)
+                       zlog_debug("Intf %s(%u) L2-VNI %u is UP",
+                                  ifp->name, ifp->ifindex, vni);
+
+               /* Locate hash entry; it is expected to exist. */
+               zvni = zvni_lookup(vni);
+               if (!zvni) {
+                       zlog_err(
+                               "Failed to locate VNI hash at UP, IF %s(%u) VNI %u",
+                               ifp->name, ifp->ifindex, vni);
+                       return -1;
+               }
+
+               assert(zvni->vxlan_if == ifp);
+               vlan_if = zvni_map_to_svi(vxl->access_vlan,
+                                         zif->brslave_info.br_if);
+               if (vlan_if) {
+                       zvni->vrf_id = vlan_if->vrf_id;
+                       zl3vni = zl3vni_from_vrf(vlan_if->vrf_id);
+                       if (zl3vni)
+                               listnode_add_sort(zl3vni->l2vnis, zvni);
+               }
+
+               /* If part of a bridge, inform BGP about this VNI. */
+               /* Also, read and populate local MACs and neighbors. */
+               if (zif->brslave_info.br_if) {
+                       zvni_send_add_to_client(zvni);
+                       zvni_read_mac_neigh(zvni, ifp);
+               }
+       }
+
+       return 0;
+}
+
+/*
+ * Handle VxLAN interface delete. Locate and remove entry in hash table
+ * and update BGP, if required.
+ */
+int zebra_vxlan_if_del(struct interface *ifp)
+{
+       vni_t vni;
+       struct zebra_if *zif = NULL;
+       struct zebra_l2info_vxlan *vxl = NULL;
+       zebra_vni_t *zvni = NULL;
+       zebra_l3vni_t *zl3vni = NULL;
+
+       /* Check if EVPN is enabled. */
+       if (!is_evpn_enabled())
+               return 0;
+
+       zif = ifp->info;
+       assert(zif);
+       vxl = &zif->l2info.vxl;
+       vni = vxl->vni;
+
+       zl3vni = zl3vni_lookup(vni);
+       if (zl3vni) {
+
+               if (IS_ZEBRA_DEBUG_VXLAN)
+                       zlog_debug("Del L3-VNI %u intf %s(%u)",
+                                  vni, ifp->name, ifp->ifindex);
+
+               /* process oper-down for l3-vni */
+               zebra_vxlan_process_l3vni_oper_down(zl3vni);
+
+               /* remove the association with vxlan_if */
+               memset(&zl3vni->local_vtep_ip, 0, sizeof(struct in_addr));
+               zl3vni->vxlan_if = NULL;
+       } else {
+
+               /* process if-del for l2-vni*/
+               if (IS_ZEBRA_DEBUG_VXLAN)
+                       zlog_debug("Del L2-VNI %u intf %s(%u)",
+                                  vni, ifp->name, ifp->ifindex);
+
+               /* Locate hash entry; it is expected to exist. */
+               zvni = zvni_lookup(vni);
+               if (!zvni) {
+                       zlog_err(
+                               "Failed to locate VNI hash at del, IF %s(%u) VNI %u",
+                               ifp->name, ifp->ifindex, vni);
+                       return 0;
+               }
+
+               /* remove from l3-vni list */
+               zl3vni = zl3vni_from_vrf(zvni->vrf_id);
+               if (zl3vni)
+                       listnode_delete(zl3vni->l2vnis, zvni);
+
+               /* Delete VNI from BGP. */
+               zvni_send_del_to_client(zvni->vni);
+
+               /* Free up all neighbors and MAC, if any. */
+               zvni_neigh_del_all(zvni, 0, 0, DEL_ALL_NEIGH);
+               zvni_mac_del_all(zvni, 0, 0, DEL_ALL_MAC);
+
+               /* Free up all remote VTEPs, if any. */
+               zvni_vtep_del_all(zvni, 0);
+
+               /* Delete the hash entry. */
+               if (zvni_del(zvni)) {
+                       zlog_err("Failed to del VNI hash %p, IF %s(%u) VNI %u",
+                                zvni, ifp->name, ifp->ifindex, zvni->vni);
+                       return -1;
+               }
+       }
+       return 0;
+}
+
+/*
+ * Handle VxLAN interface update - change to tunnel IP, master or VLAN.
+ */
+int zebra_vxlan_if_update(struct interface *ifp, u_int16_t chgflags)
+{
+       vni_t vni;
+       struct zebra_if *zif = NULL;
+       struct zebra_l2info_vxlan *vxl = NULL;
+       zebra_vni_t *zvni = NULL;
+       zebra_l3vni_t *zl3vni = NULL;
+
+       /* Check if EVPN is enabled. */
+       if (!is_evpn_enabled())
+               return 0;
+
+       zif = ifp->info;
+       assert(zif);
+       vxl = &zif->l2info.vxl;
+       vni = vxl->vni;
+
+       zl3vni = zl3vni_lookup(vni);
+       if (zl3vni) {
+
+               if (IS_ZEBRA_DEBUG_VXLAN)
+                       zlog_debug(
+                               "Update L3-VNI %u intf %s(%u) VLAN %u local IP %s master %u chg 0x%x",
+                               vni, ifp->name, ifp->ifindex,
+                               vxl->access_vlan, inet_ntoa(vxl->vtep_ip),
+                               zif->brslave_info.bridge_ifindex, chgflags);
+
+               /* Removed from bridge? Cleanup and return */
+               if ((chgflags & ZEBRA_VXLIF_MASTER_CHANGE)
+                   && (zif->brslave_info.bridge_ifindex == IFINDEX_INTERNAL)) {
+                       zebra_vxlan_process_l3vni_oper_down(zl3vni);
+                       return 0;
+               }
+
+               /* access-vlan change - process oper down, associate with new
+                * svi_if and then process oper up again
+                */
+               if (chgflags & ZEBRA_VXLIF_VLAN_CHANGE) {
+                       if (if_is_operative(ifp)) {
+                               zebra_vxlan_process_l3vni_oper_down(zl3vni);
+                               zl3vni->svi_if = NULL;
+                               zl3vni->svi_if = zl3vni_map_to_svi_if(zl3vni);
+                               if (is_l3vni_oper_up(zl3vni))
+                                       zebra_vxlan_process_l3vni_oper_up(
+                                                                       zl3vni);
+                       }
+               }
+
+               /* if we have a valid new master, process l3-vni oper up */
+               if (chgflags & ZEBRA_VXLIF_MASTER_CHANGE) {
+                       if (is_l3vni_oper_up(zl3vni))
+                               zebra_vxlan_process_l3vni_oper_up(zl3vni);
+               }
+       } else {
+
+               /* Update VNI hash. */
+               zvni = zvni_lookup(vni);
+               if (!zvni) {
+                       zlog_err(
+                               "Failed to find L2-VNI hash on update, IF %s(%u) VNI %u",
+                               ifp->name, ifp->ifindex, vni);
+                       return -1;
+               }
+
+               if (IS_ZEBRA_DEBUG_VXLAN)
+                       zlog_debug(
+                               "Update L2-VNI %u intf %s(%u) VLAN %u local IP %s master %u chg 0x%x",
+                               vni, ifp->name, ifp->ifindex,
+                               vxl->access_vlan, inet_ntoa(vxl->vtep_ip),
+                               zif->brslave_info.bridge_ifindex, chgflags);
+
+               /* Removed from bridge? Cleanup and return */
+               if ((chgflags & ZEBRA_VXLIF_MASTER_CHANGE)
+                   && (zif->brslave_info.bridge_ifindex == IFINDEX_INTERNAL)) {
+                       /* Delete from client, remove all remote VTEPs */
+                       /* Also, free up all MACs and neighbors. */
+                       zvni_send_del_to_client(zvni->vni);
+                       zvni_neigh_del_all(zvni, 1, 0, DEL_ALL_NEIGH);
+                       zvni_mac_del_all(zvni, 1, 0, DEL_ALL_MAC);
+                       zvni_vtep_del_all(zvni, 1);
+                       return 0;
+               }
+
+               /* Handle other changes. */
+               if (chgflags & ZEBRA_VXLIF_VLAN_CHANGE) {
+                       /* Remove all existing local neigh and MACs for this VNI
+                        * (including from BGP)
+                        */
+                       zvni_neigh_del_all(zvni, 0, 1, DEL_LOCAL_MAC);
+                       zvni_mac_del_all(zvni, 0, 1, DEL_LOCAL_MAC);
+               }
+
+               zvni->local_vtep_ip = vxl->vtep_ip;
+               zvni->vxlan_if = ifp;
+
+               /* Take further actions needed.
+                * Note that if we are here, there is a change of interest.
+                */
+               /* If down or not mapped to a bridge, we're done. */
+               if (!if_is_operative(ifp) || !zif->brslave_info.br_if)
+                       return 0;
+
+               /* Inform BGP, if there is a change of interest. */
+               if (chgflags
+                   & (ZEBRA_VXLIF_MASTER_CHANGE | ZEBRA_VXLIF_LOCAL_IP_CHANGE))
+                       zvni_send_add_to_client(zvni);
+
+               /* If there is a valid new master or a VLAN mapping change,
+                * read and populate local MACs and neighbors.
+                * Also, reinstall any remote MACs and neighbors
+                * for this VNI (based on new VLAN).
+                */
+               if (chgflags & ZEBRA_VXLIF_MASTER_CHANGE)
+                       zvni_read_mac_neigh(zvni, ifp);
+               else if (chgflags & ZEBRA_VXLIF_VLAN_CHANGE) {
+                       struct mac_walk_ctx m_wctx;
+                       struct neigh_walk_ctx n_wctx;
+
+                       zvni_read_mac_neigh(zvni, ifp);
+
+                       memset(&m_wctx, 0, sizeof(struct mac_walk_ctx));
+                       m_wctx.zvni = zvni;
+                       hash_iterate(zvni->mac_table,
+                                    zvni_install_mac_hash,
+                                    &m_wctx);
+
+                       memset(&n_wctx, 0, sizeof(struct neigh_walk_ctx));
+                       n_wctx.zvni = zvni;
+                       hash_iterate(zvni->neigh_table, zvni_install_neigh_hash,
+                                    &n_wctx);
+               }
+       }
 
        return 0;
 }
 
 /*
- * Handle VxLAN interface down - update BGP if required, and do
- * internal cleanup.
+ * Handle VxLAN interface add.
  */
-int zebra_vxlan_if_down(struct interface *ifp)
+int zebra_vxlan_if_add(struct interface *ifp)
 {
-       struct zebra_if *zif;
-       zebra_vni_t *zvni;
-       struct zebra_l2info_vxlan *vxl;
        vni_t vni;
+       struct zebra_if *zif = NULL;
+       struct zebra_l2info_vxlan *vxl = NULL;
+       zebra_vni_t *zvni = NULL;
+       zebra_l3vni_t *zl3vni = NULL;
 
        /* Check if EVPN is enabled. */
        if (!is_evpn_enabled())
@@ -4018,278 +6356,281 @@ int zebra_vxlan_if_down(struct interface *ifp)
        vxl = &zif->l2info.vxl;
        vni = vxl->vni;
 
-       if (IS_ZEBRA_DEBUG_VXLAN)
-               zlog_debug("Intf %s(%u) VNI %u is DOWN",
-                          ifp->name, ifp->ifindex, vni);
-
-       /* Locate hash entry; it is expected to exist. */
-       zvni = zvni_lookup(vni);
-       if (!zvni) {
-               zlog_err(
-                       "Failed to locate VNI hash at DOWN, IF %s(%u) VNI %u",
-                       ifp->name, ifp->ifindex, vni);
-               return -1;
-       }
-
-       assert(zvni->vxlan_if == ifp);
-
-       /* Delete this VNI from BGP. */
-       zvni_send_del_to_client(zvni->vni);
+       zl3vni = zl3vni_lookup(vni);
+       if (zl3vni) {
 
-       /* Free up all neighbors and MACs, if any. */
-       zvni_neigh_del_all(zvni, 1, 0, DEL_ALL_NEIGH);
-       zvni_mac_del_all(zvni, 1, 0, DEL_ALL_MAC);
+               /* process if-add for l3-vni*/
+               if (IS_ZEBRA_DEBUG_VXLAN)
+                       zlog_debug(
+                               "Add L3-VNI %u intf %s(%u) VLAN %u local IP %s master %u",
+                               vni, ifp->name, ifp->ifindex,
+                               vxl->access_vlan, inet_ntoa(vxl->vtep_ip),
+                               zif->brslave_info.bridge_ifindex);
 
-       /* Free up all remote VTEPs, if any. */
-       zvni_vtep_del_all(zvni, 1);
+               /* associate with vxlan_if */
+               zl3vni->local_vtep_ip = vxl->vtep_ip;
+               zl3vni->vxlan_if = ifp;
 
-       return 0;
-}
+               /* Associate with SVI, if any. We can associate with svi-if only
+                * after association with vxlan_if is complete */
+               zl3vni->svi_if = zl3vni_map_to_svi_if(zl3vni);
 
-/*
- * Handle VxLAN interface up - update BGP if required.
- */
-int zebra_vxlan_if_up(struct interface *ifp)
-{
-       struct zebra_if *zif;
-       zebra_vni_t *zvni;
-       struct zebra_l2info_vxlan *vxl;
-       vni_t vni;
+               if (is_l3vni_oper_up(zl3vni))
+                       zebra_vxlan_process_l3vni_oper_up(zl3vni);
+       } else {
 
-       /* Check if EVPN is enabled. */
-       if (!is_evpn_enabled())
-               return 0;
+               /* process if-add for l2-vni */
+               struct interface *vlan_if = NULL;
 
-       zif = ifp->info;
-       assert(zif);
-       vxl = &zif->l2info.vxl;
-       vni = vxl->vni;
+               /* Create or update VNI hash. */
+               zvni = zvni_lookup(vni);
+               if (!zvni) {
+                       zvni = zvni_add(vni);
+                       if (!zvni) {
+                               zlog_err(
+                                       "Failed to add VNI hash, IF %s(%u) VNI %u",
+                                       ifp->name, ifp->ifindex, vni);
+                               return -1;
+                       }
+               }
 
-       if (IS_ZEBRA_DEBUG_VXLAN)
-               zlog_debug("Intf %s(%u) VNI %u is UP",
-                          ifp->name, ifp->ifindex, vni);
+               zvni->local_vtep_ip = vxl->vtep_ip;
+               zvni->vxlan_if = ifp;
+               vlan_if = zvni_map_to_svi(vxl->access_vlan,
+                                         zif->brslave_info.br_if);
+               if (vlan_if) {
+                       zvni->vrf_id = vlan_if->vrf_id;
+                       zl3vni = zl3vni_from_vrf(vlan_if->vrf_id);
+                       if (zl3vni)
+                               listnode_add_sort(zl3vni->l2vnis, zvni);
+               }
 
-       /* Locate hash entry; it is expected to exist. */
-       zvni = zvni_lookup(vni);
-       if (!zvni) {
-               zlog_err(
-                       "Failed to locate VNI hash at UP, IF %s(%u) VNI %u",
-                       ifp->name, ifp->ifindex, vni);
-               return -1;
-       }
+               if (IS_ZEBRA_DEBUG_VXLAN)
+                       zlog_debug(
+                               "Add L2-VNI %u VRF %s intf %s(%u) VLAN %u local IP %s master %u",
+                               vni,
+                               vlan_if ? vrf_id_to_name(vlan_if->vrf_id) :
+                                       "Default",
+                               ifp->name, ifp->ifindex,
+                               vxl->access_vlan, inet_ntoa(vxl->vtep_ip),
+                               zif->brslave_info.bridge_ifindex);
 
-       assert(zvni->vxlan_if == ifp);
+               /* If down or not mapped to a bridge, we're done. */
+               if (!if_is_operative(ifp) || !zif->brslave_info.br_if)
+                       return 0;
 
-       /* If part of a bridge, inform BGP about this VNI. */
-       /* Also, read and populate local MACs and neighbors. */
-       if (zif->brslave_info.br_if) {
+               /* Inform BGP */
                zvni_send_add_to_client(zvni);
+
+               /* Read and populate local MACs and neighbors */
                zvni_read_mac_neigh(zvni, ifp);
        }
 
        return 0;
 }
 
-/*
- * Handle VxLAN interface delete. Locate and remove entry in hash table
- * and update BGP, if required.
- */
-int zebra_vxlan_if_del(struct interface *ifp)
+int zebra_vxlan_process_vrf_vni_cmd(struct zebra_vrf *zvrf,
+                                   vni_t vni,
+                                   char *err, int err_str_sz,
+                                   int add)
 {
-       struct zebra_if *zif;
-       zebra_vni_t *zvni;
-       struct zebra_l2info_vxlan *vxl;
-       vni_t vni;
-
-       /* Check if EVPN is enabled. */
-       if (!is_evpn_enabled())
-               return 0;
+       zebra_l3vni_t *zl3vni = NULL;
+       struct zebra_vrf *zvrf_default = NULL;
 
-       zif = ifp->info;
-       assert(zif);
-       vxl = &zif->l2info.vxl;
-       vni = vxl->vni;
+       zvrf_default = zebra_vrf_lookup_by_id(VRF_DEFAULT);
+       if (!zvrf_default)
+               return -1;
 
        if (IS_ZEBRA_DEBUG_VXLAN)
-               zlog_debug("Del VNI %u intf %s(%u)",
-                          vni, ifp->name, ifp->ifindex);
+               zlog_debug("vrf %s vni %u %s",
+                          zvrf_name(zvrf),
+                          vni,
+                          add ? "ADD" : "DEL");
 
-       /* Locate hash entry; it is expected to exist. */
-       zvni = zvni_lookup(vni);
-       if (!zvni) {
-               zlog_err(
-                       "Failed to locate VNI hash at del, IF %s(%u) VNI %u",
-                       ifp->name, ifp->ifindex, vni);
-               return 0;
-       }
+       if (add) {
 
-       /* Delete VNI from BGP. */
-       zvni_send_del_to_client(zvni->vni);
+               zebra_vxlan_handle_vni_transition(zvrf, vni, add);
 
-       /* Free up all neighbors and MAC, if any. */
-       zvni_neigh_del_all(zvni, 0, 0, DEL_ALL_NEIGH);
-       zvni_mac_del_all(zvni, 0, 0, DEL_ALL_MAC);
+               /* check if the vni is already present under zvrf */
+               if (zvrf->l3vni) {
+                       snprintf(err, err_str_sz,
+                                "VNI is already configured under the vrf");
+                       return -1;
+               }
 
-       /* Free up all remote VTEPs, if any. */
-       zvni_vtep_del_all(zvni, 0);
+               /* check if this VNI is already present in the system */
+               zl3vni = zl3vni_lookup(vni);
+               if (zl3vni) {
+                       snprintf(err, err_str_sz,
+                                "VNI is already configured as L3-VNI");
+                       return -1;
+               }
 
-       /* Delete the hash entry. */
-       if (zvni_del(zvni)) {
-               zlog_err("Failed to del VNI hash %p, IF %s(%u) VNI %u",
-                        zvni, ifp->name, ifp->ifindex, zvni->vni);
-               return -1;
-       }
+               /* add the L3-VNI to the global table */
+               zl3vni = zl3vni_add(vni, zvrf_id(zvrf));
+               if (!zl3vni) {
+                       snprintf(err, err_str_sz,
+                                "Could not add L3-VNI");
+                       return -1;
+               }
 
-       return 0;
-}
+               /* associate the vrf with vni */
+               zvrf->l3vni = vni;
 
-/*
- * Handle VxLAN interface update - change to tunnel IP, master or VLAN.
- */
-int zebra_vxlan_if_update(struct interface *ifp, u_int16_t chgflags)
-{
-       struct zebra_if *zif;
-       zebra_vni_t *zvni;
-       struct zebra_l2info_vxlan *vxl;
-       vni_t vni;
+               /* associate with vxlan-intf;
+                * we need to associate with the vxlan-intf first
+                */
+               zl3vni->vxlan_if = zl3vni_map_to_vxlan_if(zl3vni);
 
-       /* Check if EVPN is enabled. */
-       if (!is_evpn_enabled())
-               return 0;
+               /* associate with corresponding SVI interface, we can associate
+                * with svi-if only after vxlan interface association is
+                * complete
+                */
+               zl3vni->svi_if = zl3vni_map_to_svi_if(zl3vni);
 
-       zif = ifp->info;
-       assert(zif);
-       vxl = &zif->l2info.vxl;
-       vni = vxl->vni;
+               /* formulate l2vni list */
+               hash_iterate(zvrf_default->vni_table,
+                            zvni_add_to_l3vni_list, zl3vni);
 
-       /* Update VNI hash. */
-       zvni = zvni_lookup(vni);
-       if (!zvni) {
-               zlog_err(
-                       "Failed to find VNI hash on update, IF %s(%u) VNI %u",
-                       ifp->name, ifp->ifindex, vni);
-               return -1;
-       }
+               if (is_l3vni_oper_up(zl3vni))
+                       zebra_vxlan_process_l3vni_oper_up(zl3vni);
 
-       if (IS_ZEBRA_DEBUG_VXLAN)
-               zlog_debug(
-                       "Update VNI %u intf %s(%u) VLAN %u local IP %s "
-                       "master %u chg 0x%x",
-                       vni, ifp->name, ifp->ifindex,
-                       vxl->access_vlan, inet_ntoa(vxl->vtep_ip),
-                       zif->brslave_info.bridge_ifindex, chgflags);
-
-       /* Removed from bridge? Cleanup and return */
-       if ((chgflags & ZEBRA_VXLIF_MASTER_CHANGE)
-           && (zif->brslave_info.bridge_ifindex == IFINDEX_INTERNAL)) {
-               /* Delete from client, remove all remote VTEPs */
-               /* Also, free up all MACs and neighbors. */
-               zvni_send_del_to_client(zvni->vni);
-               zvni_neigh_del_all(zvni, 1, 0, DEL_ALL_NEIGH);
-               zvni_mac_del_all(zvni, 1, 0, DEL_ALL_MAC);
-               zvni_vtep_del_all(zvni, 1);
-               return 0;
-       }
+       } else {
+               zl3vni = zl3vni_lookup(vni);
+               if (!zl3vni) {
+                       snprintf(err, err_str_sz, "VNI doesn't exist");
+                       return -1;
+               }
 
-       /* Handle other changes. */
-       if (chgflags & ZEBRA_VXLIF_VLAN_CHANGE) {
-               /* Remove all existing local neighbors and MACs for this VNI
-                * (including from BGP)
-                */
-               zvni_neigh_del_all(zvni, 0, 1, DEL_LOCAL_MAC);
-               zvni_mac_del_all(zvni, 0, 1, DEL_LOCAL_MAC);
+               zebra_vxlan_process_l3vni_oper_down(zl3vni);
+
+               /* delete and uninstall all rmacs */
+               hash_iterate(zl3vni->rmac_table,
+                            zl3vni_del_rmac_hash_entry,
+                            zl3vni);
+
+               /* delete and uninstall all next-hops */
+               hash_iterate(zl3vni->nh_table,
+                            zl3vni_del_nh_hash_entry,
+                            zl3vni);
+
+               zvrf->l3vni = 0;
+               zl3vni_del(zl3vni);
+
+               zebra_vxlan_handle_vni_transition(zvrf, vni, add);
        }
+       return 0;
+}
 
-       zvni->local_vtep_ip = vxl->vtep_ip;
-       zvni->vxlan_if = ifp;
+int zebra_vxlan_vrf_enable(struct zebra_vrf *zvrf)
+{
+       zebra_l3vni_t *zl3vni = NULL;
 
-       /* Take further actions needed. Note that if we are here, there is a
-        * change of interest.
-        */
-       /* If down or not mapped to a bridge, we're done. */
-       if (!if_is_operative(ifp) || !zif->brslave_info.br_if)
+       if (zvrf->l3vni)
+               zl3vni = zl3vni_lookup(zvrf->l3vni);
+       if (!zl3vni)
                return 0;
 
-       /* Inform BGP, if there is a change of interest. */
-       if (chgflags
-           & (ZEBRA_VXLIF_MASTER_CHANGE | ZEBRA_VXLIF_LOCAL_IP_CHANGE))
-               zvni_send_add_to_client(zvni);
+       zl3vni->vrf_id = zvrf_id(zvrf);
+       if (is_l3vni_oper_up(zl3vni))
+               zebra_vxlan_process_l3vni_oper_up(zl3vni);
+       return 0;
+}
 
-       /* If there is a valid new master or a VLAN mapping change, read and
-        * populate local MACs and neighbors. Also, reinstall any remote MACs
-        * and neighbors for this VNI (based on new VLAN).
-        */
-       if (chgflags & ZEBRA_VXLIF_MASTER_CHANGE)
-               zvni_read_mac_neigh(zvni, ifp);
-       else if (chgflags & ZEBRA_VXLIF_VLAN_CHANGE) {
-               struct mac_walk_ctx m_wctx;
-               struct neigh_walk_ctx n_wctx;
+int zebra_vxlan_vrf_disable(struct zebra_vrf *zvrf)
+{
+       zebra_l3vni_t *zl3vni = NULL;
 
-               zvni_read_mac_neigh(zvni, ifp);
+       if (zvrf->l3vni)
+               zl3vni = zl3vni_lookup(zvrf->l3vni);
+       if (!zl3vni)
+               return 0;
 
-               memset(&m_wctx, 0, sizeof(struct mac_walk_ctx));
-               m_wctx.zvni = zvni;
-               hash_iterate(zvni->mac_table, zvni_install_mac_hash, &m_wctx);
+       zl3vni->vrf_id = VRF_UNKNOWN;
+       zebra_vxlan_process_l3vni_oper_down(zl3vni);
+       return 0;
+}
 
-               memset(&n_wctx, 0, sizeof(struct neigh_walk_ctx));
-               n_wctx.zvni = zvni;
-               hash_iterate(zvni->neigh_table, zvni_install_neigh_hash,
-                            &n_wctx);
-       }
+int zebra_vxlan_vrf_delete(struct zebra_vrf *zvrf)
+{
+       zebra_l3vni_t *zl3vni = NULL;
+       vni_t vni;
+
+       if (zvrf->l3vni)
+               zl3vni = zl3vni_lookup(zvrf->l3vni);
+       if (!zl3vni)
+               return 0;
+
+       vni = zl3vni->vni;
+       zl3vni_del(zl3vni);
+       zebra_vxlan_handle_vni_transition(zvrf, vni, 0);
 
        return 0;
 }
 
 /*
- * Handle VxLAN interface add.
+ * Handle message from client to enable/disable advertisement of g/w macip
+ * routes
  */
-int zebra_vxlan_if_add(struct interface *ifp)
+int zebra_vxlan_advertise_subnet(struct zserv *client, u_short length,
+                                struct zebra_vrf *zvrf)
 {
-       struct zebra_if *zif;
-       zebra_vni_t *zvni;
-       struct zebra_l2info_vxlan *vxl;
-       vni_t vni;
+       struct stream *s;
+       int advertise;
+       vni_t vni = 0;
+       zebra_vni_t *zvni = NULL;
+       struct interface *ifp = NULL;
+       struct zebra_if *zif = NULL;
+       struct zebra_l2info_vxlan zl2_info;
+       struct interface *vlan_if = NULL;
 
-       /* Check if EVPN is enabled. */
-       if (!is_evpn_enabled())
+       if (zvrf_id(zvrf) != VRF_DEFAULT) {
+               zlog_err("EVPN GW-MACIP Adv for non-default VRF %u",
+                        zvrf_id(zvrf));
+               return -1;
+       }
+
+       s = client->ibuf;
+       advertise = stream_getc(s);
+       vni = stream_get3(s);
+
+       zvni = zvni_lookup(vni);
+       if (!zvni)
                return 0;
 
-       zif = ifp->info;
-       assert(zif);
-       vxl = &zif->l2info.vxl;
-       vni = vxl->vni;
+       if (zvni->advertise_subnet == advertise)
+               return 0;
 
        if (IS_ZEBRA_DEBUG_VXLAN)
                zlog_debug(
-                       "Add VNI %u intf %s(%u) VLAN %u local IP %s master %u",
-                       vni, ifp->name, ifp->ifindex,
-                       vxl->access_vlan, inet_ntoa(vxl->vtep_ip),
-                       zif->brslave_info.bridge_ifindex);
+                       "EVPN subnet Adv %s on VNI %d , currently %s",
+                       advertise ? "enabled" : "disabled", vni,
+                       zvni->advertise_subnet ? "enabled" : "disabled");
 
-       /* Create or update VNI hash. */
-       zvni = zvni_lookup(vni);
-       if (!zvni) {
-               zvni = zvni_add(vni);
-               if (!zvni) {
-                       zlog_err(
-                               "Failed to add VNI hash, IF %s(%u) VNI %u",
-                               ifp->name, ifp->ifindex, vni);
-                       return -1;
-               }
-       }
 
-       zvni->local_vtep_ip = vxl->vtep_ip;
-       zvni->vxlan_if = ifp;
+       zvni->advertise_subnet = advertise;
+
+       ifp = zvni->vxlan_if;
+       if (!ifp)
+               return 0;
+
+       zif = ifp->info;
 
        /* If down or not mapped to a bridge, we're done. */
        if (!if_is_operative(ifp) || !zif->brslave_info.br_if)
                return 0;
 
-       /* Inform BGP */
-       zvni_send_add_to_client(zvni);
+       zl2_info = zif->l2info.vxl;
+
+       vlan_if = zvni_map_to_svi(zl2_info.access_vlan,
+                                 zif->brslave_info.br_if);
+       if (!vlan_if)
+               return 0;
 
-       /* Read and populate local MACs and neighbors */
-       zvni_read_mac_neigh(zvni, ifp);
+       if (zvni->advertise_subnet)
+               zvni_advertise_subnet(zvni, vlan_if, 1);
+       else
+               zvni_advertise_subnet(zvni, vlan_if, 0);
 
        return 0;
 }
@@ -4410,8 +6751,9 @@ stream_failure:
 int zebra_vxlan_advertise_all_vni(struct zserv *client,
                                  u_short length, struct zebra_vrf *zvrf)
 {
-       struct stream *s;
-       int advertise;
+       struct stream *s = NULL;
+       int advertise = 0;
+       struct zebra_ns *zns = NULL;
 
        if (zvrf_id(zvrf) != VRF_DEFAULT) {
                zlog_err("EVPN VNI Adv for non-default VRF %u",
@@ -4449,6 +6791,13 @@ int zebra_vxlan_advertise_all_vni(struct zserv *client,
                 * kernel and free entries.
                 */
                hash_iterate(zvrf->vni_table, zvni_cleanup_all, zvrf);
+
+               /* cleanup all l3vnis */
+               zns = zebra_ns_lookup(NS_DEFAULT);
+               if (!zns)
+                       return -1;
+
+               hash_iterate(zns->l3vni_table, zl3vni_cleanup_all, NULL);
        }
 
 stream_failure:
@@ -4467,6 +6816,14 @@ void zebra_vxlan_init_tables(struct zebra_vrf *zvrf)
                                      "Zebra VRF VNI Table");
 }
 
+/* Cleanup VNI info, but don't free the table. */
+void zebra_vxlan_cleanup_tables(struct zebra_vrf *zvrf)
+{
+       if (!zvrf)
+               return;
+       hash_iterate(zvrf->vni_table, zvni_cleanup_all, zvrf);
+}
+
 /* Close all VNI handling */
 void zebra_vxlan_close_tables(struct zebra_vrf *zvrf)
 {
@@ -4475,3 +6832,28 @@ void zebra_vxlan_close_tables(struct zebra_vrf *zvrf)
        hash_iterate(zvrf->vni_table, zvni_cleanup_all, zvrf);
        hash_free(zvrf->vni_table);
 }
+
+/* init the l3vni table */
+void zebra_vxlan_ns_init(struct zebra_ns *zns)
+{
+       zns->l3vni_table = hash_create(l3vni_hash_keymake, l3vni_hash_cmp,
+                                      "Zebra VRF L3 VNI table");
+}
+
+/* free l3vni table */
+void zebra_vxlan_ns_disable(struct zebra_ns *zns)
+{
+       hash_free(zns->l3vni_table);
+}
+
+/* get the l3vni svi ifindex */
+ifindex_t get_l3vni_svi_ifindex(vrf_id_t vrf_id)
+{
+       zebra_l3vni_t *zl3vni = NULL;
+
+       zl3vni = zl3vni_from_vrf(vrf_id);
+       if (!zl3vni || !is_l3vni_oper_up(zl3vni))
+               return 0;
+
+       return zl3vni->svi_if->ifindex;
+}
index 290d19bcf3302d2028fd6a574f07cf7d85c10fe5..d9801a8b6059d4bcbeec9f569aa249a8781653e2 100644 (file)
@@ -31,6 +31,7 @@
 #include "vlan.h"
 #include "vxlan.h"
 
+#include "lib/json.h"
 #include "zebra/zebra_vrf.h"
 
 /* Is EVPN enabled? */
@@ -51,6 +52,17 @@ is_evpn_enabled()
 
 #define VNI_STR_LEN 32
 
+extern ifindex_t get_l3vni_svi_ifindex(vrf_id_t vrf_id);
+extern int zebra_vxlan_vrf_delete(struct zebra_vrf *zvrf);
+extern int zebra_vxlan_vrf_enable(struct zebra_vrf *zvrf);
+extern int zebra_vxlan_vrf_disable(struct zebra_vrf *zvrf);
+extern int zebra_vxlan_vrf_delete(struct zebra_vrf *zvrf);
+extern void zebra_vxlan_print_specific_nh_l3vni(struct vty *vty, vni_t l3vni,
+                                               struct ipaddr *ip, u_char uj);
+extern void zebra_vxlan_print_evpn(struct vty *vty, u_char uj);
+extern void zebra_vxlan_print_specific_rmac_l3vni(struct vty *vty, vni_t l3vni,
+                                                 struct ethaddr *rmac,
+                                                 u_char use_json);
 extern void zebra_vxlan_print_macs_vni(struct vty *vty, struct zebra_vrf *zvrf,
                                       vni_t vni, u_char use_json);
 extern void zebra_vxlan_print_macs_all_vni(struct vty *vty,
@@ -84,7 +96,16 @@ extern void zebra_vxlan_print_vni(struct vty *vty, struct zebra_vrf *zvrf,
                                  vni_t vni, u_char use_json);
 extern void zebra_vxlan_print_vnis(struct vty *vty, struct zebra_vrf *zvrf,
                                   u_char use_json);
-
+extern void zebra_vxlan_print_rmacs_l3vni(struct vty *vty, vni_t vni, u_char
+                                         use_json);
+extern void zebra_vxlan_print_rmacs_all_l3vni(struct vty *vty, u_char use_json);
+extern void zebra_vxlan_print_nh_l3vni(struct vty *vty, vni_t vni, u_char
+                                      use_json);
+extern void zebra_vxlan_print_nh_all_l3vni(struct vty *vty, u_char use_json);
+extern void zebra_vxlan_print_l3vni(struct vty *vty, vni_t vni,
+                                   u_char use_json);
+extern void zebra_vxlan_print_vrf_vni(struct vty *vty, struct zebra_vrf *zvrf,
+                                     json_object *json_vrfs);
 extern int zebra_vxlan_add_del_gw_macip(struct interface *ifp, struct prefix *p,
                                        int add);
 extern int zebra_vxlan_svi_up(struct interface *ifp, struct interface *link_if);
@@ -123,13 +144,29 @@ extern int zebra_vxlan_remote_vtep_add(struct zserv *client,
                                       u_short length, struct zebra_vrf *zvrf);
 extern int zebra_vxlan_remote_vtep_del(struct zserv *client,
                                       u_short length, struct zebra_vrf *zvrf);
+extern int zebra_vxlan_advertise_subnet(struct zserv *client, u_short length,
+                                       struct zebra_vrf *zvrf);
 extern int zebra_vxlan_advertise_gw_macip(struct zserv *client,
                                          u_short length,
                                          struct zebra_vrf *zvrf);
 extern int zebra_vxlan_advertise_all_vni(struct zserv *client,
                                         u_short length,
                                         struct zebra_vrf *zvrf);
+extern int zebra_vxlan_process_vrf_vni_cmd(struct zebra_vrf *zvrf, vni_t vni,
+                                          char *err,
+                                          int err_str_sz, int add);
 extern void zebra_vxlan_init_tables(struct zebra_vrf *zvrf);
 extern void zebra_vxlan_close_tables(struct zebra_vrf *);
+extern void zebra_vxlan_cleanup_tables(struct zebra_vrf *);
+extern void zebra_vxlan_ns_init(struct zebra_ns *zns);
+extern void zebra_vxlan_ns_disable(struct zebra_ns *zns);
+extern void zebra_vxlan_evpn_vrf_route_add(vrf_id_t vrf_id,
+                                          struct ethaddr *rmac,
+                                          struct ipaddr *ip,
+                                          struct prefix *host_prefix);
+extern void zebra_vxlan_evpn_vrf_route_del(vrf_id_t vrf_id,
+                                          struct ethaddr *rmac,
+                                          struct ipaddr *vtep_ip,
+                                          struct prefix *host_prefix);
 
 #endif /* _ZEBRA_VXLAN_H */
index bbed5ddb05e925aee1c5faa426488142ea8d1ea8..0eb880e848abd8539efff69079237fd18e79a2ff 100644 (file)
@@ -83,6 +83,30 @@ void zebra_vxlan_print_vnis(struct vty *vty, struct zebra_vrf *zvrf)
 {
 }
 
+void zebra_vxlan_print_evpn(struct vty *vty, u_char uj)
+{
+}
+
+void zebra_vxlan_print_rmacs_l3vni(struct vty*, vni_t, u_char)
+{
+}
+
+void zebra_vxlan_print_rmacs_all_l3vni(struct vty*, u_char)
+{
+}
+
+void zebra_vxlan_print_nh_l3vni(struct vty*, vni_t, u_char)
+{
+}
+
+void zebra_vxlan_print_nh_all_l3vni(struct vty*, u_char)
+{
+}
+
+void zebra_vxlan_print_l3vni(struct vty *vty, vni_t vni)
+{
+}
+
 int zebra_vxlan_svi_up(struct interface *ifp, struct interface *link_if)
 {
        return 0;
@@ -183,3 +207,7 @@ void zebra_vxlan_init_tables(struct zebra_vrf *zvrf)
 void zebra_vxlan_close_tables(struct zebra_vrf *zvrf)
 {
 }
+
+void zebra_vxlan_cleanup_tables(struct zebra_vrf *zvrf)
+{
+}
index fa7d0e94578f14e57e4ed171db6bcef987142fbc..8d34b3e2f12bbc613b51ec50231fc1b8f4322af8 100644 (file)
 
 #include "if.h"
 #include "linklist.h"
+#include "zebra_vxlan.h"
+
+#define ERR_STR_SZ 256
 
 /* definitions */
 typedef struct zebra_vni_t_ zebra_vni_t;
 typedef struct zebra_vtep_t_ zebra_vtep_t;
 typedef struct zebra_mac_t_ zebra_mac_t;
 typedef struct zebra_neigh_t_ zebra_neigh_t;
+typedef struct zebra_l3vni_t_ zebra_l3vni_t;
 
 /*
  * VTEP info
@@ -66,6 +70,9 @@ struct zebra_vni_t_ {
        /* Flag for advertising gw macip */
        u_int8_t advertise_gw_macip;
 
+       /* Flag for advertising gw macip */
+       u_int8_t advertise_subnet;
+
        /* Corresponding VxLAN interface. */
        struct interface *vxlan_if;
 
@@ -75,6 +82,9 @@ struct zebra_vni_t_ {
        /* Local IP */
        struct in_addr local_vtep_ip;
 
+       /* tenant VRF, if any */
+       vrf_id_t vrf_id;
+
        /* List of local or remote MAC */
        struct hash *mac_table;
 
@@ -82,6 +92,128 @@ struct zebra_vni_t_ {
        struct hash *neigh_table;
 };
 
+/* L3 VNI hash table */
+struct zebra_l3vni_t_ {
+
+       /* VNI key */
+       vni_t vni;
+
+       /* vrf_id */
+       vrf_id_t vrf_id;
+
+       /* Local IP */
+       struct in_addr local_vtep_ip;
+
+       /* kernel interface for l3vni */
+       struct interface *vxlan_if;
+
+       /* SVI interface corresponding to the l3vni */
+       struct interface *svi_if;
+
+       /* list of L2 VNIs associated with the L3 VNI */
+       struct list *l2vnis;
+
+       /* list of remote router-macs */
+       struct hash *rmac_table;
+
+       /* list of remote vtep-ip neigh */
+       struct hash *nh_table;
+};
+
+/* get the vx-intf name for l3vni */
+static inline const char *zl3vni_vxlan_if_name(zebra_l3vni_t *zl3vni)
+{
+       return zl3vni->vxlan_if ? zl3vni->vxlan_if->name : "None";
+}
+
+/* get the svi intf name for l3vni */
+static inline const char *zl3vni_svi_if_name(zebra_l3vni_t *zl3vni)
+{
+       return zl3vni->svi_if ? zl3vni->svi_if->name : "None";
+}
+
+/* get the vrf name for l3vni */
+static inline const char *zl3vni_vrf_name(zebra_l3vni_t *zl3vni)
+{
+       return vrf_id_to_name(zl3vni->vrf_id);
+}
+
+/* get the rmac string */
+static inline const char *zl3vni_rmac2str(zebra_l3vni_t *zl3vni, char *buf,
+                                         int size)
+{
+       char *ptr;
+
+       if (!buf)
+               ptr = (char *)XMALLOC(MTYPE_TMP,
+                                     ETHER_ADDR_STRLEN * sizeof(char));
+       else {
+               assert(size >= ETHER_ADDR_STRLEN);
+               ptr = buf;
+       }
+
+       if (zl3vni->svi_if)
+               snprintf(ptr, (ETHER_ADDR_STRLEN),
+                        "%02x:%02x:%02x:%02x:%02x:%02x",
+                        (uint8_t)zl3vni->svi_if->hw_addr[0],
+                        (uint8_t)zl3vni->svi_if->hw_addr[1],
+                        (uint8_t)zl3vni->svi_if->hw_addr[2],
+                        (uint8_t)zl3vni->svi_if->hw_addr[3],
+                        (uint8_t)zl3vni->svi_if->hw_addr[4],
+                        (uint8_t)zl3vni->svi_if->hw_addr[5]);
+       else
+               snprintf(ptr, ETHER_ADDR_STRLEN, "None");
+
+       return ptr;
+}
+
+/*
+ * l3-vni is oper up when:
+ * 0. if EVPN is enabled (advertise-all-vni cfged)
+ * 1. it is associated to a vxlan-intf
+ * 2. Associated vxlan-intf is oper up
+ * 3. it is associated to an SVI
+ * 4. associated SVI is oper up
+ */
+static inline int is_l3vni_oper_up(zebra_l3vni_t *zl3vni)
+{
+       return (is_evpn_enabled() && zl3vni &&
+               (zl3vni->vrf_id != VRF_UNKNOWN) &&
+               zl3vni->vxlan_if && if_is_operative(zl3vni->vxlan_if) &&
+               zl3vni->svi_if && if_is_operative(zl3vni->svi_if));
+}
+
+static inline const char *zl3vni_state2str(zebra_l3vni_t *zl3vni)
+{
+       if (!zl3vni)
+               return NULL;
+
+       if (is_l3vni_oper_up(zl3vni))
+               return "Up";
+       else
+               return "Down";
+
+       return NULL;
+}
+
+static inline vrf_id_t zl3vni_vrf_id(zebra_l3vni_t *zl3vni)
+{
+       return zl3vni->vrf_id;
+}
+
+static inline void zl3vni_get_rmac(zebra_l3vni_t *zl3vni,
+                                  struct ethaddr *rmac)
+{
+       if (!zl3vni)
+               return;
+
+       if (!is_l3vni_oper_up(zl3vni))
+               return;
+
+       if (zl3vni->svi_if && if_is_operative(zl3vni->svi_if))
+               memcpy(rmac->octet, zl3vni->svi_if->hw_addr, ETH_ALEN);
+}
+
 /*
  * MAC hash table.
  *
@@ -103,6 +235,8 @@ struct zebra_mac_t_ {
 #define ZEBRA_MAC_REMOTE  0x02
 #define ZEBRA_MAC_AUTO    0x04  /* Auto created for neighbor. */
 #define ZEBRA_MAC_STICKY  0x08  /* Static MAC */
+#define ZEBRA_MAC_REMOTE_RMAC  0x10  /* remote router mac */
+#define ZEBRA_MAC_DEF_GW  0x20
 
        /* Local or remote info. */
        union {
@@ -116,6 +250,9 @@ struct zebra_mac_t_ {
 
        /* List of neigh associated with this mac */
        struct list *neigh_list;
+
+       /* list of hosts pointing to this remote RMAC */
+       struct list *host_list;
 };
 
 /*
@@ -141,6 +278,11 @@ struct mac_walk_ctx {
        struct json_object *json; /* Used for JSON Output */
 };
 
+struct rmac_walk_ctx {
+       struct vty *vty;
+       struct json_object *json;
+};
+
 enum zebra_neigh_state { ZEBRA_NEIGH_INACTIVE = 0, ZEBRA_NEIGH_ACTIVE = 1 };
 
 #define IS_ZEBRA_NEIGH_ACTIVE(n) n->state == ZEBRA_NEIGH_ACTIVE
@@ -175,11 +317,16 @@ struct zebra_neigh_t_ {
        u_int32_t flags;
 #define ZEBRA_NEIGH_LOCAL     0x01
 #define ZEBRA_NEIGH_REMOTE    0x02
+#define ZEBRA_NEIGH_REMOTE_NH    0x04 /* neigh entry for remote vtep */
+#define ZEBRA_NEIGH_DEF_GW    0x08
 
        enum zebra_neigh_state state;
 
        /* Remote VTEP IP - applicable only for remote neighbors. */
        struct in_addr r_vtep_ip;
+
+       /* list of hosts pointing to this remote NH entry */
+       struct list *host_list;
 };
 
 /*
@@ -206,4 +353,18 @@ struct neigh_walk_ctx {
        struct json_object *json; /* Used for JSON Output */
 };
 
+/* context for neigh hash walk - update l3vni and rmac */
+struct neigh_l3info_walk_ctx {
+
+       zebra_vni_t *zvni;
+       zebra_l3vni_t *zl3vni;
+       int add;
+};
+
+struct nh_walk_ctx {
+
+       struct vty *vty;
+       struct json_object *json;
+};
+
 #endif /* _ZEBRA_VXLAN_PRIVATE_H */
index 684ba49e7dc2732f038a92ca90bf7a893c5e961b..b3b1fa79e9ba89880ba1bcecf965cdbbad1fa398 100644 (file)
@@ -149,16 +149,6 @@ int zebra_server_send_message(struct zserv *client)
        return 0;
 }
 
-void zserv_create_header(struct stream *s, uint16_t cmd, vrf_id_t vrf_id)
-{
-       /* length placeholder, caller can update */
-       stream_putw(s, ZEBRA_HEADER_SIZE);
-       stream_putc(s, ZEBRA_HEADER_MARKER);
-       stream_putc(s, ZSERV_VERSION);
-       stream_putw(s, vrf_id);
-       stream_putw(s, cmd);
-}
-
 static void zserv_encode_interface(struct stream *s, struct interface *ifp)
 {
        /* Interface information. */
@@ -221,7 +211,7 @@ int zsend_interface_add(struct zserv *client, struct interface *ifp)
        s = client->obuf;
        stream_reset(s);
 
-       zserv_create_header(s, ZEBRA_INTERFACE_ADD, ifp->vrf_id);
+       zclient_create_header(s, ZEBRA_INTERFACE_ADD, ifp->vrf_id);
        zserv_encode_interface(s, ifp);
 
        client->ifadd_cnt++;
@@ -236,7 +226,7 @@ int zsend_interface_delete(struct zserv *client, struct interface *ifp)
        s = client->obuf;
        stream_reset(s);
 
-       zserv_create_header(s, ZEBRA_INTERFACE_DELETE, ifp->vrf_id);
+       zclient_create_header(s, ZEBRA_INTERFACE_DELETE, ifp->vrf_id);
        zserv_encode_interface(s, ifp);
 
        client->ifdel_cnt++;
@@ -250,7 +240,7 @@ int zsend_vrf_add(struct zserv *client, struct zebra_vrf *zvrf)
        s = client->obuf;
        stream_reset(s);
 
-       zserv_create_header(s, ZEBRA_VRF_ADD, zvrf_id(zvrf));
+       zclient_create_header(s, ZEBRA_VRF_ADD, zvrf_id(zvrf));
        zserv_encode_vrf(s, zvrf);
 
        client->vrfadd_cnt++;
@@ -265,7 +255,7 @@ int zsend_vrf_delete(struct zserv *client, struct zebra_vrf *zvrf)
        s = client->obuf;
        stream_reset(s);
 
-       zserv_create_header(s, ZEBRA_VRF_DELETE, zvrf_id(zvrf));
+       zclient_create_header(s, ZEBRA_VRF_DELETE, zvrf_id(zvrf));
        zserv_encode_vrf(s, zvrf);
 
        client->vrfdel_cnt++;
@@ -285,7 +275,7 @@ int zsend_interface_link_params(struct zserv *client, struct interface *ifp)
        s = client->obuf;
        stream_reset(s);
 
-       zserv_create_header(s, ZEBRA_INTERFACE_LINK_PARAMS, ifp->vrf_id);
+       zclient_create_header(s, ZEBRA_INTERFACE_LINK_PARAMS, ifp->vrf_id);
 
        /* Add Interface Index */
        stream_putl(s, ifp->ifindex);
@@ -348,7 +338,7 @@ int zsend_interface_address(int cmd, struct zserv *client,
        s = client->obuf;
        stream_reset(s);
 
-       zserv_create_header(s, cmd, ifp->vrf_id);
+       zclient_create_header(s, cmd, ifp->vrf_id);
        stream_putl(s, ifp->ifindex);
 
        /* Interface address flag. */
@@ -393,7 +383,7 @@ static int zsend_interface_nbr_address(int cmd, struct zserv *client,
        s = client->obuf;
        stream_reset(s);
 
-       zserv_create_header(s, cmd, ifp->vrf_id);
+       zclient_create_header(s, cmd, ifp->vrf_id);
        stream_putl(s, ifp->ifindex);
 
        /* Prefix information. */
@@ -504,11 +494,11 @@ int zsend_interface_vrf_update(struct zserv *client, struct interface *ifp,
        s = client->obuf;
        stream_reset(s);
 
-       zserv_create_header(s, ZEBRA_INTERFACE_VRF_UPDATE, ifp->vrf_id);
+       zclient_create_header(s, ZEBRA_INTERFACE_VRF_UPDATE, ifp->vrf_id);
 
        /* Fill in the ifIndex of the interface and its new VRF (id) */
        stream_putl(s, ifp->ifindex);
-       stream_putw(s, vrf_id);
+       stream_putl(s, vrf_id);
 
        /* Write packet size. */
        stream_putw_at(s, 0, stream_get_endp(s));
@@ -581,7 +571,7 @@ int zsend_interface_update(int cmd, struct zserv *client, struct interface *ifp)
        s = client->obuf;
        stream_reset(s);
 
-       zserv_create_header(s, cmd, ifp->vrf_id);
+       zclient_create_header(s, cmd, ifp->vrf_id);
        zserv_encode_interface(s, ifp);
 
        if (cmd == ZEBRA_INTERFACE_UP)
@@ -623,6 +613,7 @@ int zsend_redistribute_route(int cmd, struct zserv *client, struct prefix *p,
                        continue;
 
                api_nh = &api.nexthops[count];
+               api_nh->vrf_id = nexthop->vrf_id;
                api_nh->type = nexthop->type;
                switch (nexthop->type) {
                case NEXTHOP_TYPE_BLACKHOLE:
@@ -957,7 +948,7 @@ static int zsend_ipv4_nexthop_lookup_mrib(struct zserv *client,
        stream_reset(s);
 
        /* Fill in result. */
-       zserv_create_header(s, ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB, zvrf_id(zvrf));
+       zclient_create_header(s, ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB, zvrf_id(zvrf));
        stream_put_in_addr(s, &addr);
 
        if (re) {
@@ -1009,7 +1000,7 @@ int zsend_route_notify_owner(u_char proto, u_short instance,
        s = client->obuf;
        stream_reset(s);
 
-       zserv_create_header(s, ZEBRA_ROUTE_NOTIFY_OWNER, vrf_id);
+       zclient_create_header(s, ZEBRA_ROUTE_NOTIFY_OWNER, vrf_id);
 
        stream_put(s, &note, sizeof(note));
 
@@ -1039,7 +1030,7 @@ int zsend_router_id_update(struct zserv *client, struct prefix *p,
        stream_reset(s);
 
        /* Message type. */
-       zserv_create_header(s, ZEBRA_ROUTER_ID_UPDATE, vrf_id);
+       zclient_create_header(s, ZEBRA_ROUTER_ID_UPDATE, vrf_id);
 
        /* Prefix information. */
        stream_putc(s, p->family);
@@ -1063,7 +1054,7 @@ int zsend_pw_update(struct zserv *client, struct zebra_pw *pw)
        s = client->obuf;
        stream_reset(s);
 
-       zserv_create_header(s, ZEBRA_PW_STATUS_UPDATE, pw->vrf_id);
+       zclient_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);
@@ -1132,46 +1123,81 @@ static int zread_route_add(struct zserv *client, u_short length,
        struct route_entry *re;
        struct nexthop *nexthop = NULL;
        int i, ret;
+       vrf_id_t vrf_id = 0;
 
        s = client->ibuf;
        if (zapi_route_decode(s, &api) < 0)
                return -1;
 
        /* Allocate new route. */
+       vrf_id = zvrf_id(zvrf);
        re = XCALLOC(MTYPE_RE, sizeof(struct route_entry));
        re->type = api.type;
        re->instance = api.instance;
        re->flags = api.flags;
        re->uptime = time(NULL);
-       re->vrf_id = zvrf_id(zvrf);
+       re->vrf_id = vrf_id;
        re->table = zvrf->table_id;
 
        if (CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP)) {
                for (i = 0; i < api.nexthop_num; i++) {
                        api_nh = &api.nexthops[i];
+                       ifindex_t ifindex = 0;
 
                        switch (api_nh->type) {
                        case NEXTHOP_TYPE_IFINDEX:
                                nexthop = route_entry_nexthop_ifindex_add(
-                                       re, api_nh->ifindex);
+                                       re, api_nh->ifindex, re->vrf_id);
                                break;
                        case NEXTHOP_TYPE_IPV4:
                                nexthop = route_entry_nexthop_ipv4_add(
-                                       re, &api_nh->gate.ipv4, NULL);
+                                       re, &api_nh->gate.ipv4, NULL,
+                                       re->vrf_id);
                                break;
-                       case NEXTHOP_TYPE_IPV4_IFINDEX:
+                       case NEXTHOP_TYPE_IPV4_IFINDEX: {
+
+                               struct ipaddr vtep_ip;
+
+                               memset(&vtep_ip, 0, sizeof(struct ipaddr));
+                               if (CHECK_FLAG(api.flags,
+                                              ZEBRA_FLAG_EVPN_ROUTE)) {
+                                       ifindex =
+                                               get_l3vni_svi_ifindex(vrf_id);
+                               } else {
+                                       ifindex = api_nh->ifindex;
+                               }
+
                                nexthop = route_entry_nexthop_ipv4_ifindex_add(
-                                       re, &api_nh->gate.ipv4, NULL,
-                                       api_nh->ifindex);
+                                       re, &api_nh->gate.ipv4, NULL, ifindex,
+                                       re->vrf_id);
+
+                               /* if this an EVPN route entry,
+                                  program the nh as neigh
+                                */
+                               if (CHECK_FLAG(api.flags,
+                                              ZEBRA_FLAG_EVPN_ROUTE)) {
+                                       SET_FLAG(nexthop->flags,
+                                                NEXTHOP_FLAG_EVPN_RVTEP);
+                                       vtep_ip.ipa_type = IPADDR_V4;
+                                       memcpy(&(vtep_ip.ipaddr_v4),
+                                              &(api_nh->gate.ipv4),
+                                              sizeof(struct in_addr));
+                                       zebra_vxlan_evpn_vrf_route_add(
+                                                               vrf_id,
+                                                               &api.rmac,
+                                                               &vtep_ip,
+                                                               &api.prefix);
+                               }
                                break;
+                       }
                        case NEXTHOP_TYPE_IPV6:
                                nexthop = route_entry_nexthop_ipv6_add(
-                                       re, &api_nh->gate.ipv6);
+                                       re, &api_nh->gate.ipv6, re->vrf_id);
                                break;
                        case NEXTHOP_TYPE_IPV6_IFINDEX:
                                nexthop = route_entry_nexthop_ipv6_ifindex_add(
-                                       re, &api_nh->gate.ipv6,
-                                       api_nh->ifindex);
+                                       re, &api_nh->gate.ipv6, api_nh->ifindex,
+                                       re->vrf_id);
                                break;
                        case NEXTHOP_TYPE_BLACKHOLE:
                                nexthop = route_entry_nexthop_blackhole_add(
@@ -1265,7 +1291,7 @@ static int zread_route_del(struct zserv *client, u_short length,
 
        rib_delete(afi, api.safi, zvrf_id(zvrf), api.type, api.instance,
                   api.flags, &api.prefix, src_p, NULL, zvrf->table_id,
-                  api.metric, false);
+                  api.metric, false, &api.rmac);
 
        /* Stats */
        switch (api.prefix.family) {
@@ -1354,13 +1380,14 @@ static int zread_ipv4_add(struct zserv *client, u_short length,
                        switch (nexthop_type) {
                        case NEXTHOP_TYPE_IFINDEX:
                                STREAM_GETL(s, ifindex);
-                               route_entry_nexthop_ifindex_add(re, ifindex);
+                               route_entry_nexthop_ifindex_add(re, ifindex,
+                                                               re->vrf_id);
                                break;
                        case NEXTHOP_TYPE_IPV4:
                                STREAM_GET(&nhop_addr.s_addr, s,
                                           IPV4_MAX_BYTELEN);
                                nexthop = route_entry_nexthop_ipv4_add(
-                                       re, &nhop_addr, NULL);
+                                       re, &nhop_addr, NULL, re->vrf_id);
                                /* For labeled-unicast, each nexthop is followed
                                 * by label. */
                                if (CHECK_FLAG(message, ZAPI_MESSAGE_LABEL)) {
@@ -1374,7 +1401,8 @@ static int zread_ipv4_add(struct zserv *client, u_short length,
                                           IPV4_MAX_BYTELEN);
                                STREAM_GETL(s, ifindex);
                                route_entry_nexthop_ipv4_ifindex_add(
-                                       re, &nhop_addr, NULL, ifindex);
+                                       re, &nhop_addr, NULL, ifindex,
+                                       re->vrf_id);
                                break;
                        case NEXTHOP_TYPE_IPV6:
                                zlog_warn("%s: Please use ZEBRA_ROUTE_ADD if you want to pass v6 nexthops",
@@ -1466,7 +1494,7 @@ static int zread_ipv4_delete(struct zserv *client, u_short length,
        table_id = zvrf->table_id;
 
        rib_delete(AFI_IP, api.safi, zvrf_id(zvrf), api.type, api.instance,
-                  api.flags, &p, NULL, NULL, table_id, 0, false);
+                  api.flags, &p, NULL, NULL, table_id, 0, false, NULL);
        client->v4_route_del_cnt++;
 
 stream_failure:
@@ -1607,10 +1635,11 @@ static int zread_ipv4_route_ipv6_nexthop_add(struct zserv *client,
                                        nexthop =
                                                route_entry_nexthop_ipv6_ifindex_add(
                                                        re, &nexthops[i],
-                                                       ifindices[i]);
+                                                       ifindices[i],
+                                                       re->vrf_id);
                                else
                                        nexthop = route_entry_nexthop_ipv6_add(
-                                               re, &nexthops[i]);
+                                               re, &nexthops[i], re->vrf_id);
 
                                if (CHECK_FLAG(message, ZAPI_MESSAGE_LABEL))
                                        nexthop_add_labels(nexthop, label_type,
@@ -1618,7 +1647,7 @@ static int zread_ipv4_route_ipv6_nexthop_add(struct zserv *client,
                        } else {
                                if ((i < if_count) && ifindices[i])
                                        route_entry_nexthop_ifindex_add(
-                                               re, ifindices[i]);
+                                               re, ifindices[i], re->vrf_id);
                        }
                }
        }
@@ -1732,6 +1761,9 @@ static int zread_ipv6_add(struct zserv *client, u_short length,
        } else
                src_pp = NULL;
 
+       /* VRF ID */
+       re->vrf_id = zvrf_id(zvrf);
+
        /* We need to give nh-addr, nh-ifindex with the same next-hop object
         * to the re to ensure that IPv6 multipathing works; need to coalesce
         * these. Clients should send the same number of paired set of
@@ -1769,7 +1801,7 @@ static int zread_ipv6_add(struct zserv *client, u_short length,
                                STREAM_GET(&nhop_addr, s, 16);
                                STREAM_GETL(s, ifindex);
                                route_entry_nexthop_ipv6_ifindex_add(
-                                       re, &nhop_addr, ifindex);
+                                       re, &nhop_addr, ifindex, re->vrf_id);
                                break;
                        case NEXTHOP_TYPE_IFINDEX:
                                if (if_count < multipath_num) {
@@ -1796,17 +1828,18 @@ static int zread_ipv6_add(struct zserv *client, u_short length,
                                        nexthop =
                                                route_entry_nexthop_ipv6_ifindex_add(
                                                        re, &nexthops[i],
-                                                       ifindices[i]);
+                                                       ifindices[i],
+                                                       re->vrf_id);
                                else
                                        nexthop = route_entry_nexthop_ipv6_add(
-                                               re, &nexthops[i]);
+                                               re, &nexthops[i], re->vrf_id);
                                if (CHECK_FLAG(message, ZAPI_MESSAGE_LABEL))
                                        nexthop_add_labels(nexthop, label_type,
                                                           1, &labels[i]);
                        } else {
                                if ((i < if_count) && ifindices[i])
                                        route_entry_nexthop_ifindex_add(
-                                               re, ifindices[i]);
+                                               re, ifindices[i], re->vrf_id);
                        }
                }
        }
@@ -1830,8 +1863,6 @@ static int zread_ipv6_add(struct zserv *client, u_short length,
        else
                re->mtu = 0;
 
-       /* VRF ID */
-       re->vrf_id = zvrf_id(zvrf);
        re->table = zvrf->table_id;
 
        ret = rib_add_multipath(AFI_IP6, safi, &p, src_pp, re);
@@ -1884,7 +1915,8 @@ static int zread_ipv6_delete(struct zserv *client, u_short length,
                src_pp = NULL;
 
        rib_delete(AFI_IP6, api.safi, zvrf_id(zvrf), api.type, api.instance,
-                  api.flags, &p, src_pp, NULL, client->rtm_table, 0, false);
+                  api.flags, &p, src_pp, NULL, client->rtm_table, 0, false,
+                  NULL);
 
        client->v6_route_del_cnt++;
 
@@ -2054,7 +2086,7 @@ static int zsend_label_manager_connect_response(struct zserv *client,
        s = client->obuf;
        stream_reset(s);
 
-       zserv_create_header(s, ZEBRA_LABEL_MANAGER_CONNECT, vrf_id);
+       zclient_create_header(s, ZEBRA_LABEL_MANAGER_CONNECT, vrf_id);
 
        /* result */
        stream_putc(s, result);
@@ -2116,7 +2148,7 @@ static int zsend_assign_label_chunk_response(struct zserv *client,
        s = client->obuf;
        stream_reset(s);
 
-       zserv_create_header(s, ZEBRA_GET_LABEL_CHUNK, vrf_id);
+       zclient_create_header(s, ZEBRA_GET_LABEL_CHUNK, vrf_id);
 
        if (lmc) {
                /* keep */
@@ -2437,11 +2469,11 @@ static int zread_interface_set_master(struct zserv *client,
        int ifindex;
        vrf_id_t vrf_id;
 
-       STREAM_GETW(s, vrf_id);
+       STREAM_GETL(s, vrf_id);
        STREAM_GETL(s, ifindex);
        master = if_lookup_by_index(ifindex, vrf_id);
 
-       STREAM_GETW(s, vrf_id);
+       STREAM_GETL(s, vrf_id);
        STREAM_GETL(s, ifindex);
        slave = if_lookup_by_index(ifindex, vrf_id);
 
@@ -2454,6 +2486,75 @@ stream_failure:
        return 1;
 }
 
+
+static void zread_vrf_label(struct zserv *client,
+                           struct zebra_vrf *zvrf)
+{
+       struct interface *ifp;
+       mpls_label_t nlabel;
+       afi_t afi;
+       struct stream *s;
+       struct zebra_vrf *def_zvrf;
+       enum lsp_types_t ltype;
+
+       s = client->ibuf;
+       STREAM_GETL(s, nlabel);
+       STREAM_GETC(s, afi);
+       if (nlabel == zvrf->label[afi]) {
+               /*
+                * Nothing to do here move along
+                */
+               return;
+       }
+
+       STREAM_GETC(s, ltype);
+
+       if (zvrf->vrf->vrf_id != VRF_DEFAULT)
+               ifp = if_lookup_by_name(zvrf->vrf->name, zvrf->vrf->vrf_id);
+       else
+               ifp = if_lookup_by_name("lo", VRF_DEFAULT);
+
+       if (!ifp) {
+               zlog_debug("Unable to find specified Interface for %s",
+                          zvrf->vrf->name);
+               return;
+       }
+
+       def_zvrf = zebra_vrf_lookup_by_id(VRF_DEFAULT);
+
+       if (zvrf->label[afi] != MPLS_LABEL_NONE) {
+               afi_t scrubber;
+               bool really_remove;
+
+               really_remove = true;
+               for (scrubber = AFI_IP; scrubber < AFI_MAX ; scrubber++) {
+                       if (scrubber == afi)
+                               continue;
+
+                       if (zvrf->label[scrubber] == MPLS_LABEL_NONE)
+                               continue;
+
+                       if (zvrf->label[afi] == zvrf->label[scrubber]) {
+                               really_remove = false;
+                               break;
+                       }
+               }
+
+               if (really_remove)
+                       mpls_lsp_uninstall(def_zvrf, ltype, zvrf->label[afi],
+                                          NEXTHOP_TYPE_IFINDEX, NULL,
+                                          ifp->ifindex);
+       }
+
+       if (nlabel != MPLS_LABEL_NONE)
+               mpls_lsp_install(def_zvrf, ltype, nlabel, MPLS_LABEL_IMPLICIT_NULL,
+                                NEXTHOP_TYPE_IFINDEX, NULL, ifp->ifindex);
+
+       zvrf->label[afi] = nlabel;
+stream_failure:
+       return;
+}
+
 static inline void zserv_handle_commands(struct zserv *client,
                                         uint16_t command,
                                         uint16_t length,
@@ -2538,6 +2639,9 @@ static inline void zserv_handle_commands(struct zserv *client,
        case ZEBRA_VRF_UNREGISTER:
                zread_vrf_unregister(client, length, zvrf);
                break;
+       case ZEBRA_VRF_LABEL:
+               zread_vrf_label(client, zvrf);
+               break;
        case ZEBRA_BFD_CLIENT_REGISTER:
                zebra_ptm_bfd_client_register(client, length);
                break;
@@ -2572,6 +2676,9 @@ static inline void zserv_handle_commands(struct zserv *client,
        case ZEBRA_ADVERTISE_DEFAULT_GW:
                zebra_vxlan_advertise_gw_macip(client, length, zvrf);
                break;
+       case ZEBRA_ADVERTISE_SUBNET:
+               zebra_vxlan_advertise_subnet(client, length, zvrf);
+               break;
        case ZEBRA_ADVERTISE_ALL_VNI:
                zebra_vxlan_advertise_all_vni(client, length, zvrf);
                break;
@@ -2679,7 +2786,7 @@ static int zebra_client_read(struct thread *thread)
                STREAM_GETW(client->ibuf, length);
                STREAM_GETC(client->ibuf, marker);
                STREAM_GETC(client->ibuf, version);
-               STREAM_GETW(client->ibuf, vrf_id);
+               STREAM_GETL(client->ibuf, vrf_id);
                STREAM_GETW(client->ibuf, command);
 
                if (marker != ZEBRA_HEADER_MARKER || version != ZSERV_VERSION) {
@@ -2979,6 +3086,8 @@ static void zebra_show_client_detail(struct vty *vty, struct zserv *client)
        vty_out(vty, "Interface Down Notifications: %d\n", client->ifdown_cnt);
        vty_out(vty, "VNI add notifications: %d\n", client->vniadd_cnt);
        vty_out(vty, "VNI delete notifications: %d\n", client->vnidel_cnt);
+       vty_out(vty, "L3-VNI add notifications: %d\n", client->l3vniadd_cnt);
+       vty_out(vty, "L3-VNI delete notifications: %d\n", client->l3vnidel_cnt);
        vty_out(vty, "MAC-IP add notifications: %d\n", client->macipadd_cnt);
        vty_out(vty, "MAC-IP delete notifications: %d\n", client->macipdel_cnt);
 
index c4b4e20df293b8b9d0c3ccf6e3f918bf94466209..7d5f6b45437f203c23c6b3f7d1e8e1e27239cb11 100644 (file)
@@ -110,8 +110,12 @@ struct zserv {
        u_int32_t bfd_client_reg_cnt;
        u_int32_t vniadd_cnt;
        u_int32_t vnidel_cnt;
+       u_int32_t l3vniadd_cnt;
+       u_int32_t l3vnidel_cnt;
        u_int32_t macipadd_cnt;
        u_int32_t macipdel_cnt;
+       u_int32_t prefixadd_cnt;
+       u_int32_t prefixdel_cnt;
 
        time_t connect_time;
        time_t last_read_time;
@@ -175,8 +179,6 @@ extern int zsend_route_notify_owner(u_char proto, u_short instance,
                                    vrf_id_t vrf_id, struct prefix *p,
                                    enum zapi_route_notify_owner note);
 
-extern void zserv_create_header(struct stream *s, uint16_t cmd,
-                               vrf_id_t vrf_id);
 extern void zserv_nexthop_num_warn(const char *, const struct prefix *,
                                   const unsigned int);
 extern int zebra_server_send_message(struct zserv *client);