]> git.proxmox.com Git - mirror_frr.git/commitdiff
Merge branch 'master' into docs-user
authorQuentin Young <qlyoung@cumulusnetworks.com>
Tue, 30 Jan 2018 20:05:15 +0000 (15:05 -0500)
committerQuentin Young <qlyoung@cumulusnetworks.com>
Tue, 30 Jan 2018 20:05:15 +0000 (15:05 -0500)
Manually merged these doc commits:

3bb7cd7f56649ef17eeada95c132de1146c5fc92
ff21655441a64c427b3e373272e7b4564a8a1bb1

214 files changed:
.clang-format
COMMUNITY.md
README
babeld/babeld.c
babeld/kernel.c
babeld/kernel.h
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_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_main.c
bgpd/bgp_memory.c
bgpd/bgp_memory.h
bgpd/bgp_nht.c
bgpd/bgp_packet.c
bgpd/bgp_rd.c
bgpd/bgp_route.c
bgpd/bgp_route.h
bgpd/bgp_routemap.c
bgpd/bgp_snmp.c
bgpd/bgp_vty.c
bgpd/bgp_zebra.c
bgpd/bgpd.c
bgpd/bgpd.h
bgpd/rfapi/bgp_rfapi_cfg.c
bgpd/rfapi/rfapi.c
bgpd/rfapi/rfapi_import.c
bgpd/rfapi/rfapi_monitor.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/Makefile.am
debianpkg/README.deb_build.md
doc/Makefile.am
doc/bgpd.texi [new file with mode: 0644]
doc/install.texi [new file with mode: 0644]
doc/isisd.texi [new file with mode: 0644]
doc/ospfd.texi [new file with mode: 0644]
doc/pimd.texi [new file with mode: 0644]
doc/routemap.texi [new file with mode: 0644]
doc/user/bgp.rst
doc/user/vnc.rst
doc/vnc.texi [new file with mode: 0644]
eigrpd/eigrp_reply.c
eigrpd/eigrp_zebra.c
isisd/dict.h
isisd/isis_bpf.c
isisd/isis_circuit.c
isisd/isis_circuit.h
isisd/isis_lsp.c
isisd/isis_spf.c
isisd/isis_zebra.c
ldpd/ldp_debug.c
ldpd/ldp_debug.h
lib/command.h
lib/command_match.c
lib/frr_pthread.c
lib/frr_pthread.h
lib/frr_zmq.c
lib/frr_zmq.h
lib/grammar_sandbox.c
lib/if.c
lib/if.h
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/ptm_lib.h
lib/ringbuf.c [new file with mode: 0644]
lib/ringbuf.h [new file with mode: 0644]
lib/subdir.am
lib/thread.c
lib/vrf.c
lib/vrf.h
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_interface.c
ospf6d/ospf6_interface.h
ospf6d/ospf6_intra.c
ospf6d/ospf6_lsa.c
ospf6d/ospf6_lsa.h
ospf6d/ospf6_memory.c
ospf6d/ospf6_memory.h
ospf6d/ospf6_message.c
ospf6d/ospf6_route.c
ospf6d/ospf6_route.h
ospf6d/ospf6_snmp.c
ospf6d/ospf6_spf.c
ospf6d/ospf6_spf.h
ospf6d/ospf6_top.c
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_ia.c
ospfd/ospf_interface.c
ospfd/ospf_interface.h
ospfd/ospf_lsa.c
ospfd/ospf_network.c
ospfd/ospf_nsm.c
ospfd/ospf_opaque.c
ospfd/ospf_packet.c
ospfd/ospf_snmp.c
ospfd/ospf_spf.c
ospfd/ospf_vty.c
ospfd/ospf_vty.h
ospfd/ospf_zebra.c
ospfd/ospfd.c
pimd/pim_cmd.c
pimd/pim_iface.c
pimd/pim_ifchannel.c
pimd/pim_instance.c
pimd/pim_nht.c
pimd/pim_zebra.c
pkgsrc/README.txt
redhat/frr.spec.in
ripd/rip_zebra.c
ripd/ripd.conf.sample
ripngd/ripng_zebra.c
ripngd/ripngd.conf.sample
sharpd/.gitignore [new file with mode: 0644]
sharpd/sharp_zebra.c
tests/Makefile.am
tests/bgpd/test_aspath.c
tests/bgpd/test_capability.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]
tests/lib/test_zmq.c
tests/lib/test_zmq.refout
tools/etc/frr/daemons.conf
tools/frr-reload.py
vtysh/vtysh.c
vtysh/vtysh.h
vtysh/vtysh_main.c
watchfrr/watchfrr.c
zebra/connected.c
zebra/if_netlink.c
zebra/interface.c
zebra/interface.h
zebra/ioctl.c
zebra/ipforward_proc.c
zebra/ipforward_sysctl.c
zebra/kernel_netlink.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/rtadv.c
zebra/rtread_getmsg.c
zebra/rtread_netlink.c
zebra/rtread_sysctl.c
zebra/zebra.conf.sample
zebra/zebra_fpm.c
zebra/zebra_mpls.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_routemap.c
zebra/zebra_routemap.h
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
index 7605b03201ae1f12038e18b05ff6c4dda3886e60..0eee524d585b74ec35c277357fd951e72d156ec6 100644 (file)
@@ -68,6 +68,16 @@ Italicized lists are private.
 | _Security_                     | security@lists.frrouting.org |
 | _Technical Steering Committee_ | tsc@lists.frrouting.org      |
 
+The Development list is used to discuss and document general issues
+related to project development and governance. The public Slack
+instance, frrouting.slack.com, and weekly technical meetings provide a
+higher bandwidth channel for discussions.  The results of such
+discussions must be reflected in updates, as appropriate, to code (i.e.,
+merges), [github](https://github.com/FRRouting/frr/issues) tracked
+issues, and for governance or process changes, updates to the
+Development list and either this file or information posted at
+[https://frrouting.org/](https://frrouting.org/).
+
 
 ### Changelog
 
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 00367612c624d94d97e9b6be14d3fe1ecb84c527..20dd098f33026754713b51f3b2c642c570ea5257 100644 (file)
@@ -229,7 +229,7 @@ babel_get_myid(void)
         int ifindex = if_nametoindex(ifp->name);
         if(ifindex > 0) {
             unsigned char eui[8];
-            rc = if_eui64(ifp->name, ifindex, eui);
+            rc = if_eui64(ifindex, eui);
             if(rc < 0)
                 continue;
             memcpy(myid, eui, 8);
@@ -245,7 +245,7 @@ babel_get_myid(void)
         ifname = if_indextoname(i, buf);
         if(ifname == NULL)
             continue;
-        rc = if_eui64(ifname, i, eui);
+        rc = if_eui64(i, eui);
         if(rc < 0)
             continue;
         memcpy(myid, eui, 8);
index 3343ca2e9538a3acba11a10a72d6be72df0ad0f7..6b673c487c53386ce6fb4b00e8bf6605b2787119 100644 (file)
@@ -166,6 +166,7 @@ zebra_route(int add, int family, const unsigned char *pref, unsigned short plen,
     api.type  = ZEBRA_ROUTE_BABEL;
     api.safi = SAFI_UNICAST;
     api.vrf_id = VRF_DEFAULT;
+    api.nh_vrf_id = VRF_DEFAULT;
     api.prefix = quagga_prefix;
 
     if(metric >= KERNEL_INFINITY) {
@@ -203,7 +204,7 @@ zebra_route(int add, int family, const unsigned char *pref, unsigned short plen,
 }
 
 int
-if_eui64(char *ifname, int ifindex, unsigned char *eui)
+if_eui64(int ifindex, unsigned char *eui)
 {
     struct interface *ifp = if_lookup_by_index(ifindex, VRF_DEFAULT);
     if (ifp == NULL) {
index 7ade26dc3655948691fe27b75d7df2fcfc383ce7..eb1e793279c52b9b4c5878d6a592d0df3c9bc060 100644 (file)
@@ -40,7 +40,7 @@ int kernel_route(int operation, const unsigned char *dest, unsigned short plen,
                  const unsigned char *gate, int ifindex, unsigned int metric,
                  const unsigned char *newgate, int newifindex,
                  unsigned int newmetric);
-int if_eui64(char *ifname, int ifindex, unsigned char *eui);
+int if_eui64(int ifindex, unsigned char *eui);
 int gettime(struct timeval *tv);
 int read_random_bytes(void *buf, size_t len);
 
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..206d91bfe9115a4cb8a363d2fb22dd67d2b1e813 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,9 @@ bgp_attr_ext_communities(struct bgp_attr_parser_args *args)
        attr->mm_seqnum = bgp_attr_mac_mobility_seqnum(attr, &sticky);
        attr->sticky = sticky;
 
+       /* Extract the Rmac, if any */
+       bgp_attr_rmac(attr, &attr->rmac);
+
        return BGP_ATTR_PARSE_PROCEED;
 }
 
@@ -3252,6 +3252,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);
index f694f01adb10be860f746d0d0d3232b3cc288908..1de1bee0f9d69fea750edecb6101e668cccf95bc 100644 (file)
@@ -182,6 +182,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 */
index 300c9ddb506a4f471a788ba351dfa4af33474986..eaa4e329d455b616ffd71ac6d2c22fadb05a8a81 100644 (file)
@@ -105,6 +105,35 @@ 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);
+       }
+}
+
 /*
  * Fetch and return the sequence number from MAC Mobility extended
  * community, if present, else 0.
index 15d9e126e404cd8e2ac42a4fa5a653355f507b7a..8b55cb30020bf4f7a168afad88b6adc43f90035e 100644 (file)
@@ -59,7 +59,7 @@ 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);
 
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 e19f516505f0d840c443bbfd8be00c3c52a0b8c2..9caf38d569b35a355f5f5fb60870d1961873c151 100644 (file)
@@ -695,19 +695,19 @@ char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter)
                } 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..12cc425bd36e5d6d850db63c69ed2756a25a31c5 100644 (file)
@@ -92,6 +92,131 @@ 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;
+       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;
+}
+
+/*
+ * 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.
  */
@@ -246,6 +371,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 +477,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);
@@ -425,20 +601,76 @@ 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_rmac;
        struct ecommunity_val eval;
        struct ecommunity_val eval_sticky;
+       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 +682,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 +710,15 @@ 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);
+       }
+
        attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES);
 }
 
@@ -699,6 +954,123 @@ 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);
+
+               /* L3-VNI goes in the label2 field */
+               bgp_info_extra_get(ri);
+               vni2label(bgp_vrf->l3vni, &label);
+               memcpy(&ri->extra->label2, &label, BGP_LABEL_BYTES);
+
+               /* 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)
+{
+       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 -1;
+
+       /* build path attribute for this route */
+       memset(&attr, 0, sizeof(struct attr));
+       bgp_attr_default_set(&attr, BGP_ORIGIN_IGP);
+       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 */
+       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.
@@ -834,9 +1206,14 @@ static int update_evpn_route(struct bgp *bgp, struct bgpevpn *vpn,
        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.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 +1255,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 -1;
+
+       /* 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,12 +1394,16 @@ 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_ip6;
+       struct attr attr_sticky_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_ip6, 0, sizeof(struct attr));
+       memset(&attr_sticky_ip6, 0, sizeof(struct attr));
 
        /* Build path-attribute - all type-2 routes for this VNI will share the
         * same path attribute.
@@ -980,14 +1413,29 @@ static int update_all_type2_routes(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;
+       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);
+       bgp_attr_default_set(&attr_ip6, BGP_ORIGIN_IGP);
+       bgp_attr_default_set(&attr_sticky_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);
 
        /* 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_ip6, AFI_IP6);
+       build_evpn_route_extcomm(vpn, &attr_sticky_ip6, AFI_IP6);
 
        /* 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 +1449,24 @@ 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
+                               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
+                               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.
@@ -1219,6 +1679,100 @@ static int handle_tunnel_ip_change(struct bgp *bgp, struct bgpevpn *vpn,
        return update_routes_for_vni(bgp, vpn);
 }
 
+/*
+ * Install route entry into the VRF routing table and invoke route selection.
+ */
+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 = 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,
+                              BGP_LABEL_BYTES);
+               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.
  */
@@ -1285,6 +1839,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 +1945,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 +2079,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 +2235,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 +2265,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 +2293,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 +2388,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 +2402,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,32 +2422,104 @@ 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;
+       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);
 }
 
 /*
@@ -1971,6 +2876,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,14 +2911,12 @@ 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;
@@ -2043,10 +2947,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);
@@ -2107,30 +3014,311 @@ 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 bgp_node *rn,
+                                  afi_t afi, safi_t safi)
+{
+       int ret = 0;
+       struct prefix_evpn evp;
+       char buf[PREFIX_STRLEN];
+
+       build_type5_prefix_from_ip_prefix(&evp, &rn->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(&rn->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;
+
+       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, afi, safi);
+
+}
+
+/* advertise ip prefix as type-5 route*/
+void bgp_evpn_advertise_type5_route(struct bgp *bgp_vrf, struct bgp_node *rn,
+                                   afi_t afi, safi_t safi)
+{
+       int ret = 0;
+       struct prefix_evpn evp;
+       char buf[PREFIX_STRLEN];
+
+       if (!advertise_type5_routes(bgp_vrf, afi))
+               return;
+
+       if (!rn->info)
+               return;
+
+       /* only advertise subnet routes as type-5 */
+       if (is_host_route(&rn->p))
+               return;
+
+       build_type5_prefix_from_ip_prefix(&evp, &rn->p);
+       ret = update_evpn_type5_route(bgp_vrf, &evp);
+       if (ret) {
+               zlog_err(
+                        "%u failed to create type-5 route for prefix %s in vrf %s",
+                        bgp_vrf->vrf_id,
+                        prefix2str(&rn->p, buf, sizeof(buf)),
+                        vrf_id_to_name(bgp_vrf->vrf_id));
+       }
+}
+
+/* advertise all type-5 routes for an address family */
+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;
+
+       table = bgp_vrf->rib[afi][safi];
+       for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn))
+               bgp_evpn_advertise_type5_route(bgp_vrf, rn, afi, safi);
+}
+
+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 +3329,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
@@ -2285,6 +3482,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]:[%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)",
@@ -2453,6 +3657,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 +3778,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 +3790,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 +3841,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 +3856,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 +3874,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 +3890,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);
@@ -2770,6 +4054,160 @@ int bgp_evpn_local_macip_add(struct bgp *bgp, vni_t vni, struct ethaddr *mac,
        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;
+}
+
 /*
  * Handle del of a local VNI.
  */
@@ -2813,7 +4251,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 +4265,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 +4288,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 +4355,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 +4375,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 +4384,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..9400916845b04374263de3772f004e1077860110 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;
+}
+
+extern void bgp_evpn_advertise_type5_route(struct bgp *bgp_vrf,
+                                          struct bgp_node *rn,
+                                          afi_t afi, safi_t safi);
+extern void bgp_evpn_withdraw_type5_route(struct bgp *bgp_vrf,
+                                         struct bgp_node *rn,
+                                         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_route2str(struct prefix_evpn *p, char *buf, int len);
@@ -45,9 +65,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..2d52e1995d2bbc6596bf98f43486b7ca1a718ff2 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" */
@@ -96,10 +98,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));
@@ -157,6 +248,15 @@ static inline vni_t label2vni(mpls_label_t *label)
        return vni;
 }
 
+static inline void encode_rmac_extcomm(struct ecommunity_val *eval,
+                                      struct ethaddr *rmac)
+{
+       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 void encode_mac_mobility_extcomm(int static_mac, u_int32_t seq,
                                               struct ecommunity_val *eval)
 {
@@ -171,6 +271,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 +323,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 +359,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 +402,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 70f7e78976b9c08dd98b8ed9a8253c88fa8f4ee9..b463896c493345f2825bd40a734bc50bb8e18a14 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++);
+               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)
 {
@@ -226,7 +337,7 @@ static void bgp_evpn_show_route_header(struct vty *vty, struct bgp *bgp,
 
 static void display_vni(struct vty *vty, struct bgpevpn *vpn, json_object *json)
 {
-       char buf1[INET6_ADDRSTRLEN];
+       char buf1[RD_ADDRSTRLEN];
        char *ecom_str;
        struct listnode *node, *nnode;
        struct ecommunity *ecom;
@@ -241,7 +352,7 @@ static void display_vni(struct vty *vty, struct bgpevpn *vpn, json_object *json)
                                       is_vni_live(vpn) ? "Yes" : "No");
                json_object_string_add(
                        json, "rd",
-                       prefix_rd2str(&vpn->prd, buf1, RD_ADDRSTRLEN));
+                       prefix_rd2str(&vpn->prd, buf1, sizeof(buf1)));
                json_object_string_add(json, "originatorIp",
                                       inet_ntoa(vpn->originator_ip));
                json_object_string_add(json, "advertiseGatewayMacip",
@@ -252,8 +363,10 @@ 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, "  Tenant-Vrf: %s\n",
+                       vrf_id_to_name(vpn->tenant_vrf_id));
                vty_out(vty, "  RD: %s\n",
-                       prefix_rd2str(&vpn->prd, buf1, RD_ADDRSTRLEN));
+                       prefix_rd2str(&vpn->prd, buf1, sizeof(buf1)));
                vty_out(vty, "  Originator IP: %s\n",
                        inet_ntoa(vpn->originator_ip));
                vty_out(vty, "  Advertise-gw-macip : %s\n",
@@ -298,6 +411,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)
@@ -414,12 +574,12 @@ static void show_vni_entry(struct hash_backet *backet, void *args[])
 {
        struct vty *vty;
        json_object *json;
-       json_object *json_vni;
-       json_object *json_import_rtl;
-       json_object *json_export_rtl;
+       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[INET6_ADDRSTRLEN];
+       char buf2[RD_ADDRSTRLEN];
        char rt_buf[25];
        char *ecom_str;
        struct listnode *node, *nnode;
@@ -446,7 +606,7 @@ static void show_vni_entry(struct hash_backet *backet, void *args[])
                                       inet_ntoa(vpn->originator_ip));
                json_object_string_add(
                        json_vni, "rd",
-                       prefix_rd2str(&vpn->prd, buf2, RD_ADDRSTRLEN));
+                       prefix_rd2str(&vpn->prd, buf2, sizeof(buf2)));
        } else {
                vty_out(vty, "%-1s %-10u %-15s %-21s", buf1, vpn->vni,
                        inet_ntoa(vpn->originator_ip),
@@ -502,6 +662,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 +1329,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 +1489,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 +1581,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 +1633,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 +1978,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");
                                vty_out(vty,
-                                       "EVPN type-3 prefix: [3]:[EthTag]:[IPlen]:"
-                                       "[OrigIP]\n\n");
+                                       "EVPN type-5 prefix: [5]:[EthTag]:[IPlen]:[IP]\n\n");
                                rd_header = 0;
                        }
 
@@ -2014,8 +2214,9 @@ static void evpn_show_all_vnis(struct vty *vty, struct bgp *bgp,
        } else {
                vty_out(vty, "Number of VNIs: %u\n", num_vnis);
                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 %-15s %-21s %-25s %-25s %-37s\n", "VNI",
+                       "Orig IP", "RD", "Import RT",
+                       "Export RT", "Tenant-Vrf");
        }
 
        args[0] = vty;
@@ -2093,7 +2294,7 @@ static void evpn_unset_advertise_all_vni(struct bgp *bgp)
 
 static void write_vni_config(struct vty *vty, struct bgpevpn *vpn)
 {
-       char buf1[INET6_ADDRSTRLEN];
+       char buf1[RD_ADDRSTRLEN];
        char *ecom_str;
        struct listnode *node, *nnode;
        struct ecommunity *ecom;
@@ -2102,7 +2303,7 @@ static void write_vni_config(struct vty *vty, struct bgpevpn *vpn)
                vty_out(vty, "  vni %d\n", vpn->vni);
                if (is_rd_configured(vpn))
                        vty_out(vty, "   rd %s\n",
-                               prefix_rd2str(&vpn->prd, buf1, RD_ADDRSTRLEN));
+                               prefix_rd2str(&vpn->prd, buf1, sizeof(buf1)));
 
                if (is_import_rt_configured(vpn)) {
                        for (ALL_LIST_ELEMENTS(vpn->import_rtl, node, nnode,
@@ -2239,6 +2440,115 @@ DEFUN (no_bgp_evpn_advertise_all_vni,
        return CMD_SUCCESS;
 }
 
+DEFUN (bgp_evpn_advertise_type5,
+       bgp_evpn_advertise_type5_cmd,
+       "advertise " BGP_AFI_CMD_STR "" BGP_SAFI_CMD_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)) {
+                       SET_FLAG(bgp_vrf->vrf_flags,
+                                BGP_VRF_ADVERTISE_IPV4_IN_EVPN);
+                       bgp_evpn_advertise_type5_routes(bgp_vrf, afi, safi);
+               }
+       } 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)) {
+                       SET_FLAG(bgp_vrf->vrf_flags,
+                                BGP_VRF_ADVERTISE_IPV6_IN_EVPN);
+                       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);
+               }
+       }
+       return CMD_SUCCESS;
+}
+
 /*
  * Display VNI information - for all or a specific VNI
  */
@@ -2278,7 +2588,7 @@ DEFUN(show_bgp_l2vpn_evpn_vni,
                                                       ? "Enabled"
                                                       : "Disabled");
                        json_object_string_add(json, "advertiseAllVnis",
-                                              bgp->advertise_all_vni
+                                              is_evpn_enabled()
                                                       ? "Enabled"
                                                       : "Disabled");
                } else {
@@ -2288,8 +2598,7 @@ DEFUN(show_bgp_l2vpn_evpn_vni,
 
                        /* Display all VNIs */
                        vty_out(vty, "Advertise All VNI flag: %s\n",
-                               bgp->advertise_all_vni ? "Enabled"
-                                                      : "Disabled");
+                               is_evpn_enabled() ? "Enabled" : "Disabled");
                }
 
                evpn_show_all_vnis(vty, bgp, json);
@@ -2529,6 +2838,33 @@ DEFUN(show_bgp_l2vpn_evpn_route_rd_macip,
        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;
+
+       evpn_show_vrf_routes(vty, bgp_vrf);
+
+       return CMD_SUCCESS;
+}
+
 /*
  * Display per-VNI EVPN routing table.
  */
@@ -2784,6 +3120,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 +3350,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 +3541,279 @@ 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 l3vni info [json]",
+       SHOW_STR
+       BGP_STR
+       "show bgp vrf\n"
+       "VRF Name\n"
+       "L3-VNI\n"
+       "L3-VNI info\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 +4036,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 +4069,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 +4079,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 +4098,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,6 +4109,11 @@ 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,
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 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 625d4f844260d03bb0c58977f7b2a979d074d974..a963838f5f27941e82e23ec761a930202f1a6608 100644 (file)
@@ -336,7 +336,7 @@ void bgp_parse_nexthop_update(int command, vrf_id_t vrf_id)
        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;
        }
@@ -389,7 +389,7 @@ void bgp_parse_nexthop_update(int command, vrf_id_t vrf_id)
                char buf[PREFIX2STR_BUFFER];
                prefix2str(&p, buf, sizeof(buf));
                zlog_debug(
-                       "%d: Rcvd NH update %s - metric %d/%d #nhops %d/%d flags 0x%x",
+                       "%u: Rcvd NH update %s - metric %d/%d #nhops %d/%d flags 0x%x",
                        vrf_id, buf, metric, bnc->metric, nexthop_num,
                        bnc->nexthop_num, bnc->flags);
        }
@@ -572,12 +572,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 +584,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 2b676e052b3480b31ac72c2938ff0e69df317918..ae1ec7b84525b75ca082bd08f04aada818766625 100644 (file)
@@ -166,8 +166,7 @@ char *prefix_rd2str(struct prefix_rd *prd, char *buf, size_t size)
        struct rd_as rd_as;
        struct rd_ip rd_ip;
 
-       if (size < RD_ADDRSTRLEN)
-               return NULL;
+       assert(size >= RD_ADDRSTRLEN);
 
        pnt = prd->val;
 
@@ -197,5 +196,7 @@ char *prefix_rd2str(struct prefix_rd *prd, char *buf, size_t size)
                return buf;
        }
 #endif
-       return NULL;
+
+       snprintf(buf, size, "Unknown Type: %d", type);
+       return buf;
 }
index a655bd0b6f4f869662e368e146e4435ef5a9ef1a..fdc7f22ae859ed3b1d9220a47950e9ef4e3db9de 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[];
@@ -2219,6 +2222,14 @@ 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, afi, safi);
+               else if (old_select)
+                       bgp_evpn_withdraw_type5_route(bgp, rn, afi, safi);
+       }
+
        /* Clear any route change flags. */
        bgp_zebra_clear_route_change_flags(rn);
 
@@ -2708,7 +2719,9 @@ 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)
@@ -4480,9 +4493,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 +4517,109 @@ 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);
+               /* Update BGP RIB. */
+               if (!bgp_static->backdoor)
+                       bgp_static_withdraw(bgp, &p, afi, safi);
 
-       if (!bgp_static->backdoor)
-               bgp_static_update(bgp, &p, bgp_static, afi, safi);
+               /* Clear configuration. */
+               bgp_static_free(bgp_static);
+               rn->info = NULL;
+               bgp_unlock_node(rn);
+               bgp_unlock_node(rn);
+       } else {
 
-       return CMD_SUCCESS;
-}
+               /* Set BGP static route configuration. */
+               rn = bgp_node_get(bgp->route[afi][safi], &p);
 
-/* 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;
+               if (rn->info) {
+                       /* Configuration change. */
+                       bgp_static = rn->info;
 
-       /* 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;
-       }
+                       /* 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;
+                       }
 
-       apply_mask(&p);
+                       /* Check previous routes are installed into BGP.  */
+                       if (bgp_static->valid &&
+                           bgp_static->backdoor != backdoor)
+                               need_update = 1;
 
-       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;
-       }
+                       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;
 
-       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);
+                       }
+                       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 +5046,62 @@ 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
@@ -7388,7 +7073,7 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct prefix *p,
                                vty_out(vty, "  Imported from %s:%s\n",
                                        prefix_rd2str(
                                                (struct prefix_rd *)&prn->p,
-                                               buf1, RD_ADDRSTRLEN),
+                                               buf1, sizeof(buf1)),
                                        buf2);
                        }
                }
@@ -7601,7 +7286,7 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct prefix *p,
                                        json_peer, "routerId",
                                        inet_ntop(AF_INET,
                                                  &binfo->peer->remote_id, buf1,
-                                                 BUFSIZ));
+                                                 sizeof(buf1)));
 
                                if (binfo->peer->hostname)
                                        json_object_string_add(
@@ -7655,7 +7340,7 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct prefix *p,
                                                inet_ntop(
                                                        AF_INET,
                                                        &binfo->peer->remote_id,
-                                                       buf1, BUFSIZ));
+                                                       buf1, sizeof(buf1)));
                        }
                }
 
@@ -8174,7 +7859,7 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi,
                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));
@@ -8394,8 +8079,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,7 +8095,8 @@ 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 (json_paths)
+                       json_object_free(json_paths);
                if (is_last)
                        vty_out(vty, " } }\n");
                else
@@ -8440,6 +8127,9 @@ 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;
+       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);
@@ -8447,19 +8137,27 @@ int bgp_show_table_rd(struct vty *vty, struct bgp *bgp, safi_t safi,
                        continue;
                if (rn->info != NULL) {
                        struct prefix_rd prd;
-                       char rd[BUFSIZ];
+                       char rd[RD_ADDRSTRLEN];
 
                        memcpy(&prd, &(rn->p), sizeof(struct prefix_rd));
-                       if (prefix_rd2str(&prd, rd, BUFSIZ) == NULL)
-                               sprintf(rd,
-                                       "Unknown Type: %u",
-                                       decode_rd_type(prd.val));
+                       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);
+                       if (next == NULL)
+                               show_msg = false;
                }
        }
+       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);
+       }
        if (use_json)
                vty_out(vty, " } }");
        return CMD_SUCCESS;
@@ -8539,7 +8237,7 @@ void route_vty_out_detail_header(struct vty *vty, struct bgp *bgp,
        struct prefix *p;
        struct peer *peer;
        struct listnode *node, *nnode;
-       char buf1[INET6_ADDRSTRLEN];
+       char buf1[RD_ADDRSTRLEN];
        char buf2[INET6_ADDRSTRLEN];
 #if defined(HAVE_CUMULUS)
        char buf3[EVPN_ROUTE_STRLEN];
@@ -8573,7 +8271,7 @@ void route_vty_out_detail_header(struct vty *vty, struct bgp *bgp,
 #if defined(HAVE_CUMULUS)
                if (safi == SAFI_EVPN)
                        vty_out(vty, "BGP routing table entry for %s%s%s\n",
-                               prd ? prefix_rd2str(prd, buf1, RD_ADDRSTRLEN)
+                               prd ? prefix_rd2str(prd, buf1, sizeof(buf1))
                                    : "",
                                prd ? ":" : "",
                                bgp_evpn_route2str((struct prefix_evpn *)p,
@@ -8582,7 +8280,7 @@ 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)
                                         ? prefix_rd2str(prd, buf1,
-                                                        RD_ADDRSTRLEN)
+                                                        sizeof(buf1))
                                         : ""),
                                safi == SAFI_MPLS_VPN ? ":" : "",
                                inet_ntop(p->family, &p->u.prefix, buf2,
@@ -8597,8 +8295,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, RD_ADDRSTRLEN)
-                                : ""),
+                        ? prefix_rd2str(prd, buf1, sizeof(buf1))
+                        : ""),
                        ((safi == SAFI_MPLS_VPN) || (safi == SAFI_EVPN)) ? ":"
                                                                         : "",
                        buf2, p->prefixlen);
@@ -10569,12 +10267,17 @@ DEFUN (show_bgp_afi_vpn_rd_route,
        afi_t afi = AFI_MAX;
        int idx = 0;
 
-       (void)argv_find_and_parse_afi(argv, argc, &idx, &afi);
+       if (!argv_find_and_parse_afi(argv, argc, &idx, &afi)) {
+               vty_out(vty, "%% Malformed Address Family\n");
+               return CMD_WARNING;
+       }
+
        ret = str2prefix_rd(argv[5]->arg, &prd);
        if (!ret) {
                vty_out(vty, "%% Malformed Route Distinguisher\n");
                return CMD_WARNING;
        }
+
        return bgp_show_route(vty, NULL, argv[6]->arg, afi, SAFI_MPLS_VPN, &prd,
                              0, BGP_PATH_ALL, use_json(argc, argv));
 }
@@ -11139,7 +10842,7 @@ static void bgp_config_write_network_vpn(struct vty *vty, struct bgp *bgp,
                        prd = (struct prefix_rd *)&prn->p;
 
                        /* "network" configuration display.  */
-                       prefix_rd2str(prd, rdbuf, RD_ADDRSTRLEN);
+                       prefix_rd2str(prd, rdbuf, sizeof(rdbuf));
                        label = decode_label(&bgp_static->label);
 
                        vty_out(vty, "  network %s/%d rd %s",
@@ -11152,10 +10855,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");
                }
        }
@@ -11196,7 +10899,7 @@ static void bgp_config_write_network_evpn(struct vty *vty, struct bgp *bgp,
                        prd = (struct prefix_rd *)&prn->p;
 
                        /* "network" configuration display.  */
-                       prefix_rd2str(prd, rdbuf, RD_ADDRSTRLEN);
+                       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)
@@ -11215,7 +10918,7 @@ static void bgp_config_write_network_evpn(struct vty *vty, struct bgp *bgp,
                                          &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);
@@ -11288,10 +10991,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");
        }
@@ -11374,18 +11076,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);
@@ -11395,20 +11086,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);
@@ -11418,16 +11096,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);
@@ -11470,21 +11139,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..ae4759aad0dbc848b6a3e05f9463d77cb972a38e 100644 (file)
@@ -73,9 +73,12 @@ struct bgp_info_extra {
        /* Nexthop reachability check.  */
        u_int32_t igpmetric;
 
-       /* MPLS label.  */
+       /* MPLS label - L2VNI  */
        mpls_label_t label;
 
+       /* MPLS label - L3-VNI */
+       mpls_label_t label2;
+
 #if ENABLE_BGP_VNC
        union {
 
index 30397f84877d45bc02925299f6a6b19fdef7a231..8c9f9f65ca4e4b3894e6d27ae7d2435b41ecaca1 100644 (file)
@@ -2082,7 +2082,10 @@ static void *route_set_aggregator_as_compile(const char *arg)
 
        aggregator =
                XCALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(struct aggregator));
-       sscanf(arg, "%s %s", as, address);
+       if (sscanf(arg, "%s %s", as, address) != 2) {
+               XFREE(MTYPE_ROUTE_MAP_COMPILED, aggregator);
+               return NULL;
+       }
 
        aggregator->as = strtoul(as, NULL, 10);
        ret = inet_aton(address, &aggregator->address);
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 5515643ed1ae185fca4696c66df79ffe8937b35f..4b9f4c639a9f1481c4daab19d921fb0c27fef274 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);
@@ -1423,7 +1438,7 @@ DEFUN (no_bgp_rpkt_quanta,
 
 void bgp_config_write_coalesce_time(struct vty *vty, struct bgp *bgp)
 {
-       if (bgp->coalesce_time != BGP_DEFAULT_SUBGROUP_COALESCE_TIME)
+       if (!bgp->heuristic_coalesce)
                vty_out(vty, " coalesce-time %u\n", bgp->coalesce_time);
 }
 
@@ -1438,6 +1453,7 @@ DEFUN (bgp_coalesce_time,
 
        int idx = 0;
        argv_find(argv, argc, "(0-4294967295)", &idx);
+       bgp->heuristic_coalesce = false;
        bgp->coalesce_time = strtoul(argv[idx]->arg, NULL, 10);
        return CMD_SUCCESS;
 }
@@ -1451,6 +1467,7 @@ DEFUN (no_bgp_coalesce_time,
 {
        VTY_DECLVAR_CONTEXT(bgp, bgp);
 
+       bgp->heuristic_coalesce = true;
        bgp->coalesce_time = BGP_DEFAULT_SUBGROUP_COALESCE_TIME;
        return CMD_SUCCESS;
 }
@@ -2675,6 +2692,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"
+       "Do not automatically activate peers upon configuration\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>",
@@ -3221,7 +3251,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",
@@ -6448,6 +6477,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;
@@ -6455,8 +6485,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");
@@ -6474,7 +6502,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)
@@ -6482,7 +6509,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)
@@ -6505,8 +6535,10 @@ 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",
@@ -6516,11 +6548,19 @@ 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) {
@@ -6838,10 +6878,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;
+                               (bgp->vrf_id == VRF_UNKNOWN) ? -1 :
+                               (int64_t)bgp->vrf_id;
 
                        /* Usage summary and header */
                        if (use_json) {
@@ -6860,7 +6901,8 @@ 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");
                        }
 
@@ -7051,17 +7093,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]);
@@ -7118,48 +7152,18 @@ 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)");
@@ -7721,7 +7725,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");
                }
@@ -7993,7 +7997,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");
                }
 
@@ -8286,17 +8290,29 @@ 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,
@@ -9327,34 +9343,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. */
@@ -9363,25 +9389,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) {
@@ -9831,7 +9870,6 @@ 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));
                json_object_free(json);
@@ -9843,12 +9881,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");
@@ -9865,8 +9906,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);
+                                           ? -1 : (int64_t) bgp->vrf_id);
                        json_object_string_add(
                                json, "vrfName",
                                (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)
@@ -9888,8 +9928,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)
@@ -9907,7 +9958,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);
@@ -11556,6 +11608,9 @@ void bgp_vty_init(void)
        install_element(BGP_NODE, &bgp_listen_range_cmd);
        install_element(BGP_NODE, &no_bgp_listen_range_cmd);
 
+       /* "neighbors auto-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 1cf04abfce69a32c7a9682133cdaaf5784aa9548..de170fdd0135b274369fae45ccb9afade18b1402 100644 (file)
@@ -999,7 +999,9 @@ 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.nh_vrf_id = bgp->vrf_id;
        api.type = ZEBRA_ROUTE_BGP;
        api.safi = safi;
        api.prefix = *p;
@@ -1015,6 +1017,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 +1081,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;
+
+                       /* 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;
@@ -1126,8 +1142,8 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p,
                        api_nh->type = NEXTHOP_TYPE_IPV6_IFINDEX;
                }
 
-               if (mpinfo->extra
-                   && bgp_is_valid_label(&mpinfo->extra->label)) {
+               if (mpinfo->extra && bgp_is_valid_label(&mpinfo->extra->label)
+                   && !CHECK_FLAG(api.flags, ZEBRA_FLAG_EVPN_ROUTE)) {
                        has_valid_label = 1;
                        label = label_pton(&mpinfo->extra->label);
 
@@ -1137,7 +1153,9 @@ 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 +1197,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 +1252,20 @@ 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.nh_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 +1544,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],
@@ -1550,7 +1579,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)
+           && is_evpn_enabled())
                bgp_zebra_advertise_all_vni(bgp, 1);
 }
 
@@ -1569,7 +1598,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)
+           && is_evpn_enabled())
                bgp_zebra_advertise_all_vni(bgp, 0);
 
        /* Deregister for router-id, interfaces, redistributed routes. */
@@ -1675,6 +1704,39 @@ 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)
 {
@@ -1682,23 +1744,29 @@ static int bgp_zebra_process_local_vni(int command, struct zclient *zclient,
        vni_t vni;
        struct bgp *bgp;
        struct in_addr vtep_ip;
+       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);
 }
@@ -1782,6 +1850,8 @@ 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;
 }
 
 void bgp_zebra_destroy(void)
index 8b27a0e905fd4f8d3a9a8695fb65937f2e3488f4..19f0c8cabf6c4d10da4bc116b060534f3b700a68 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;
@@ -912,7 +910,7 @@ static void peer_global_config_reset(struct peer *peer)
 }
 
 /* Check peer's AS number and determines if this peer is IBGP or EBGP */
-static bgp_peer_sort_t peer_calc_sort(struct peer *peer)
+static inline bgp_peer_sort_t peer_calc_sort(struct peer *peer)
 {
        struct bgp *bgp;
 
@@ -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);
@@ -1204,7 +1202,7 @@ void peer_xfer_config(struct peer *peer_dst, struct peer *peer_src)
        peer_dst->local_as = peer_src->local_as;
        peer_dst->ifindex = peer_src->ifindex;
        peer_dst->port = peer_src->port;
-       peer_sort(peer_dst);
+       (void)peer_sort(peer_dst);
        peer_dst->rmap_type = peer_src->rmap_type;
 
        /* Timers */
@@ -1475,9 +1473,12 @@ struct peer *peer_create(union sockunion *su, const char *conf_if,
        hash_get(bgp->peerhash, peer, hash_alloc_intern);
 
        /* Adjust update-group coalesce timer heuristics for # peers. */
-       long ct = BGP_DEFAULT_SUBGROUP_COALESCE_TIME
-                 + (bgp->peer->count * BGP_PEER_ADJUST_SUBGROUP_COALESCE_TIME);
-       bgp->coalesce_time = MIN(BGP_MAX_SUBGROUP_COALESCE_TIME, ct);
+       if (bgp->heuristic_coalesce) {
+               long ct = BGP_DEFAULT_SUBGROUP_COALESCE_TIME
+                         + (bgp->peer->count
+                            * BGP_PEER_ADJUST_SUBGROUP_COALESCE_TIME);
+               bgp->coalesce_time = MIN(BGP_MAX_SUBGROUP_COALESCE_TIME, ct);
+       }
 
        active = peer_active(peer);
 
@@ -1494,8 +1495,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;
@@ -2176,7 +2180,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;
        }
 
@@ -2336,7 +2340,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;
 
@@ -2354,14 +2358,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;
@@ -3139,6 +3140,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);
@@ -7077,6 +7081,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);
 
@@ -7140,6 +7149,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 auto-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");
@@ -7301,6 +7314,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);
 
@@ -7361,6 +7406,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);
 
@@ -7418,24 +7470,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(io, NULL);
+       frr_pthread_run(ka, NULL);
 
-       frr_pthread_run(PTHREAD_IO, &attr, NULL);
-       frr_pthread_run(PTHREAD_KEEPALIVES, &attr, NULL);
+       /* Wait until threads are ready. */
+       frr_pthread_wait_running(io);
+       frr_pthread_wait_running(ka);
 }
 
 void bgp_pthreads_finish()
@@ -7517,6 +7578,7 @@ void bgp_terminate(void)
         */
        /* reverse bgp_master_init */
        bgp_close();
+
        if (bm->listen_sockets)
                list_delete_and_null(&bm->listen_sockets);
 
index e5e363ef52252552b7b6aa15be32ed35ef780576..c4ac4b0adb05d8e5f0c1cf15b899cc5f38c071d7 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)
@@ -381,7 +385,13 @@ struct bgp {
        _Atomic uint32_t wpkt_quanta; // max # packets to write per i/o cycle
        _Atomic uint32_t rpkt_quanta; // max # packets to read per i/o cycle
 
-       u_int32_t coalesce_time;
+       /* Automatic coalesce adjust on/off */
+       bool heuristic_coalesce;
+       /* 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];
@@ -405,8 +415,41 @@ 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;
 
        QOBJ_FIELDS
 };
@@ -595,8 +638,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
 
@@ -826,6 +869,22 @@ 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 */
@@ -860,9 +919,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;
 
@@ -1017,6 +1073,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
index 3ecc4be94eba2f683c496e4a0127aae2d19d9a13..e3cb73946474a0e2829ff2d936d18b1869ce2a25 100644 (file)
@@ -170,12 +170,12 @@ struct rfapi_nve_group_cfg *bgp_rfapi_cfg_match_group(struct rfapi_cfg *hc,
 
 #if BGP_VNC_DEBUG_MATCH_GROUP
        {
-               char buf[BUFSIZ];
+               char buf[PREFIX_STRLEN];
 
-               prefix2str(vn, buf, BUFSIZ);
+               prefix2str(vn, buf, sizeof(buf));
                vnc_zlog_debug_verbose("%s: vn prefix: %s", __func__, buf);
 
-               prefix2str(un, buf, BUFSIZ);
+               prefix2str(un, buf, sizeof(buf));
                vnc_zlog_debug_verbose("%s: un prefix: %s", __func__, buf);
 
                vnc_zlog_debug_verbose(
@@ -1626,7 +1626,11 @@ DEFUN (vnc_nve_group_export_no_prefixlist,
                return CMD_WARNING_CONFIG_FAILED;
        }
 
-       argv_find_and_parse_afi(argv, argc, &idx, &afi);
+       if (!argv_find_and_parse_afi(argv, argc, &idx, &afi)) {
+               vty_out(vty, "%% Malformed Address Family\n");
+               return CMD_WARNING_CONFIG_FAILED;
+       }
+
        if (argv[idx-1]->text[0] == 'z')
                is_bgp = 0;
        idx += 2;               /* skip afi and keyword */
@@ -1691,7 +1695,11 @@ DEFUN (vnc_nve_group_export_prefixlist,
                return CMD_WARNING_CONFIG_FAILED;
        }
 
-       argv_find_and_parse_afi(argv, argc, &idx, &afi);
+       if (!argv_find_and_parse_afi(argv, argc, &idx, &afi)) {
+               vty_out(vty, "%% Malformed Address Family\n");
+               return CMD_WARNING_CONFIG_FAILED;
+       }
+
        if (argv[idx-1]->text[0] == 'z')
                is_bgp = 0;
        idx = argc - 1;
@@ -3884,8 +3892,7 @@ int bgp_rfapi_cfg_write(struct vty *vty, struct bgp *bgp)
                        }
 
                        if (rfg->rd.prefixlen) {
-                               char buf[BUFSIZ];
-                               buf[0] = buf[BUFSIZ - 1] = 0;
+                               char buf[RD_ADDRSTRLEN];
 
                                if (AF_UNIX == rfg->rd.family) {
 
@@ -3898,18 +3905,10 @@ int bgp_rfapi_cfg_write(struct vty *vty, struct bgp *bgp)
                                        vty_out(vty, "  rd auto:nh:%d\n",
                                                value);
 
-                               } else {
-
-                                       if (!prefix_rd2str(&rfg->rd, buf,
-                                                          BUFSIZ)
-                                           || !buf[0] || buf[BUFSIZ - 1]) {
-
-                                               vty_out(vty,
-                                                       "!Error: Can't convert rd\n");
-                                       } else {
-                                               vty_out(vty, "  rd %s\n", buf);
-                                       }
-                               }
+                               } else
+                                       vty_out(vty, "  rd %s\n",
+                                               prefix_rd2str(&rfg->rd, buf,
+                                                             sizeof(buf)));
                        }
 
                        if (rfg->rt_import_list && rfg->rt_export_list
@@ -4098,7 +4097,8 @@ 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) {
 
@@ -4107,8 +4107,7 @@ int bgp_rfapi_cfg_write(struct vty *vty, struct bgp *bgp)
                        vty_out(vty, " vnc defaults\n");
 
                        if (hc->default_rd.prefixlen) {
-                               char buf[BUFSIZ];
-                               buf[0] = buf[BUFSIZ - 1] = 0;
+                               char buf[RD_ADDRSTRLEN];
 
                                if (AF_UNIX == hc->default_rd.family) {
                                        uint16_t value = 0;
@@ -4121,20 +4120,14 @@ int bgp_rfapi_cfg_write(struct vty *vty, struct bgp *bgp)
                                        vty_out(vty, "  rd auto:vn:%d\n",
                                                value);
 
-                               } else {
-
-                                       if (!prefix_rd2str(&hc->default_rd, buf,
-                                                          BUFSIZ)
-                                           || !buf[0] || buf[BUFSIZ - 1]) {
-
-                                               vty_out(vty,
-                                                       "!Error: Can't convert rd\n");
-                                       } else {
-                                               vty_out(vty, "  rd %s\n", buf);
-                                       }
-                               }
+                               } else
+                                       vty_out(vty, "  rd %s\n",
+                                               prefix_rd2str(&hc->default_rd,
+                                                             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",
@@ -4187,38 +4180,26 @@ int bgp_rfapi_cfg_write(struct vty *vty, struct bgp *bgp)
                                vty_out(vty, " vnc nve-group %s\n", rfg->name);
 
                                if (rfg->vn_prefix.family && rfg->vn_node) {
-                                       char buf[BUFSIZ];
-                                       buf[0] = buf[BUFSIZ - 1] = 0;
+                                       char buf[PREFIX_STRLEN];
 
                                        prefix2str(&rfg->vn_prefix, buf,
-                                                  BUFSIZ);
-                                       if (!buf[0] || buf[BUFSIZ - 1]) {
-                                               vty_out(vty,
-                                                       "!Error: Can't convert prefix\n");
-                                       } else {
-                                               vty_out(vty, "  prefix %s %s\n",
-                                                       "vn", buf);
-                                       }
+                                                  sizeof(buf));
+                                       vty_out(vty, "  prefix %s %s\n",
+                                               "vn", buf);
                                }
 
                                if (rfg->un_prefix.family && rfg->un_node) {
-                                       char buf[BUFSIZ];
-                                       buf[0] = buf[BUFSIZ - 1] = 0;
+                                       char buf[PREFIX_STRLEN];
+
                                        prefix2str(&rfg->un_prefix, buf,
-                                                  BUFSIZ);
-                                       if (!buf[0] || buf[BUFSIZ - 1]) {
-                                               vty_out(vty,
-                                                       "!Error: Can't convert prefix\n");
-                                       } else {
-                                               vty_out(vty, "  prefix %s %s\n",
-                                                       "un", buf);
-                                       }
+                                                  sizeof(buf));
+                                       vty_out(vty, "  prefix %s %s\n",
+                                               "un", buf);
                                }
 
 
                                if (rfg->rd.prefixlen) {
-                                       char buf[BUFSIZ];
-                                       buf[0] = buf[BUFSIZ - 1] = 0;
+                                       char buf[RD_ADDRSTRLEN];
 
                                        if (AF_UNIX == rfg->rd.family) {
 
@@ -4233,21 +4214,12 @@ int bgp_rfapi_cfg_write(struct vty *vty, struct bgp *bgp)
                                                        "  rd auto:vn:%d\n",
                                                        value);
 
-                                       } else {
-
-                                               if (!prefix_rd2str(&rfg->rd,
-                                                                  buf, BUFSIZ)
-                                                   || !buf[0]
-                                                   || buf[BUFSIZ - 1]) {
-
-                                                       vty_out(vty,
-                                                               "!Error: Can't convert rd\n");
-                                               } else {
-                                                       vty_out(vty,
-                                                               "  rd %s\n",
-                                                               buf);
-                                               }
-                                       }
+                                       } else
+                                               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 fa3da9c283045f9449a2d54537708f3b39b7ade2..95666143a5c5a9723e70f789d59e52193f8c0487 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"
@@ -363,15 +364,11 @@ void del_vnc_route(struct rfapi_descriptor *rfd,
        afi_t afi; /* of the VN address */
        struct bgp_node *bn;
        struct bgp_info *bi;
-       char buf[BUFSIZ];
-       char buf2[BUFSIZ];
+       char buf[PREFIX_STRLEN];
+       char buf2[RD_ADDRSTRLEN];
        struct prefix_rd prd0;
 
-       prefix2str(p, buf, BUFSIZ);
-       buf[BUFSIZ - 1] = 0; /* guarantee NUL-terminated */
-
-       prefix_rd2str(prd, buf2, BUFSIZ);
-       buf2[BUFSIZ - 1] = 0;
+       prefix2str(p, buf, sizeof(buf));
 
        afi = family2afi(p->family);
        assert(afi == AFI_IP || afi == AFI_IP6);
@@ -386,7 +383,8 @@ void del_vnc_route(struct rfapi_descriptor *rfd,
 
        vnc_zlog_debug_verbose(
                "%s: peer=%p, prefix=%s, prd=%s afi=%d, safi=%d bn=%p, bn->info=%p",
-               __func__, peer, buf, buf2, afi, safi, bn,
+               __func__, peer, buf,
+               prefix_rd2str(prd, buf2, sizeof(buf2)), afi, safi, bn,
                (bn ? bn->info : NULL));
 
        for (bi = (bn ? bn->info : NULL); bi; bi = bi->next) {
@@ -464,11 +462,9 @@ void del_vnc_route(struct rfapi_descriptor *rfd,
        rfapiProcessWithdraw(peer, rfd, p, prd, NULL, afi, safi, type, kill);
 
        if (bi) {
-               char buf[BUFSIZ];
-
-               prefix2str(p, buf, BUFSIZ);
-               buf[BUFSIZ - 1] = 0; /* guarantee NUL-terminated */
+               char buf[PREFIX_STRLEN];
 
+               prefix2str(p, buf, sizeof(buf));
                vnc_zlog_debug_verbose(
                        "%s: Found route (safi=%d) to delete at prefix %s",
                        __func__, safi, buf);
@@ -593,8 +589,8 @@ void add_vnc_route(struct rfapi_descriptor *rfd, /* cookie, VPN UN addr, peer */
        uint32_t label_val;
 
        struct bgp_attr_encap_subtlv *encaptlv;
-       char buf[BUFSIZ];
-       char buf2[BUFSIZ];
+       char buf[PREFIX_STRLEN];
+       char buf2[RD_ADDRSTRLEN];
 #if 0 /* unused? */
   struct prefix pfx_buf;
 #endif
@@ -650,9 +646,7 @@ void add_vnc_route(struct rfapi_descriptor *rfd, /* cookie, VPN UN addr, peer */
        else
                label_val = MPLS_LABEL_IMPLICIT_NULL;
 
-       prefix_rd2str(prd, buf2, BUFSIZ);
-       buf2[BUFSIZ - 1] = 0;
-
+       prefix_rd2str(prd, buf2, sizeof(buf2));
 
        afi = family2afi(p->family);
        assert(afi == AFI_IP || afi == AFI_IP6);
@@ -907,8 +901,7 @@ void add_vnc_route(struct rfapi_descriptor *rfd, /* cookie, VPN UN addr, peer */
        }
 
 
-       prefix2str(p, buf, BUFSIZ);
-       buf[BUFSIZ - 1] = 0; /* guarantee NUL-terminated */
+       prefix2str(p, buf, sizeof(buf));
 
        /*
         * At this point:
@@ -920,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;
@@ -1318,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);
 
@@ -1611,11 +1604,10 @@ rfapi_query_inner(void *handle, struct rfapi_ip_addr *target,
        }
 
        {
-               char buf[BUFSIZ];
+               char buf[PREFIX_STRLEN];
                char *s;
 
-               prefix2str(&p, buf, BUFSIZ);
-               buf[BUFSIZ - 1] = 0; /* guarantee NUL-terminated */
+               prefix2str(&p, buf, sizeof(buf));
                vnc_zlog_debug_verbose("%s(rfd=%p, target=%s, ppNextHop=%p)",
                                       __func__, rfd, buf, ppNextHopEntry);
 
@@ -2434,10 +2426,9 @@ int rfapi_register(void *handle, struct rfapi_ip_prefix *prefix,
 
 
        {
-               char buf[BUFSIZ];
+               char buf[PREFIX_STRLEN];
 
-               prefix2str(&p, buf, BUFSIZ);
-               buf[BUFSIZ - 1] = 0; /* guarantee NUL-terminated */
+               prefix2str(&p, buf, sizeof(buf));
                vnc_zlog_debug_verbose(
                        "%s(rfd=%p, pfx=%s, lifetime=%d, opts_un=%p, opts_vn=%p, action=%s)",
                        __func__, rfd, buf, lifetime, options_un, options_vn,
@@ -3841,12 +3832,10 @@ int rfapi_set_autord_from_vn(struct prefix_rd *rd, struct rfapi_ip_addr *vn)
                       4); /* low order 4 bytes */
        }
        {
-               char buf[BUFSIZ];
-               buf[0] = 0;
-               prefix_rd2str(rd, buf, BUFSIZ);
-               buf[BUFSIZ - 1] = 0;
+               char buf[RD_ADDRSTRLEN];
+
                vnc_zlog_debug_verbose("%s: auto-RD is set to %s", __func__,
-                                      buf);
+                                      prefix_rd2str(rd, buf, sizeof(buf)));
        }
        return 0;
 }
index cdbc88c967ad47115fef733f0a2cfaf30f4e3ad7..8727c5d5ea5c20a1bb1eae186387df7ffd2935af 100644 (file)
@@ -41,6 +41,7 @@
 #include "bgpd/bgp_route.h"
 #include "bgpd/bgp_mplsvpn.h" /* prefix_rd2str() */
 #include "bgpd/bgp_vnc_types.h"
+#include "bgpd/bgp_rd.h"
 
 #include "bgpd/rfapi/rfapi.h"
 #include "bgpd/rfapi/bgp_rfapi_cfg.h"
@@ -645,10 +646,9 @@ rfapiMonitorMoveShorter(struct route_node *original_vpn_node, int lockoffset)
 
 #if DEBUG_MONITOR_MOVE_SHORTER
        {
-               char buf[BUFSIZ];
+               char buf[PREFIX_STRLEN];
 
-               prefix2str(&original_vpn_node->p, buf, BUFSIZ);
-               buf[BUFSIZ - 1] = 0;
+               prefix2str(&original_vpn_node->p, buf, sizeof(buf));
                vnc_zlog_debug_verbose("%s: called with node pfx=%s", __func__,
                                       buf);
        }
@@ -779,10 +779,9 @@ rfapiMonitorMoveShorter(struct route_node *original_vpn_node, int lockoffset)
 
 #if DEBUG_MONITOR_MOVE_SHORTER
        {
-               char buf[BUFSIZ];
+               char buf[PREFIX_STRLEN];
 
-               prefix2str(&par->p, buf, BUFSIZ);
-               buf[BUFSIZ - 1] = 0;
+               prefix2str(&par->p, buf, sizeof(buf));
                vnc_zlog_debug_verbose("%s: moved to node pfx=%s", __func__,
                                       buf);
        }
@@ -1452,7 +1451,7 @@ rfapiRouteInfo2NextHopEntry(struct rfapi_ip_prefix *rprefix,
                                       __func__, __LINE__, have_vnc_tunnel_un);
 #endif
 
-               if (!have_vnc_tunnel_un && bi && bi->extra) {
+               if (!have_vnc_tunnel_un && bi->extra) {
                        /*
                         * use cached UN address from ENCAP route
                         */
@@ -1594,10 +1593,9 @@ static int rfapiNhlAddNodeRoutes(
                }
                if (!skiplist_search(seen_nexthops, &pfx_vn, NULL)) {
 #if DEBUG_RETURNED_NHL
-                       char buf[BUFSIZ];
+                       char buf[PREFIX_STRLEN];
 
-                       prefix2str(&pfx_vn, buf, BUFSIZ);
-                       buf[BUFSIZ - 1] = 0; /* guarantee NUL-terminated */
+                       prefix2str(&pfx_vn, buf, sizeof(buf));
                        vnc_zlog_debug_verbose(
                                "%s: already put VN/nexthop %s, skip", __func__,
                                buf);
@@ -1760,10 +1758,9 @@ struct rfapi_next_hop_entry *rfapiRouteNode2NextHopList(
 
 #if DEBUG_RETURNED_NHL
        {
-               char buf[BUFSIZ];
+               char buf[PREFIX_STRLEN];
 
-               prefix2str(&rn->p, buf, BUFSIZ);
-               buf[BUFSIZ - 1] = 0;
+               prefix2str(&rn->p, buf, sizeof(buf));
                vnc_zlog_debug_verbose("%s: called with node pfx=%s", __func__,
                                       buf);
        }
@@ -2136,10 +2133,12 @@ static void rfapiItBiIndexAdd(struct route_node *rn, /* Import table VPN node */
        assert(bi->extra);
 
        {
-               char buf[BUFSIZ];
-               prefix_rd2str(&bi->extra->vnc.import.rd, buf, BUFSIZ);
+               char buf[RD_ADDRSTRLEN];
+
                vnc_zlog_debug_verbose("%s: bi %p, peer %p, rd %s", __func__,
-                                      bi, bi->peer, buf);
+                                      bi, bi->peer,
+                                      prefix_rd2str(&bi->extra->vnc.import.rd,
+                                                    buf, sizeof(buf)));
        }
 
        sl = RFAPI_RDINDEX_W_ALLOC(rn);
@@ -2173,18 +2172,15 @@ static void rfapiItBiIndexDump(struct route_node *rn)
        for (rc = skiplist_next(sl, (void **)&k, (void **)&v, &cursor); !rc;
             rc = skiplist_next(sl, (void **)&k, (void **)&v, &cursor)) {
 
-               char buf[BUFSIZ];
-               char buf_aux_pfx[BUFSIZ];
+               char buf[RD_ADDRSTRLEN];
+               char buf_aux_pfx[PREFIX_STRLEN];
 
-               prefix_rd2str(&k->extra->vnc.import.rd, buf, BUFSIZ);
-               buf_aux_pfx[0] = 0;
+               prefix_rd2str(&k->extra->vnc.import.rd, buf, sizeof(buf));
                if (k->extra->vnc.import.aux_prefix.family) {
                        prefix2str(&k->extra->vnc.import.aux_prefix,
-                                  buf_aux_pfx, BUFSIZ);
-               } else {
-                       strncpy(buf_aux_pfx, "(none)", BUFSIZ);
-                       buf_aux_pfx[BUFSIZ - 1] = 0;
-               }
+                                  buf_aux_pfx, sizeof(buf_aux_pfx));
+               } else
+                       strncpy(buf_aux_pfx, "(none)", PREFIX_STRLEN);
 
                vnc_zlog_debug_verbose("bi %p, peer %p, rd %s, aux_prefix %s",
                                       k, k->peer, buf, buf_aux_pfx);
@@ -2208,19 +2204,19 @@ static struct bgp_info *rfapiItBiIndexSearch(
 
 #if DEBUG_BI_SEARCH
        {
-               char buf[BUFSIZ];
-               char buf_aux_pfx[BUFSIZ];
+               char buf[RD_ADDRSTRLEN];
+               char buf_aux_pfx[PREFIX_STRLEN];
 
-               prefix_rd2str(prd, buf, BUFSIZ);
                if (aux_prefix) {
-                       prefix2str(aux_prefix, buf_aux_pfx, BUFSIZ);
-               } else {
-                       strncpy(buf_aux_pfx, "(nil)", BUFSIZ - 1);
-                       buf_aux_pfx[BUFSIZ - 1] = 0;
-               }
+                       prefix2str(aux_prefix, buf_aux_pfx,
+                                  sizeof(buf_aux_pfx));
+               } else
+                       strncpy(buf_aux_pfx, "(nil)", sizeof(buf_aux_pfx));
 
                vnc_zlog_debug_verbose("%s want prd=%s, peer=%p, aux_prefix=%s",
-                                      __func__, buf, peer, buf_aux_pfx);
+                                      __func__,
+                                      prefix_rd2str(prd, buf, sizeof(buf)),
+                                      peer, buf_aux_pfx);
                rfapiItBiIndexDump(rn);
        }
 #endif
@@ -2235,12 +2231,14 @@ static struct bgp_info *rfapiItBiIndexSearch(
                     bi_result = bi_result->next) {
 #if DEBUG_BI_SEARCH
                        {
-                               char buf[BUFSIZ];
-                               prefix_rd2str(&bi_result->extra->vnc.import.rd,
-                                             buf, BUFSIZ);
+                               char buf[RD_ADDRSTRLEN];
+
                                vnc_zlog_debug_verbose(
                                        "%s: bi has prd=%s, peer=%p", __func__,
-                                       buf, bi_result->peer);
+                                       prefix_rd2str(&bi_result->extra->vnc.import.rd,
+                                                     buf,
+                                                     sizeof(buf)),
+                                       bi_result->peer);
                        }
 #endif
                        if (peer == bi_result->peer
@@ -2303,10 +2301,12 @@ static void rfapiItBiIndexDel(struct route_node *rn, /* Import table VPN node */
        int rc;
 
        {
-               char buf[BUFSIZ];
-               prefix_rd2str(&bi->extra->vnc.import.rd, buf, BUFSIZ);
+               char buf[RD_ADDRSTRLEN];
+
                vnc_zlog_debug_verbose("%s: bi %p, peer %p, rd %s", __func__,
-                                      bi, bi->peer, buf);
+                                      bi, bi->peer,
+                                      prefix_rd2str(&bi->extra->vnc.import.rd,
+                                                    buf, sizeof(buf)));
        }
 
        sl = RFAPI_RDINDEX(rn);
@@ -3671,9 +3671,9 @@ void rfapiBgpInfoFilteredImportVPN(
                rfapiCopyUnEncap2VPN(ern->info, info_new);
                route_unlock_node(ern); /* undo lock in route_note_match */
        } else {
-               char buf[BUFSIZ];
+               char buf[PREFIX_STRLEN];
+
                prefix2str(&vn_prefix, buf, sizeof(buf));
-               buf[BUFSIZ - 1] = 0;
                /* Not a big deal, just means VPN route got here first */
                vnc_zlog_debug_verbose("%s: no encap route for vn addr %s",
                                       __func__, buf);
@@ -3947,7 +3947,7 @@ void rfapiProcessUpdate(struct peer *peer,
                vnc_zlog_debug_verbose(
                        "%s: rfapiEcommunityGetLNI returned %d, lni=%d, attr=%p",
                        __func__, rc, lni, attr);
-               if (attr && !rc) {
+               if (!rc) {
                        it = rfapiMacImportTableGet(bgp, lni);
 
                        rfapiBgpInfoFilteredImportVPN(
@@ -4433,10 +4433,10 @@ static void rfapiDeleteRemotePrefixesIt(
 
 #if DEBUG_L2_EXTRA
        {
-               char buf_pfx[BUFSIZ];
+               char buf_pfx[PREFIX_STRLEN];
 
                if (p) {
-                       prefix2str(p, buf_pfx, BUFSIZ);
+                       prefix2str(p, buf_pfx, sizeof(buf_pfx));
                } else {
                        buf_pfx[0] = '*';
                        buf_pfx[1] = 0;
@@ -4469,11 +4469,11 @@ static void rfapiDeleteRemotePrefixesIt(
                        struct bgp_info *next;
 
                        if (VNC_DEBUG(IMPORT_DEL_REMOTE)) {
-                               char p1line[BUFSIZ];
-                               char p2line[BUFSIZ];
+                               char p1line[PREFIX_STRLEN];
+                               char p2line[PREFIX_STRLEN];
 
-                               prefix2str(p, p1line, BUFSIZ);
-                               prefix2str(&rn->p, p2line, BUFSIZ);
+                               prefix2str(p, p1line, sizeof(p1line));
+                               prefix2str(&rn->p, p2line, sizeof(p2line));
                                vnc_zlog_debug_any("%s: want %s, have %s",
                                                   __func__, p1line, p2line);
                        }
@@ -4482,8 +4482,9 @@ static void rfapiDeleteRemotePrefixesIt(
                                continue;
 
                        {
-                               char buf_pfx[BUFSIZ];
-                               prefix2str(&rn->p, buf_pfx, BUFSIZ);
+                               char buf_pfx[PREFIX_STRLEN];
+
+                               prefix2str(&rn->p, buf_pfx, sizeof(buf_pfx));
                                vnc_zlog_debug_verbose("%s: rn pfx=%s",
                                                       __func__, buf_pfx);
                        }
index 47a72d75fd40c05238522d7221b1fe9c2b0aed9a..5c222b6dda823b23d6cbc1bc69fb50e2ac973553 100644 (file)
@@ -839,7 +839,7 @@ void rfapiMonitorItNodeChanged(
        struct bgp *bgp = bgp_get_default();
        afi_t afi = family2afi(rn->p.family);
 #if DEBUG_L2_EXTRA
-       char buf_prefix[BUFSIZ];
+       char buf_prefix[PREFIX_STRLEN];
 #endif
 
        assert(bgp);
@@ -848,7 +848,7 @@ void rfapiMonitorItNodeChanged(
        nves_seen = skiplist_new(0, NULL, NULL);
 
 #if DEBUG_L2_EXTRA
-       prefix2str(&it_node->p, buf_prefix, BUFSIZ);
+       prefix2str(&it_node->p, buf_prefix, sizeof(buf_prefix));
        vnc_zlog_debug_verbose("%s: it=%p, it_node=%p, it_node->prefix=%s",
                               __func__, import_table, it_node, buf_prefix);
 #endif
@@ -926,22 +926,20 @@ void rfapiMonitorItNodeChanged(
                                        assert(!skiplist_insert(nves_seen,
                                                                m->rfd, NULL));
 
-                                       {
-                                               char buf_attach_pfx[BUFSIZ];
-                                               char buf_target_pfx[BUFSIZ];
-
-                                               prefix2str(&m->node->p,
-                                                          buf_attach_pfx,
-                                                          BUFSIZ);
-                                               prefix2str(&m->p,
-                                                          buf_target_pfx,
-                                                          BUFSIZ);
-                                               vnc_zlog_debug_verbose(
-                                                       "%s: update rfd %p attached to pfx %s (targ=%s)",
-                                                       __func__, m->rfd,
-                                                       buf_attach_pfx,
-                                                       buf_target_pfx);
-                                       }
+                                       char buf_attach_pfx[PREFIX_STRLEN];
+                                       char buf_target_pfx[PREFIX_STRLEN];
+
+                                       prefix2str(&m->node->p,
+                                                  buf_attach_pfx,
+                                                  sizeof(buf_attach_pfx));
+                                       prefix2str(&m->p,
+                                                  buf_target_pfx,
+                                                  sizeof(buf_target_pfx));
+                                       vnc_zlog_debug_verbose(
+                                               "%s: update rfd %p attached to pfx %s (targ=%s)",
+                                               __func__, m->rfd,
+                                               buf_attach_pfx,
+                                               buf_target_pfx);
 
                                        /*
                                         * update its RIB
@@ -1271,8 +1269,9 @@ static void rfapiMonitorEthDetachImport(
        assert(rn);
 
 #if DEBUG_L2_EXTRA
-       char buf_prefix[BUFSIZ];
-       prefix2str(&rn->p, buf_prefix, BUFSIZ);
+       char buf_prefix[PREFIX_STRLEN];
+
+       prefix2str(&rn->p, buf_prefix, sizeof(buf_prefix));
 #endif
 
        /*
index 36ae6e7273776644e6738bd5a7bdcb75513a981a..bd79518bfd75c7caa2d4d19d39508faf8ddaed49 100644 (file)
@@ -207,7 +207,7 @@ void rfapiRibCheckCounts(
                }
        }
 
-       if (checkstats && bgp && bgp->rfapi) {
+       if (checkstats && bgp->rfapi) {
                if (t_pfx_active != bgp->rfapi->rib_prefix_count_total) {
                        vnc_zlog_debug_verbose(
                                "%s: actual total pfx count %u != running %u",
@@ -342,7 +342,7 @@ rfapiRibStartTimer(struct rfapi_descriptor *rfd, struct rfapi_info *ri,
 {
        struct thread *t = ri->timer;
        struct rfapi_rib_tcb *tcb = NULL;
-       char buf_prefix[BUFSIZ];
+       char buf_prefix[PREFIX_STRLEN];
 
        if (t) {
                tcb = t->arg;
@@ -363,7 +363,7 @@ rfapiRibStartTimer(struct rfapi_descriptor *rfd, struct rfapi_info *ri,
                UNSET_FLAG(tcb->flags, RFAPI_RIB_TCB_FLAG_DELETED);
        }
 
-       prefix2str(&rn->p, buf_prefix, BUFSIZ);
+       prefix2str(&rn->p, buf_prefix, sizeof(buf_prefix));
        vnc_zlog_debug_verbose("%s: rfd %p pfx %s life %u", __func__, rfd,
                               buf_prefix, ri->lifetime);
        ri->timer = NULL;
@@ -688,13 +688,10 @@ static void rfapiRibBi2Ri(struct bgp_info *bi, struct rfapi_info *ri,
                memcpy(&vo->v.l2addr.macaddr, bi->extra->vnc.import.rd.val + 2,
                       ETH_ALEN);
 
-               if (bi->attr) {
-                       (void)rfapiEcommunityGetLNI(
-                               bi->attr->ecommunity,
-                               &vo->v.l2addr.logical_net_id);
-                       (void)rfapiEcommunityGetEthernetTag(
-                               bi->attr->ecommunity, &vo->v.l2addr.tag_id);
-               }
+               (void)rfapiEcommunityGetLNI(bi->attr->ecommunity,
+                                           &vo->v.l2addr.logical_net_id);
+               (void)rfapiEcommunityGetEthernetTag(bi->attr->ecommunity,
+                                                   &vo->v.l2addr.tag_id);
 
                /* local_nve_id comes from RD */
                vo->v.l2addr.local_nve_id = bi->extra->vnc.import.rd.val[1];
@@ -710,7 +707,7 @@ static void rfapiRibBi2Ri(struct bgp_info *bi, struct rfapi_info *ri,
        /*
         * If there is an auxiliary IP address (L2 can have it), copy it
         */
-       if (bi && bi->extra && bi->extra->vnc.import.aux_prefix.family) {
+       if (bi->extra && bi->extra->vnc.import.aux_prefix.family) {
                ri->rk.aux_prefix = bi->extra->vnc.import.aux_prefix;
        }
 }
@@ -855,7 +852,7 @@ static void process_pending_node(struct bgp *bgp, struct rfapi_descriptor *rfd,
        struct list *lPendCost = NULL;
        struct list *delete_list = NULL;
        int printedprefix = 0;
-       char buf_prefix[BUFSIZ];
+       char buf_prefix[PREFIX_STRLEN];
        int rib_node_started_nonempty = 0;
        int sendingsomeroutes = 0;
 
@@ -866,7 +863,7 @@ static void process_pending_node(struct bgp *bgp, struct rfapi_descriptor *rfd,
 #endif
 
        assert(pn);
-       prefix2str(&pn->p, buf_prefix, BUFSIZ);
+       prefix2str(&pn->p, buf_prefix, sizeof(buf_prefix));
        vnc_zlog_debug_verbose("%s: afi=%d, %s pn->info=%p", __func__, afi,
                               buf_prefix, pn->info);
 
@@ -916,8 +913,8 @@ static void process_pending_node(struct bgp *bgp, struct rfapi_descriptor *rfd,
                        while (0
                               == skiplist_first(slRibPt, NULL, (void **)&ri)) {
 
-                               char buf[BUFSIZ];
-                               char buf2[BUFSIZ];
+                               char buf[PREFIX_STRLEN];
+                               char buf2[PREFIX_STRLEN];
 
                                listnode_add(delete_list, ri);
                                vnc_zlog_debug_verbose(
@@ -935,8 +932,8 @@ static void process_pending_node(struct bgp *bgp, struct rfapi_descriptor *rfd,
                                        ri->timer = NULL;
                                }
 
-                               prefix2str(&ri->rk.vn, buf, BUFSIZ);
-                               prefix2str(&ri->un, buf2, BUFSIZ);
+                               prefix2str(&ri->rk.vn, buf, sizeof(buf));
+                               prefix2str(&ri->un, buf2, sizeof(buf2));
                                vnc_zlog_debug_verbose(
                                        "%s:   put dl pfx=%s vn=%s un=%s cost=%d life=%d vn_options=%p",
                                        __func__, buf_prefix, buf, buf2,
@@ -1126,7 +1123,7 @@ static void process_pending_node(struct bgp *bgp, struct rfapi_descriptor *rfd,
 
                        } else {
 
-                               char buf_rd[BUFSIZ];
+                               char buf_rd[RD_ADDRSTRLEN];
 
                                /* not found: add new route to RIB */
                                ori = rfapi_info_new();
@@ -1405,13 +1402,14 @@ callback:
                                        ri->last_sent_time = rfapi_time(NULL);
 #if DEBUG_RIB_SL_RD
                                        {
-                                               char buf_rd[BUFSIZ];
-                                               prefix_rd2str(&ri->rk.rd,
-                                                             buf_rd,
-                                                             sizeof(buf_rd));
+                                               char buf_rd[RD_ADDRSTRLEN];
+
                                                vnc_zlog_debug_verbose(
                                                        "%s: move route to recently deleted list, rd=%s",
-                                                       __func__, buf_rd);
+                                                       __func__,
+                                                       prefix_rd2str(&ri->rk.rd,
+                                                                     buf_rd,
+                                                                     sizeof(buf_rd)));
                                        }
 #endif
 
@@ -1595,7 +1593,7 @@ void rfapiRibUpdatePendingNode(
        afi_t afi;
        uint32_t queued_flag;
        int count = 0;
-       char buf[BUFSIZ];
+       char buf[PREFIX_STRLEN];
 
        vnc_zlog_debug_verbose("%s: entry", __func__);
 
@@ -1608,7 +1606,7 @@ void rfapiRibUpdatePendingNode(
 
        prefix = &it_node->p;
        afi = family2afi(prefix->family);
-       prefix2str(prefix, buf, BUFSIZ);
+       prefix2str(prefix, buf, sizeof(buf));
        vnc_zlog_debug_verbose("%s: prefix=%s", __func__, buf);
 
        pn = route_node_get(rfd->rib_pending[afi], prefix);
@@ -1814,9 +1812,9 @@ int rfapiRibFTDFilterRecentPrefix(
 
 #if DEBUG_FTD_FILTER_RECENT
        {
-               char buf_pfx[BUFSIZ];
+               char buf_pfx[PREFIX_STRLEN];
 
-               prefix2str(&it_rn->p, buf_pfx, BUFSIZ);
+               prefix2str(&it_rn->p, buf_pfx, sizeof(buf_pfx));
                vnc_zlog_debug_verbose("%s: prefix %s", __func__, buf_pfx);
        }
 #endif
@@ -1978,14 +1976,15 @@ rfapiRibPreload(struct bgp *bgp, struct rfapi_descriptor *rfd,
 
 #if DEBUG_NHL
                {
-                       char str_vn[BUFSIZ];
-                       char str_aux_prefix[BUFSIZ];
+                       char str_vn[PREFIX_STRLEN];
+                       char str_aux_prefix[PREFIX_STRLEN];
 
                        str_vn[0] = 0;
                        str_aux_prefix[0] = 0;
 
-                       prefix2str(&rk.vn, str_vn, BUFSIZ);
-                       prefix2str(&rk.aux_prefix, str_aux_prefix, BUFSIZ);
+                       prefix2str(&rk.vn, str_vn, sizeof(str_vn));
+                       prefix2str(&rk.aux_prefix, str_aux_prefix,
+                                  sizeof(str_aux_prefix));
 
                        if (!rk.aux_prefix.family) {
                        }
@@ -2075,11 +2074,11 @@ rfapiRibPreload(struct bgp *bgp, struct rfapi_descriptor *rfd,
                        route_unlock_node(trn);
 
                {
-                       char str_pfx[BUFSIZ];
-                       char str_pfx_vn[BUFSIZ];
+                       char str_pfx[PREFIX_STRLEN];
+                       char str_pfx_vn[PREFIX_STRLEN];
 
-                       prefix2str(&pfx, str_pfx, BUFSIZ);
-                       prefix2str(&rk.vn, str_pfx_vn, BUFSIZ);
+                       prefix2str(&pfx, str_pfx, sizeof(str_pfx));
+                       prefix2str(&rk.vn, str_pfx_vn, sizeof(str_pfx_vn));
                        vnc_zlog_debug_verbose(
                                "%s:   added pfx=%s nh[vn]=%s, cost=%u, lifetime=%u, allowed=%d",
                                __func__, str_pfx, str_pfx_vn, nhp->prefix.cost,
@@ -2114,9 +2113,9 @@ void rfapiRibPendingDeleteRoute(struct bgp *bgp, struct rfapi_import_table *it,
 {
        struct rfapi_descriptor *rfd;
        struct listnode *node;
-       char buf[BUFSIZ];
+       char buf[PREFIX_STRLEN];
 
-       prefix2str(&it_node->p, buf, BUFSIZ);
+       prefix2str(&it_node->p, buf, sizeof(buf));
        vnc_zlog_debug_verbose("%s: entry, it=%p, afi=%d, it_node=%p, pfx=%s",
                               __func__, it, afi, it_node, buf);
 
@@ -2290,21 +2289,21 @@ static int print_rib_sl(int (*fp)(void *, const char *, ...), struct vty *vty,
        for (rc = skiplist_next(sl, NULL, (void **)&ri, &cursor); !rc;
             rc = skiplist_next(sl, NULL, (void **)&ri, &cursor)) {
 
-               char str_vn[BUFSIZ];
-               char str_un[BUFSIZ];
+               char str_vn[PREFIX_STRLEN];
+               char str_un[PREFIX_STRLEN];
                char str_lifetime[BUFSIZ];
                char str_age[BUFSIZ];
                char *p;
-               char str_rd[BUFSIZ];
+               char str_rd[RD_ADDRSTRLEN];
 
                ++routes_displayed;
 
-               prefix2str(&ri->rk.vn, str_vn, BUFSIZ);
+               prefix2str(&ri->rk.vn, str_vn, sizeof(str_vn));
                p = index(str_vn, '/');
                if (p)
                        *p = 0;
 
-               prefix2str(&ri->un, str_un, BUFSIZ);
+               prefix2str(&ri->un, str_un, sizeof(str_un));
                p = index(str_un, '/');
                if (p)
                        *p = 0;
@@ -2325,11 +2324,10 @@ static int print_rib_sl(int (*fp)(void *, const char *, ...), struct vty *vty,
 
                str_rd[0] = 0; /* start empty */
 #if DEBUG_RIB_SL_RD
-               str_rd[0] = ' ';
-               prefix_rd2str(&ri->rk.rd, str_rd + 1, BUFSIZ - 1);
+               prefix_rd2str(&ri->rk.rd, str_rd, sizeof(str_rd));
 #endif
 
-               fp(out, " %c %-20s %-15s %-15s %-4u %-8s %-8s%s\n",
+               fp(out, " %c %-20s %-15s %-15s %-4u %-8s %-8s %s\n",
                   deleted ? 'r' : ' ', *printedprefix ? "" : str_pfx, str_vn,
                   str_un, ri->cost, str_lifetime, str_age, str_rd);
 
@@ -2352,13 +2350,13 @@ static void rfapiRibShowRibSl(void *stream, struct prefix *pfx,
        const char *vty_newline;
 
        int nhs_displayed = 0;
-       char str_pfx[BUFSIZ];
+       char str_pfx[PREFIX_STRLEN];
        int printedprefix = 0;
 
        if (rfapiStream2Vty(stream, &fp, &vty, &out, &vty_newline) == 0)
                return;
 
-       prefix2str(pfx, str_pfx, BUFSIZ);
+       prefix2str(pfx, str_pfx, sizeof(str_pfx));
 
        nhs_displayed +=
                print_rib_sl(fp, vty, out, sl, 0, str_pfx, &printedprefix);
@@ -2418,7 +2416,7 @@ void rfapiRibShowResponses(void *stream, struct prefix *pfx_match,
                             rn = route_next(rn)) {
 
                                struct skiplist *sl;
-                               char str_pfx[BUFSIZ];
+                               char str_pfx[PREFIX_STRLEN];
                                int printedprefix = 0;
 
                                if (!show_removed)
@@ -2472,7 +2470,7 @@ void rfapiRibShowResponses(void *stream, struct prefix *pfx_match,
                                                                str_un,
                                                                BUFSIZ));
                                }
-                               prefix2str(&rn->p, str_pfx, BUFSIZ);
+                               prefix2str(&rn->p, str_pfx, sizeof(str_pfx));
                                // fp(out, "  %s\n", buf);  /* prefix */
 
                                routes_displayed++;
index 6af99278bce3de085e9b664b2e4ebbb8e7b2dfd3..37ca5edc96dfde0b2532c584a98e0f18f1586983 100644 (file)
@@ -1146,7 +1146,7 @@ static int rfapiPrintRemoteRegBi(struct bgp *bgp, void *stream,
 
                char buf_age[BUFSIZ];
 
-               if (bi && bi->extra && bi->extra->vnc.import.create_time) {
+               if (bi->extra && bi->extra->vnc.import.create_time) {
                        rfapiFormatAge(bi->extra->vnc.import.create_time,
                                       buf_age, BUFSIZ);
                } else {
@@ -1163,7 +1163,7 @@ static int rfapiPrintRemoteRegBi(struct bgp *bgp, void *stream,
                 * print that on the next line
                 */
 
-               if (bi && bi->extra
+               if (bi->extra
                    && bi->extra->vnc.import.aux_prefix.family) {
                        const char *sp;
 
@@ -1527,11 +1527,9 @@ void rfapiPrintRfapiIpPrefix(void *stream, struct rfapi_ip_prefix *p)
 
 void rfapiPrintRd(struct vty *vty, struct prefix_rd *prd)
 {
-       char buf[BUFSIZ];
+       char buf[RD_ADDRSTRLEN];
 
-       buf[0] = 0;
-       prefix_rd2str(prd, buf, BUFSIZ);
-       buf[BUFSIZ - 1] = 0;
+       prefix_rd2str(prd, buf, sizeof(buf));
        vty_out(vty, "%s", buf);
 }
 
@@ -1599,7 +1597,7 @@ void rfapiPrintDescriptor(struct vty *vty, struct rfapi_descriptor *rfd)
        int rc;
        afi_t afi;
        struct rfapi_adb *adb;
-       char buf[BUFSIZ];
+       char buf[PREFIX_STRLEN];
 
        vty_out(vty, "%-10p ", rfd);
        rfapiPrintRfapiIpAddr(vty, &rfd->un_addr);
@@ -1651,8 +1649,7 @@ void rfapiPrintDescriptor(struct vty *vty, struct rfapi_descriptor *rfd)
                        if (family != adb->u.s.prefix_ip.family)
                                continue;
 
-                       prefix2str(&adb->u.s.prefix_ip, buf, BUFSIZ);
-                       buf[BUFSIZ - 1] = 0; /* guarantee NUL-terminated */
+                       prefix2str(&adb->u.s.prefix_ip, buf, sizeof(buf));
 
                        vty_out(vty, "  Adv Pfx: %s%s", buf, HVTYNL);
                        rfapiPrintAdvertisedInfo(vty, rfd, SAFI_MPLS_VPN,
@@ -1664,8 +1661,7 @@ void rfapiPrintDescriptor(struct vty *vty, struct rfapi_descriptor *rfd)
             rc == 0; rc = skiplist_next(rfd->advertised.ip0_by_ether, NULL,
                                         (void **)&adb, &cursor)) {
 
-               prefix2str(&adb->u.s.prefix_eth, buf, BUFSIZ);
-               buf[BUFSIZ - 1] = 0; /* guarantee NUL-terminated */
+               prefix2str(&adb->u.s.prefix_eth, buf, sizeof(buf));
 
                vty_out(vty, "  Adv Pfx: %s%s", buf, HVTYNL);
 
index b348c399bfc15a320fdedd111c0331297bc4b947..d4921ce40a80ec6d49c05a81313a1c664544bc83 100644 (file)
@@ -437,14 +437,11 @@ static void vnc_direct_bgp_vpn_enable_ce(struct bgp *bgp, afi_t afi)
                        continue;
 
                {
-                       char prefixstr[BUFSIZ];
-
-                       prefixstr[0] = 0;
-                       inet_ntop(rn->p.family, &rn->p.u.prefix, prefixstr,
-                                 BUFSIZ);
-                       vnc_zlog_debug_verbose("%s: checking prefix %s/%d",
-                                              __func__, prefixstr,
-                                              rn->p.prefixlen);
+                       char prefixstr[PREFIX_STRLEN];
+
+                       prefix2str(&rn->p, prefixstr, sizeof(prefixstr));
+                       vnc_zlog_debug_verbose("%s: checking prefix %s",
+                                              __func__, prefixstr);
                }
 
                for (ri = rn->info; ri; ri = ri->next) {
@@ -1856,14 +1853,13 @@ void vnc_direct_bgp_rh_vpn_enable(struct bgp *bgp, afi_t afi)
                                continue;
 
                        {
-                               char prefixstr[BUFSIZ];
+                               char prefixstr[PREFIX_STRLEN];
 
-                               prefixstr[0] = 0;
-                               inet_ntop(rn->p.family, &rn->p.u.prefix,
-                                         prefixstr, BUFSIZ);
+                               prefix2str(&rn->p, prefixstr,
+                                          sizeof(prefixstr));
                                vnc_zlog_debug_verbose(
-                                       "%s: checking prefix %s/%d", __func__,
-                                       prefixstr, rn->p.prefixlen);
+                                       "%s: checking prefix %s", __func__,
+                                       prefixstr);
                        }
 
                        /*
index 05fbd180560dccb5f0127a878fc028b6a55b0580..f7e86123b4f3422a5e4f372b9e9d30a6c2240c94 100644 (file)
@@ -205,15 +205,15 @@ static void print_rhn_list(const char *tag1, const char *tag2)
 
        /* XXX uses secret knowledge of skiplist structure */
        for (p = sl->header->forward[0]; p; p = p->forward[0]) {
-               char kbuf[BUFSIZ];
-               char hbuf[BUFSIZ];
-               char ubuf[BUFSIZ];
+               char kbuf[PREFIX_STRLEN];
+               char hbuf[PREFIX_STRLEN];
+               char ubuf[PREFIX_STRLEN];
 
                pb = p->value;
 
-               prefix2str(p->key, kbuf, BUFSIZ);
-               prefix2str(&pb->hpfx, hbuf, BUFSIZ);
-               prefix2str(&pb->upfx, ubuf, BUFSIZ);
+               prefix2str(p->key, kbuf, sizeof(kbuf));
+               prefix2str(&pb->hpfx, hbuf, sizeof(hbuf));
+               prefix2str(&pb->upfx, ubuf, sizeof(ubuf));
 
                vnc_zlog_debug_verbose(
                        "RHN Entry %d (q=%p): kpfx=%s, upfx=%s, hpfx=%s, ubi=%p",
@@ -259,14 +259,11 @@ static void vnc_rhnck(char *tag)
                 * pfx */
                assert(!vnc_prefix_cmp(&pb->hpfx, pkey));
                if (vnc_prefix_cmp(&pb->hpfx, &pfx_orig_nexthop)) {
-                       char str_onh[BUFSIZ];
-                       char str_nve_pfx[BUFSIZ];
+                       char str_onh[PREFIX_STRLEN];
+                       char str_nve_pfx[PREFIX_STRLEN];
 
-                       prefix2str(&pfx_orig_nexthop, str_onh, BUFSIZ);
-                       str_onh[BUFSIZ - 1] = 0;
-
-                       prefix2str(&pb->hpfx, str_nve_pfx, BUFSIZ);
-                       str_nve_pfx[BUFSIZ - 1] = 0;
+                       prefix2str(&pfx_orig_nexthop, str_onh, sizeof(str_onh));
+                       prefix2str(&pb->hpfx, str_nve_pfx, sizeof(str_nve_pfx));
 
                        vnc_zlog_debug_verbose(
                                "%s: %s: FATAL: resolve_nve_nexthop list item bi nexthop %s != nve pfx %s",
@@ -529,10 +526,9 @@ static void vnc_import_bgp_add_route_mode_resolve_nve_one_rd(
                return;
 
        {
-               char str_nh[BUFSIZ];
+               char str_nh[PREFIX_STRLEN];
 
-               prefix2str(ubi_nexthop, str_nh, BUFSIZ);
-               str_nh[BUFSIZ - 1] = 0;
+               prefix2str(ubi_nexthop, str_nh, sizeof(str_nh));
 
                vnc_zlog_debug_verbose("%s: ubi_nexthop=%s", __func__, str_nh);
        }
@@ -574,18 +570,16 @@ static void vnc_import_bgp_add_route_mode_resolve_nve(
 
        /*debugging */
        if (VNC_DEBUG(VERBOSE)) {
-               char str_pfx[BUFSIZ];
-               char str_nh[BUFSIZ];
+               char str_pfx[PREFIX_STRLEN];
+               char str_nh[PREFIX_STRLEN];
                struct prefix nh;
 
-               prefix2str(prefix, str_pfx, BUFSIZ);
-               str_pfx[BUFSIZ - 1] = 0;
+               prefix2str(prefix, str_pfx, sizeof(str_pfx));
 
                nh.prefixlen = 0;
                rfapiUnicastNexthop2Prefix(afi, info->attr, &nh);
                if (nh.prefixlen) {
-                       prefix2str(&nh, str_nh, BUFSIZ);
-                       str_nh[BUFSIZ - 1] = 0;
+                       prefix2str(&nh, str_nh, sizeof(str_nh));
                } else {
                        str_nh[0] = '?';
                        str_nh[1] = 0;
@@ -718,11 +712,9 @@ static void vnc_import_bgp_add_route_mode_plain(struct bgp *bgp,
        uint32_t *med = NULL;
 
        {
-               char buf[BUFSIZ];
+               char buf[PREFIX_STRLEN];
 
-               buf[0] = 0;
-               prefix2str(prefix, buf, BUFSIZ);
-               buf[BUFSIZ - 1] = 0;
+               prefix2str(prefix, buf, sizeof(buf));
                vnc_zlog_debug_verbose("%s(prefix=%s) entry", __func__, buf);
        }
 
@@ -789,11 +781,9 @@ static void vnc_import_bgp_add_route_mode_plain(struct bgp *bgp,
        }
 
        if (VNC_DEBUG(IMPORT_BGP_ADD_ROUTE)) {
-               char buf[BUFSIZ];
+               char buf[PREFIX_STRLEN];
 
-               buf[0] = 0;
-               prefix2str(vn_pfx, buf, BUFSIZ);
-               buf[BUFSIZ - 1] = 0;
+               prefix2str(vn_pfx, buf, sizeof(buf));
                vnc_zlog_debug_any("%s vn_pfx=%s", __func__, buf);
        }
 
@@ -867,11 +857,9 @@ static void vnc_import_bgp_add_route_mode_plain(struct bgp *bgp,
        }
 
        if (VNC_DEBUG(IMPORT_BGP_ADD_ROUTE)) {
-               char buf[BUFSIZ];
+               char buf[PREFIX_STRLEN];
 
-               buf[0] = 0;
-               rfapiRfapiIpAddr2Str(&vnaddr, buf, BUFSIZ);
-               buf[BUFSIZ - 1] = 0;
+               rfapiRfapiIpAddr2Str(&vnaddr, buf, sizeof(buf));
                vnc_zlog_debug_any("%s: setting vnaddr to %s", __func__, buf);
        }
 
@@ -910,11 +898,9 @@ vnc_import_bgp_add_route_mode_nvegroup(struct bgp *bgp, struct prefix *prefix,
        uint32_t local_pref;
 
        {
-               char buf[BUFSIZ];
+               char buf[PREFIX_STRLEN];
 
-               buf[0] = 0;
-               prefix2str(prefix, buf, BUFSIZ);
-               buf[BUFSIZ - 1] = 0;
+               prefix2str(prefix, buf, sizeof(buf));
                vnc_zlog_debug_verbose("%s(prefix=%s) entry", __func__, buf);
        }
 
@@ -997,11 +983,9 @@ vnc_import_bgp_add_route_mode_nvegroup(struct bgp *bgp, struct prefix *prefix,
        }
 
        if (VNC_DEBUG(IMPORT_BGP_ADD_ROUTE)) {
-               char buf[BUFSIZ];
+               char buf[PREFIX_STRLEN];
 
-               buf[0] = 0;
-               prefix2str(vn_pfx, buf, BUFSIZ);
-               buf[BUFSIZ - 1] = 0;
+               prefix2str(vn_pfx, buf, sizeof(buf));
                vnc_zlog_debug_any("%s vn_pfx=%s", __func__, buf);
        }
 
@@ -1183,7 +1167,8 @@ static void vnc_import_bgp_del_route_mode_nvegroup(struct bgp *bgp,
 
        assert(afi);
 
-       assert((rfg = bgp->rfapi_cfg->rfg_redist));
+       rfg = bgp->rfapi_cfg->rfg_redist;
+       assert(rfg);
 
        /*
         * Compute VN address
@@ -1297,11 +1282,9 @@ static void vnc_import_bgp_del_route_mode_resolve_nve_one_rd(
                return;
 
        {
-               char str_nh[BUFSIZ];
-
-               prefix2str(ubi_nexthop, str_nh, BUFSIZ);
-               str_nh[BUFSIZ - 1] = 0;
+               char str_nh[PREFIX_STRLEN];
 
+               prefix2str(ubi_nexthop, str_nh, sizeof(str_nh));
                vnc_zlog_debug_verbose("%s: ubi_nexthop=%s", __func__, str_nh);
        }
 
@@ -1450,7 +1433,7 @@ void vnc_import_bgp_add_vnc_host_route_mode_resolve_nve(
                return;
        }
 
-       if (bgp && bgp->rfapi)
+       if (bgp->rfapi)
                sl = bgp->rfapi->resolve_nve_nexthop;
 
        if (!sl) {
@@ -1477,11 +1460,11 @@ void vnc_import_bgp_add_vnc_host_route_mode_resolve_nve(
                       sizeof(struct prefix)); /* keep valgrind happy */
 
                if (VNC_DEBUG(IMPORT_BGP_ADD_ROUTE)) {
-                       char hbuf[BUFSIZ];
-                       char ubuf[BUFSIZ];
+                       char hbuf[PREFIX_STRLEN];
+                       char ubuf[PREFIX_STRLEN];
 
-                       prefix2str(&pb->hpfx, hbuf, BUFSIZ);
-                       prefix2str(&pb->upfx, ubuf, BUFSIZ);
+                       prefix2str(&pb->hpfx, hbuf, sizeof(hbuf));
+                       prefix2str(&pb->upfx, ubuf, sizeof(ubuf));
 
                        vnc_zlog_debug_any(
                                "%s: examining RHN Entry (q=%p): upfx=%s, hpfx=%s, ubi=%p",
@@ -1509,14 +1492,12 @@ void vnc_import_bgp_add_vnc_host_route_mode_resolve_nve(
                 * Sanity check
                 */
                if (vnc_prefix_cmp(&pfx_unicast_nexthop, prefix)) {
-                       char str_unh[BUFSIZ];
-                       char str_nve_pfx[BUFSIZ];
+                       char str_unh[PREFIX_STRLEN];
+                       char str_nve_pfx[PREFIX_STRLEN];
 
-                       prefix2str(&pfx_unicast_nexthop, str_unh, BUFSIZ);
-                       str_unh[BUFSIZ - 1] = 0;
-
-                       prefix2str(prefix, str_nve_pfx, BUFSIZ);
-                       str_nve_pfx[BUFSIZ - 1] = 0;
+                       prefix2str(&pfx_unicast_nexthop, str_unh,
+                                  sizeof(str_unh));
+                       prefix2str(prefix, str_nve_pfx, sizeof(str_nve_pfx));
 
                        vnc_zlog_debug_verbose(
                                "%s: FATAL: resolve_nve_nexthop list item bi nexthop %s != nve pfx %s",
@@ -1535,9 +1516,9 @@ void vnc_import_bgp_add_vnc_host_route_mode_resolve_nve(
 #if DEBUG_RHN_LIST
                /* debug */
                {
-                       char pbuf[BUFSIZ];
+                       char pbuf[PREFIX_STRLEN];
 
-                       prefix2str(prefix, pbuf, BUFSIZ);
+                       prefix2str(prefix, pbuf, sizeof(pbuf));
 
                        vnc_zlog_debug_verbose(
                                "%s: advancing past RHN Entry (q=%p): with prefix %s",
@@ -1565,10 +1546,9 @@ void vnc_import_bgp_del_vnc_host_route_mode_resolve_nve(
        int rc;
 
        {
-               char str_pfx[BUFSIZ];
+               char str_pfx[PREFIX_STRLEN];
 
-               prefix2str(prefix, str_pfx, BUFSIZ);
-               str_pfx[BUFSIZ - 1] = 0;
+               prefix2str(prefix, str_pfx, sizeof(str_pfx));
 
                vnc_zlog_debug_verbose("%s(bgp=%p, nve prefix=%s)", __func__,
                                       bgp, str_pfx);
@@ -1597,7 +1577,7 @@ void vnc_import_bgp_del_vnc_host_route_mode_resolve_nve(
                return;
        }
 
-       if (bgp && bgp->rfapi)
+       if (bgp->rfapi)
                sl = bgp->rfapi->resolve_nve_nexthop;
 
        if (!sl) {
@@ -1636,14 +1616,12 @@ void vnc_import_bgp_del_vnc_host_route_mode_resolve_nve(
                 * Sanity check
                 */
                if (vnc_prefix_cmp(&pfx_unicast_nexthop, prefix)) {
-                       char str_unh[BUFSIZ];
-                       char str_nve_pfx[BUFSIZ];
-
-                       prefix2str(&pfx_unicast_nexthop, str_unh, BUFSIZ);
-                       str_unh[BUFSIZ - 1] = 0;
+                       char str_unh[PREFIX_STRLEN];
+                       char str_nve_pfx[PREFIX_STRLEN];
 
-                       prefix2str(prefix, str_nve_pfx, BUFSIZ);
-                       str_nve_pfx[BUFSIZ - 1] = 0;
+                       prefix2str(&pfx_unicast_nexthop, str_unh,
+                                  sizeof(str_unh));
+                       prefix2str(prefix, str_nve_pfx, sizeof(str_nve_pfx));
 
                        vnc_zlog_debug_verbose(
                                "%s: FATAL: resolve_nve_nexthop list item bi nexthop %s != nve pfx %s",
@@ -2092,11 +2070,9 @@ void vnc_import_bgp_exterior_add_route_interior(
 
        /*debugging */
        {
-               char str_pfx[BUFSIZ];
-
-               prefix2str(&rn_interior->p, str_pfx, BUFSIZ);
-               str_pfx[BUFSIZ - 1] = 0;
+               char str_pfx[PREFIX_STRLEN];
 
+               prefix2str(&rn_interior->p, str_pfx, sizeof(str_pfx));
                vnc_zlog_debug_verbose("%s: interior prefix=%s, bi type=%d",
                                       __func__, str_pfx, bi_interior->type);
        }
@@ -2337,11 +2313,10 @@ void vnc_import_bgp_exterior_add_route_interior(
                                     (void **)&pfx_exterior, &cursor)) {
 
                struct prefix pfx_nexthop;
-               char buf[BUFSIZ];
+               char buf[PREFIX_STRLEN];
                afi_t afi_exterior = family2afi(pfx_exterior->family);
 
                prefix2str(pfx_exterior, buf, sizeof(buf));
-               buf[sizeof(buf) - 1] = 0;
                vnc_zlog_debug_verbose(
                        "%s: checking exterior orphan at prefix %s", __func__,
                        buf);
@@ -2480,10 +2455,9 @@ void vnc_import_bgp_exterior_del_route_interior(
 
        /*debugging */
        {
-               char str_pfx[BUFSIZ];
+               char str_pfx[PREFIX_STRLEN];
 
-               prefix2str(&rn_interior->p, str_pfx, BUFSIZ);
-               str_pfx[BUFSIZ - 1] = 0;
+               prefix2str(&rn_interior->p, str_pfx, sizeof(str_pfx));
 
                vnc_zlog_debug_verbose("%s: interior prefix=%s, bi type=%d",
                                       __func__, str_pfx, bi_interior->type);
@@ -2639,12 +2613,12 @@ void vnc_import_bgp_add_route(struct bgp *bgp, struct prefix *prefix,
 
        if (VNC_DEBUG(VERBOSE)) {
                struct prefix pfx_nexthop;
-               char buf[BUFSIZ];
-               char buf_nh[BUFSIZ];
+               char buf[PREFIX_STRLEN];
+               char buf_nh[PREFIX_STRLEN];
 
-               prefix2str(prefix, buf, BUFSIZ);
+               prefix2str(prefix, buf, sizeof(buf));
                rfapiUnicastNexthop2Prefix(afi, info->attr, &pfx_nexthop);
-               prefix2str(&pfx_nexthop, buf_nh, BUFSIZ);
+               prefix2str(&pfx_nexthop, buf_nh, sizeof(buf_nh));
 
                vnc_zlog_debug_verbose("%s: pfx %s, nh %s", __func__, buf,
                                       buf_nh);
@@ -2709,12 +2683,12 @@ void vnc_import_bgp_del_route(struct bgp *bgp, struct prefix *prefix,
 
        {
                struct prefix pfx_nexthop;
-               char buf[BUFSIZ];
-               char buf_nh[BUFSIZ];
+               char buf[PREFIX_STRLEN];
+               char buf_nh[PREFIX_STRLEN];
 
-               prefix2str(prefix, buf, BUFSIZ);
+               prefix2str(prefix, buf, sizeof(buf));
                rfapiUnicastNexthop2Prefix(afi, info->attr, &pfx_nexthop);
-               prefix2str(&pfx_nexthop, buf_nh, BUFSIZ);
+               prefix2str(&pfx_nexthop, buf_nh, sizeof(buf_nh));
 
                vnc_zlog_debug_verbose("%s: pfx %s, nh %s", __func__, buf,
                                       buf_nh);
index 07be7833b689b29d948a164add1205c27b4d38b2..92d7e6fc76be6a91729562e30a1469738e00d289 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",
@@ -393,6 +396,7 @@ static void vnc_zebra_route_msg(struct prefix *p, unsigned int nhp_count,
 
        memset(&api, 0, sizeof(api));
        api.vrf_id = VRF_DEFAULT;
+       api.nh_vrf_id = VRF_DEFAULT;
        api.type = ZEBRA_ROUTE_VNC;
        api.safi = SAFI_UNICAST;
        api.prefix = *p;
@@ -401,20 +405,16 @@ 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];
                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 16cc8901a331f37d209d9a27a4bbc886e377386d..a3b38559e55fa054d5fd14fc6aa20de3ffd32a7e 100755 (executable)
@@ -40,7 +40,7 @@ AS_IF([test "$host" != "$build"], [
   ( CPPFLAGS="$HOST_CPPFLAGS"; \
     CFLAGS="$HOST_CFLAGS"; \
     LDFLAGS="$HOST_LDFLAGS"; \
-    cd hosttools; "${abssrc}/configure" "--host=$build" "--build=$build"; )
+    cd hosttools; "${abssrc}/configure" "--host=$build" "--build=$build" "--enable-clippy-only" "--disable-nhrpd" "--disable-vtysh"; )
 
   AC_MSG_NOTICE([...])
   AC_MSG_NOTICE([... cross-compilation: finished self-configuring for build platform tools])
@@ -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,
@@ -392,7 +394,10 @@ AC_ARG_ENABLE([oldvpn_commands],
   AS_HELP_STRING([--enable-oldvpn-commands], [Keep old vpn commands]))
 AC_ARG_ENABLE(rpki,
   AS_HELP_STRING([--enable-rpki], [enable RPKI prefix validation support]))
+AC_ARG_ENABLE([clippy-only],
+  AS_HELP_STRING([--enable-clippy-only], [Only build clippy]))
 
+AS_IF([test "${enable_clippy_only}" != "yes"], [
 AC_CHECK_HEADERS(json-c/json.h)
 AC_CHECK_LIB(json-c, json_object_get, LIBS="$LIBS -ljson-c", [], [-lm])
 if test $ac_cv_lib_json_c_json_object_get = no; then
@@ -401,6 +406,7 @@ if test $ac_cv_lib_json_c_json_object_get = no; then
       AC_MSG_ERROR([lib json is needed to compile])
   fi
 fi
+])
 
 AC_ARG_ENABLE([dev_build],
     AS_HELP_STRING([--enable-dev-build], [build for development]))
@@ -875,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
@@ -891,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 ---------------------
index 6bb01dffba005e72915cc55ce49c1a60410bc74d..06e5bda3d42252f1ec615d0b076d1ca5e3f3d9e5 100644 (file)
@@ -35,6 +35,7 @@ EXTRA_DIST = README.Debian README.Maintainer \
        backports/ubuntu17.10/versionext \
        frr-doc.docs frr-doc.info frr-doc.install \
        frr-doc.lintian-overrides frr.conf \
+       frr-dbg.lintian-overrides \
        frr.dirs frr.docs frr.install \
        frr.lintian-overrides frr.logrotate \
        frr.manpages frr.pam frr.postinst frr.postrm \
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 6c80ddeaa4a67febea3acfa0883283867a22e0f6..7aaa36556f25da4647ba0f0ed1a8552f469d5a74 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) $< "$@"
diff --git a/doc/bgpd.texi b/doc/bgpd.texi
new file mode 100644 (file)
index 0000000..83483f5
--- /dev/null
@@ -0,0 +1,2142 @@
+@c -*-texinfo-*-
+@c This is part of the Frr Manual.
+@c @value{COPYRIGHT_STR}
+@c Portions: 
+@c   Copyright @copyright{} 2015 Hewlett Packard Enterprise Development LP
+@c See file frr.texi for copying conditions.
+@node BGP
+@chapter BGP
+
+@acronym{BGP} stands for a Border Gateway Protocol.  The lastest BGP version
+is 4.  It is referred as BGP-4.  BGP-4 is one of the Exterior Gateway
+Protocols and de-fact standard of Inter Domain routing protocol.
+BGP-4 is described in @cite{RFC1771, A Border Gateway Protocol
+4 (BGP-4)}.
+
+Many extensions have been added to @cite{RFC1771}.  @cite{RFC2858,
+Multiprotocol Extensions for BGP-4} provides multiprotocol support to
+BGP-4.
+
+@menu
+* Starting BGP::                
+* BGP router::                  
+* BGP MED::
+* BGP network::                 
+* BGP Peer::                    
+* BGP Peer Group::              
+* BGP Address Family::          
+* Autonomous System::           
+* BGP Communities Attribute::   
+* BGP Extended Communities Attribute::  
+* BGP Large Communities Attribute::  
+* Displaying BGP information::       
+* Capability Negotiation::      
+* Route Reflector::             
+* Route Server::                
+* BGP Regular Expressions::  
+* How to set up a 6-Bone connection::  
+* Dump BGP packets and table::  
+* BGP Configuration Examples::
+* Prefix Origin Validation Using RPKI::
+@end menu
+
+@node Starting BGP
+@section Starting BGP
+
+Default configuration file of @command{bgpd} is @file{bgpd.conf}.
+@command{bgpd} searches the current directory first then
+@value{INSTALL_PREFIX_ETC}/bgpd.conf.  All of bgpd's command must be
+configured in @file{bgpd.conf}.
+
+@command{bgpd} specific invocation options are described below.  Common
+options may also be specified (@pxref{Common Invocation Options}).
+
+@table @samp
+@item -p @var{PORT}
+@itemx --bgp_port=@var{PORT}
+Set the bgp protocol's port number.
+
+@item -r
+@itemx --retain
+When program terminates, retain BGP routes added by zebra.
+
+@item -l
+@itemx --listenon
+Specify a specific IP address for bgpd to listen on, rather than its 
+default of INADDR_ANY / IN6ADDR_ANY. This can be useful to constrain bgpd
+to an internal address, or to run multiple bgpd processes on one host.
+
+@end table
+
+@node BGP router
+@section BGP router
+
+  First of all you must configure BGP router with @command{router bgp}
+command.  To configure BGP router, you need AS number.  AS number is an
+identification of autonomous system.  BGP protocol uses the AS number
+for detecting whether the BGP connection is internal one or external one.
+
+@deffn Command {router bgp @var{asn}} {}
+Enable a BGP protocol process with the specified @var{asn}.  After
+this statement you can input any @code{BGP Commands}.  You can not
+create different BGP process under different @var{asn} without
+specifying @code{multiple-instance} (@pxref{Multiple instance}).
+@end deffn
+
+@deffn Command {no router bgp @var{asn}} {}
+Destroy a BGP protocol process with the specified @var{asn}.
+@end deffn
+
+@deffn {BGP} {bgp router-id @var{A.B.C.D}} {}
+This command specifies the router-ID.  If @command{bgpd} connects to @command{zebra} it gets
+interface and address information.  In that case default router ID value
+is selected as the largest IP Address of the interfaces.  When
+@code{router zebra} is not enabled @command{bgpd} can't get interface information
+so @code{router-id} is set to 0.0.0.0.  So please set router-id by hand.
+@end deffn
+
+@menu
+* BGP distance::                
+* BGP decision process::        
+* BGP route flap dampening::      
+@end menu
+
+@node BGP distance
+@subsection BGP distance
+
+@deffn {BGP} {distance bgp <1-255> <1-255> <1-255>} {}
+This command change distance value of BGP.  Each argument is distance
+value for external routes, internal routes and local routes.
+@end deffn
+
+@deffn {BGP} {distance <1-255> @var{A.B.C.D/M}} {}
+@deffnx {BGP} {distance <1-255> @var{A.B.C.D/M} @var{word}} {}
+This command set distance value to 
+@end deffn
+
+@node BGP decision process
+@subsection BGP decision process
+
+The decision process Frr BGP uses to select routes is as follows:
+
+@table @asis
+@item 1. Weight check
+prefer higher local weight routes to lower routes.
+  
+@item 2. Local preference check
+prefer higher local preference routes to lower.
+
+@item 3. Local route check
+Prefer local routes (statics, aggregates, redistributed) to received routes.
+
+@item 4. AS path length check
+Prefer shortest hop-count AS_PATHs. 
+
+@item 5. Origin check
+Prefer the lowest origin type route.  That is, prefer IGP origin routes to
+EGP, to Incomplete routes. 
+
+@item 6. MED check
+Where routes with a MED were received from the same AS,
+prefer the route with the lowest MED. @xref{BGP MED}.
+
+@item 7. External check
+Prefer the route received from an external, eBGP peer
+over routes received from other types of peers.
+
+@item 8. IGP cost check
+Prefer the route with the lower IGP cost.
+
+@item 9. Multi-path check
+If multi-pathing is enabled, then check whether
+the routes not yet distinguished in preference may be considered equal. If
+@ref{bgp bestpath as-path multipath-relax} is set, all such routes are
+considered equal, otherwise routes received via iBGP with identical AS_PATHs
+or routes received from eBGP neighbours in the same AS are considered equal.
+
+@item 10 Already-selected external check
+
+Where both routes were received from eBGP peers, then prefer the route which
+is already selected.  Note that this check is not applied if @ref{bgp
+bestpath compare-routerid} is configured.  This check can prevent some cases
+of oscillation.
+
+@item 11. Router-ID check
+Prefer the route with the lowest @w{router-ID}.  If the
+route has an @w{ORIGINATOR_ID} attribute, through iBGP reflection, then that
+router ID is used, otherwise the @w{router-ID} of the peer the route was
+received from is used.
+
+@item 12. Cluster-List length check
+The route with the shortest cluster-list
+length is used.  The cluster-list reflects the iBGP reflection path the
+route has taken.
+
+@item 13. Peer address
+Prefer the route received from the peer with the higher
+transport layer address, as a last-resort tie-breaker.
+
+@end table
+
+@deffn {BGP} {bgp bestpath as-path confed} {}
+This command specifies that the length of confederation path sets and
+sequences should should be taken into account during the BGP best path
+decision process.
+@end deffn
+
+@deffn {BGP} {bgp bestpath as-path multipath-relax} {}
+@anchor{bgp bestpath as-path multipath-relax}
+This command specifies that BGP decision process should consider paths
+of equal AS_PATH length candidates for multipath computation. Without
+the knob, the entire AS_PATH must match for multipath computation.
+@end deffn
+
+@deffn {BGP} {bgp bestpath compare-routerid} {}
+@anchor{bgp bestpath compare-routerid}
+
+Ensure that when comparing routes where both are equal on most metrics,
+including local-pref, AS_PATH length, IGP cost, MED, that the tie is broken
+based on router-ID.
+
+If this option is enabled, then the already-selected check, where
+already selected eBGP routes are preferred, is skipped.
+
+If a route has an @w{ORIGINATOR_ID} attribute because it has been reflected,
+that @w{ORIGINATOR_ID} will be used.  Otherwise, the router-ID of the peer the
+route was received from will be used.
+
+The advantage of this is that the route-selection (at this point) will be
+more deterministic.  The disadvantage is that a few or even one lowest-ID
+router may attract all trafic to otherwise-equal paths because of this
+check.  It may increase the possibility of MED or IGP oscillation, unless
+other measures were taken to avoid these.  The exact behaviour will be
+sensitive to the iBGP and reflection topology.
+
+@end deffn
+
+
+@node BGP route flap dampening
+@subsection BGP route flap dampening
+
+@deffn {BGP} {bgp dampening @var{<1-45>} @var{<1-20000>} @var{<1-20000>} @var{<1-255>}} {}
+This command enables BGP route-flap dampening and specifies dampening parameters.
+
+@table @asis
+@item @asis{half-life}
+Half-life time for the penalty
+@item @asis{reuse-threshold}
+Value to start reusing a route
+@item @asis{suppress-threshold}
+Value to start suppressing a route
+@item @asis{max-suppress}
+Maximum duration to suppress a stable route
+@end table
+
+The route-flap damping algorithm is compatible with @cite{RFC2439}. The use of this command
+is not recommended nowadays, see @uref{http://www.ripe.net/ripe/docs/ripe-378,,RIPE-378}.
+@end deffn
+
+@node BGP MED
+@section BGP MED
+
+The BGP MED (Multi_Exit_Discriminator) attribute has properties which can
+cause subtle convergence problems in BGP.  These properties and problems
+have proven to be hard to understand, at least historically, and may still
+not be widely understood.  The following attempts to collect together and
+present what is known about MED, to help operators and Frr users in
+designing and configuring their networks.
+
+The BGP @acronym{MED, Multi_Exit_Discriminator} attribute is intended to
+allow one AS to indicate its preferences for its ingress points to another
+AS.  The MED attribute will not be propagated on to another AS by the
+receiving AS - it is `non-transitive' in the BGP sense.
+
+E.g., if AS X and AS Y have 2 different BGP peering points, then AS X
+might set a MED of 100 on routes advertised at one and a MED of 200 at the
+other.  When AS Y selects between otherwise equal routes to or via
+AS X, AS Y should prefer to take the path via the lower MED peering of 100 with
+AS X.  Setting the MED allows an AS to influence the routing taken to it
+within another, neighbouring AS.
+
+In this use of MED it is not really meaningful to compare the MED value on
+routes where the next AS on the paths differs.  E.g., if AS Y also had a
+route for some destination via AS Z in addition to the routes from AS X, and
+AS Z had also set a MED, it wouldn't make sense for AS Y to compare AS Z's
+MED values to those of AS X.  The MED values have been set by different
+administrators, with different frames of reference.
+
+The default behaviour of BGP therefore is to not compare MED values across
+routes received from different neighbouring ASes.  In Frr this is done by
+comparing the neighbouring, left-most AS in the received AS_PATHs of the
+routes and only comparing MED if those are the same.
+
+@c TeXInfo uses the old, non-UTF-8 capable, pdftex, and so 
+@c doesn't render TeX the unicode precedes character correctly in PDF, etc.
+@c Using a TeX code on the other hand doesn't work for non-TeX outputs
+@c (plaintext, e.g.). So, use an output-conditional macro.
+
+@iftex
+@macro mprec{}
+@math{\\prec}
+@end macro
+@end iftex
+
+@ifnottex
+@macro mprec{}
+@math{≺}
+@end macro
+@end ifnottex
+
+Unfortunately, this behaviour of MED, of sometimes being compared across
+routes and sometimes not, depending on the properties of those other routes,
+means MED can cause the order of preference over all the routes to be
+undefined.  That is, given routes A, B, and C, if A is preferred to B, and B
+is preferred to C, then a well-defined order should mean the preference is
+transitive (in the sense of orders @footnote{For some set of objects to have
+an order, there @emph{must} be some binary ordering relation that is defined
+for @emph{every} combination of those objects, and that relation @emph{must}
+be transitive.  I.e.@:, if the relation operator is @mprec{}, and if 
+a @mprec{} b and b @mprec{} c then that relation must carry over
+and it @emph{must} be that a @mprec{} c for the objects to have an
+order.  The ordering relation may allow for equality, i.e. 
+a @mprec{} b and b @mprec{} a may both be true amd imply that
+a and b are equal in the order and not distinguished by it, in
+which case the set has a partial order.  Otherwise, if there is an order,
+all the objects have a distinct place in the order and the set has a total
+order.}) and that A would be preferred to C.
+
+However, when MED is involved this need not be the case.  With MED it is
+possible that C is actually preferred over A.  So A is preferred to B, B is
+preferred to C, but C is preferred to A.  This can be true even where BGP
+defines a deterministic ``most preferred'' route out of the full set of
+A,B,C.  With MED, for any given set of routes there may be a
+deterministically preferred route, but there need not be any way to arrange
+them into any order of preference.  With unmodified MED, the order of
+preference of routes literally becomes undefined.
+
+That MED can induce non-transitive preferences over routes can cause issues. 
+Firstly, it may be perceived to cause routing table churn locally at
+speakers; secondly, and more seriously, it may cause routing instability in
+iBGP topologies, where sets of speakers continually oscillate between
+different paths.
+
+The first issue arises from how speakers often implement routing decisions. 
+Though BGP defines a selection process that will deterministically select
+the same route as best at any given speaker, even with MED, that process
+requires evaluating all routes together.  For performance and ease of
+implementation reasons, many implementations evaluate route preferences in a
+pair-wise fashion instead.  Given there is no well-defined order when MED is
+involved, the best route that will be chosen becomes subject to
+implementation details, such as the order the routes are stored in.  That
+may be (locally) non-deterministic, e.g.@: it may be the order the routes
+were received in.  
+
+This indeterminism may be considered undesirable, though it need not cause
+problems.  It may mean additional routing churn is perceived, as sometimes
+more updates may be produced than at other times in reaction to some event .
+
+This first issue can be fixed with a more deterministic route selection that
+ensures routes are ordered by the neighbouring AS during selection. 
+@xref{bgp deterministic-med}.  This may reduce the number of updates as
+routes are received, and may in some cases reduce routing churn.  Though, it
+could equally deterministically produce the largest possible set of updates
+in response to the most common sequence of received updates.
+
+A deterministic order of evaluation tends to imply an additional overhead of
+sorting over any set of n routes to a destination.  The implementation of
+deterministic MED in Frr scales significantly worse than most sorting
+algorithms at present, with the number of paths to a given destination. 
+That number is often low enough to not cause any issues, but where there are
+many paths, the deterministic comparison may quickly become increasingly
+expensive in terms of CPU.
+
+Deterministic local evaluation can @emph{not} fix the second, more major,
+issue of MED however.  Which is that the non-transitive preference of routes
+MED can cause may lead to routing instability or oscillation across multiple
+speakers in iBGP topologies.  This can occur with full-mesh iBGP, but is
+particularly problematic in non-full-mesh iBGP topologies that further
+reduce the routing information known to each speaker.  This has primarily
+been documented with iBGP route-reflection topologies.  However, any
+route-hiding technologies potentially could also exacerbate oscillation with
+MED.
+
+This second issue occurs where speakers each have only a subset of routes,
+and there are cycles in the preferences between different combinations of
+routes - as the undefined order of preference of MED allows - and the routes
+are distributed in a way that causes the BGP speakers to 'chase' those
+cycles.  This can occur even if all speakers use a deterministic order of
+evaluation in route selection.
+
+E.g., speaker 4 in AS A might receive a route from speaker 2 in AS X, and
+from speaker 3 in AS Y; while speaker 5 in AS A might receive that route
+from speaker 1 in AS Y.  AS Y might set a MED of 200 at speaker 1, and 100
+at speaker 3. I.e, using ASN:ID:MED to label the speakers:
+
+@example
+
+           /---------------\
+ X:2------|--A:4-------A:5--|-Y:1:200
+ Y:3:100--|-/               |
+           \---------------/
+
+@end example
+
+Assuming all other metrics are equal (AS_PATH, ORIGIN, 0 IGP costs), then
+based on the RFC4271 decision process speaker 4 will choose X:2 over
+Y:3:100, based on the lower ID of 2.  Speaker 4 advertises X:2 to speaker 5. 
+Speaker 5 will continue to prefer Y:1:200 based on the ID, and advertise
+this to speaker 4.  Speaker 4 will now have the full set of routes, and the
+Y:1:200 it receives from 5 will beat X:2, but when speaker 4 compares
+Y:1:200 to Y:3:100 the MED check now becomes active as the ASes match, and
+now Y:3:100 is preferred.  Speaker 4 therefore now advertises Y:3:100 to 5,
+which will also agrees that Y:3:100 is preferred to Y:1:200, and so
+withdraws the latter route from 4.  Speaker 4 now has only X:2 and Y:3:100,
+and X:2 beats Y:3:100, and so speaker 4 implicitly updates its route to
+speaker 5 to X:2.  Speaker 5 sees that Y:1:200 beats X:2 based on the ID,
+and advertises Y:1:200 to speaker 4, and the cycle continues.
+
+The root cause is the lack of a clear order of preference caused by how MED
+sometimes is and sometimes is not compared, leading to this cycle in the
+preferences between the routes:
+
+@example
+
+       /---> X:2 ---beats---> Y:3:100 --\
+      |                                  |
+      |                                  |
+       \---beats--- Y:1:200 <---beats---/
+
+@end example
+
+This particular type of oscillation in full-mesh iBGP topologies can  be
+avoided by speakers preferring already selected, external routes rather than
+choosing to update to new a route based on a post-MED metric (e.g. 
+router-ID), at the cost of a non-deterministic selection process.  Frr
+implements this, as do many other implementations, so long as it is not
+overridden by setting @ref{bgp bestpath compare-routerid}, and see also
+@ref{BGP decision process}, .
+
+However, more complex and insidious cycles of oscillation are possible with
+iBGP route-reflection, which are not so easily avoided.  These have been
+documented in various places.  See, e.g., @cite{McPherson, D.  and Gill, V. 
+and Walton, D., "Border Gateway Protocol (BGP) Persistent Route Oscillation
+Condition", IETF RFC3345}, and @cite{Flavel, A.  and M.  Roughan, "Stable
+and flexible iBGP", ACM SIGCOMM 2009}, and @cite{Griffin, T.  and G.  Wilfong, 
+"On the correctness of IBGP configuration", ACM SIGCOMM 2002} for concrete 
+examples and further references.
+
+There is as of this writing @emph{no} known way to use MED for its original
+purpose; @emph{and} reduce routing information in iBGP topologies;
+@emph{and} be sure to avoid the instability problems of MED due the
+non-transitive routing preferences it can induce; in general on arbitrary
+networks.
+
+There may be iBGP topology specific ways to reduce the instability risks,
+even while using MED, e.g.@: by constraining the reflection topology and by
+tuning IGP costs between route-reflector clusters, see RFC3345 for details. 
+In the near future, the Add-Path extension to BGP may also solve MED
+oscillation while still allowing MED to be used as intended, by distributing
+"best-paths per neighbour AS".  This would be at the cost of distributing at
+least as many routes to all speakers as a full-mesh iBGP would, if not more,
+while also imposing similar CPU overheads as the "Deterministic MED" feature
+at each Add-Path reflector.
+
+More generally, the instability problems that MED can introduce on more
+complex, non-full-mesh, iBGP topologies may be avoided either by:
+
+@itemize 
+
+@item
+Setting @ref{bgp always-compare-med}, however this allows MED to be compared
+across values set by different neighbour ASes, which may not produce
+coherent desirable results, of itself.
+
+@item 
+Effectively ignoring MED by setting MED to the same value (e.g.@: 0) using
+@ref{routemap set metric} on all received routes, in combination with
+setting @ref{bgp always-compare-med} on all speakers. This is the simplest
+and most performant way to avoid MED oscillation issues, where an AS is happy
+not to allow neighbours to inject this problematic metric.
+
+@end itemize
+
+As MED is evaluated after the AS_PATH length check, another possible use for
+MED is for intra-AS steering of routes with equal AS_PATH length, as an
+extension of the last case above.  As MED is evaluated before IGP metric,
+this can allow cold-potato routing to be implemented to send traffic to
+preferred hand-offs with neighbours, rather than the closest hand-off
+according to the IGP metric.
+
+Note that even if action is taken to address the MED non-transitivity
+issues, other oscillations may still be possible.  E.g., on IGP cost if
+iBGP and IGP topologies are at cross-purposes with each other - see the
+Flavel and Roughan paper above for an example.  Hence the guideline that the
+iBGP topology should follow the IGP topology.
+
+@deffn {BGP} {bgp deterministic-med} {}
+@anchor{bgp deterministic-med}
+
+Carry out route-selection in way that produces deterministic answers
+locally, even in the face of MED and the lack of a well-defined order of
+preference it can induce on routes.  Without this option the preferred route
+with MED may be determined largely by the order that routes were received
+in.
+
+Setting this option will have a performance cost that may be noticeable when
+there are many routes for each destination.  Currently in Frr it is
+implemented in a way that scales poorly as the number of routes per
+destination increases.
+
+The default is that this option is not set.
+@end deffn
+
+Note that there are other sources of indeterminism in the route selection
+process, specifically, the preference for older and already selected routes
+from eBGP peers, @xref{BGP decision process}.
+
+@deffn {BGP} {bgp always-compare-med} {}
+@anchor{bgp always-compare-med}
+
+Always compare the MED on routes, even when they were received from
+different neighbouring ASes.  Setting this option makes the order of
+preference of routes more defined, and should eliminate MED induced
+oscillations.
+
+If using this option, it may also be desirable to use @ref{routemap set
+metric} to set MED to 0 on routes received from external neighbours.
+
+This option can be used, together with @ref{routemap set metric} to use MED
+as an intra-AS metric to steer equal-length AS_PATH routes to, e.g., desired
+exit points.
+@end deffn
+
+
+
+@node BGP network
+@section BGP network
+
+@menu
+* BGP route::                   
+* Route Aggregation::           
+* Redistribute to BGP::         
+@end menu
+
+@node BGP route
+@subsection BGP route
+
+@deffn {BGP} {network @var{A.B.C.D/M}} {}
+This command adds the announcement network.
+@example
+@group
+router bgp 1
+ address-family ipv4 unicast
+  network 10.0.0.0/8
+ exit-address-family
+@end group
+@end example
+This configuration example says that network 10.0.0.0/8 will be
+announced to all neighbors.  Some vendors' routers don't advertise
+routes if they aren't present in their IGP routing tables; @code{bgpd}
+doesn't care about IGP routes when announcing its routes.
+@end deffn
+
+@deffn {BGP} {no network @var{A.B.C.D/M}} {}
+@end deffn
+
+@node Route Aggregation
+@subsection Route Aggregation
+
+@deffn {BGP} {aggregate-address @var{A.B.C.D/M}} {}
+This command specifies an aggregate address.
+@end deffn
+
+@deffn {BGP} {aggregate-address @var{A.B.C.D/M} as-set} {}
+This command specifies an aggregate address.  Resulting routes include
+AS set.
+@end deffn
+
+@deffn {BGP} {aggregate-address @var{A.B.C.D/M} summary-only} {}
+This command specifies an aggregate address.  Aggreated routes will
+not be announce.
+@end deffn
+
+@deffn {BGP} {no aggregate-address @var{A.B.C.D/M}} {}
+@end deffn
+
+@node Redistribute to BGP
+@subsection Redistribute to BGP
+
+@deffn {BGP} {redistribute kernel} {}
+Redistribute kernel route to BGP process.
+@end deffn
+
+@deffn {BGP} {redistribute static} {}
+Redistribute static route to BGP process.
+@end deffn
+
+@deffn {BGP} {redistribute connected} {}
+Redistribute connected route to BGP process.
+@end deffn
+
+@deffn {BGP} {redistribute rip} {}
+Redistribute RIP route to BGP process.
+@end deffn
+
+@deffn {BGP} {redistribute ospf} {}
+Redistribute OSPF route to BGP process.
+@end deffn
+
+@deffn {BGP} {redistribute vpn} {}
+Redistribute VNC routes to BGP process.
+@end deffn
+
+@deffn {BGP} {update-delay @var{max-delay}} {}
+@deffnx {BGP} {update-delay @var{max-delay} @var{establish-wait}} {}
+This feature is used to enable read-only mode on BGP process restart or when
+BGP process is cleared using 'clear ip bgp *'. When applicable, read-only mode
+would begin as soon as the first peer reaches Established status and a timer
+for max-delay seconds is started.
+
+During this mode BGP doesn't run any best-path or generate any updates to its
+peers. This mode continues until:
+1. All the configured peers, except the shutdown peers, have sent explicit EOR
+(End-Of-RIB) or an implicit-EOR. The first keep-alive after BGP has reached
+Established is considered an implicit-EOR.
+   If the establish-wait optional value is given, then BGP will wait for
+   peers to reach established from the begining of the update-delay till the
+   establish-wait period is over, i.e. the minimum set of established peers for
+   which EOR is expected would be peers established during the establish-wait
+   window, not necessarily all the configured neighbors.
+2. max-delay period is over.
+On hitting any of the above two conditions, BGP resumes the decision process
+and generates updates to its peers.
+
+Default max-delay is 0, i.e. the feature is off by default.
+@end deffn
+
+@deffn {BGP} {table-map @var{route-map-name}} {}
+This feature is used to apply a route-map on route updates from BGP to Zebra.
+All the applicable match operations are allowed, such as match on prefix,
+next-hop, communities, etc. Set operations for this attach-point are limited
+to metric and next-hop only. Any operation of this feature does not affect
+BGPs internal RIB.
+
+Supported for ipv4 and ipv6 address families. It works on multi-paths as well,
+however, metric setting is based on the best-path only.
+@end deffn
+
+@node BGP Peer
+@section BGP Peer
+
+@menu
+* Defining Peer::               
+* BGP Peer commands::           
+* Peer filtering::              
+@end menu
+
+@node Defining Peer
+@subsection Defining Peer
+
+@deffn {BGP} {neighbor @var{peer} remote-as @var{asn}} {}
+Creates a new neighbor whose remote-as is @var{asn}.  @var{peer}
+can be an IPv4 address or an IPv6 address.
+@example
+@group
+router bgp 1
+ neighbor 10.0.0.1 remote-as 2
+@end group
+@end example
+In this case my router, in AS-1, is trying to peer with AS-2 at
+10.0.0.1.
+
+This command must be the first command used when configuring a neighbor.
+If the remote-as is not specified, @command{bgpd} will complain like this:
+@example
+can't find neighbor 10.0.0.1
+@end example
+@end deffn
+
+@node BGP Peer commands
+@subsection BGP Peer commands
+
+In a @code{router bgp} clause there are neighbor specific configurations
+required.
+
+@deffn {BGP} {neighbor @var{peer} shutdown} {}
+@deffnx {BGP} {no neighbor @var{peer} shutdown} {}
+Shutdown the peer.  We can delete the neighbor's configuration by
+@code{no neighbor @var{peer} remote-as @var{as-number}} but all
+configuration of the neighbor will be deleted.  When you want to
+preserve the configuration, but want to drop the BGP peer, use this
+syntax.
+@end deffn
+
+@deffn {BGP} {neighbor @var{peer} ebgp-multihop} {}
+@deffnx {BGP} {no neighbor @var{peer} ebgp-multihop} {}
+@end deffn
+
+@deffn {BGP} {neighbor @var{peer} description ...} {}
+@deffnx {BGP} {no neighbor @var{peer} description ...} {}
+Set description of the peer.
+@end deffn
+
+@deffn {BGP} {neighbor @var{peer} version @var{version}} {}
+Set up the neighbor's BGP version.  @var{version} can be @var{4},
+@var{4+} or @var{4-}.  BGP version @var{4} is the default value used for
+BGP peering.  BGP version @var{4+} means that the neighbor supports
+Multiprotocol Extensions for BGP-4.  BGP version @var{4-} is similar but
+the neighbor speaks the old Internet-Draft revision 00's Multiprotocol
+Extensions for BGP-4.  Some routing software is still using this
+version.
+@end deffn
+
+@deffn {BGP} {neighbor @var{peer} interface @var{ifname}} {}
+@deffnx {BGP} {no neighbor @var{peer} interface @var{ifname}} {}
+When you connect to a BGP peer over an IPv6 link-local address, you 
+have to specify the @var{ifname} of the interface used for the 
+connection. To specify IPv4 session addresses, see the 
+@code{neighbor @var{peer} update-source} command below.
+
+This command is deprecated and may be removed in a future release. Its
+use should be avoided.
+@end deffn
+
+@deffn {BGP} {neighbor @var{peer} next-hop-self [all]} {}
+@deffnx {BGP} {no neighbor @var{peer} next-hop-self [all]} {}
+This command specifies an announced route's nexthop as being equivalent
+to the address of the bgp router if it is learned via eBGP.
+If the optional keyword @code{all} is specified the modifiation is done
+also for routes learned via iBGP.
+@end deffn
+
+@deffn {BGP} {neighbor @var{peer} update-source @var{<ifname|address>}} {}
+@deffnx {BGP} {no neighbor @var{peer} update-source} {}
+Specify the IPv4 source address to use for the @acronym{BGP} session to this
+neighbour, may be specified as either an IPv4 address directly or
+as an interface name (in which case the @command{zebra} daemon MUST be running
+in order for @command{bgpd} to be able to retrieve interface state).
+@example
+@group
+router bgp 64555
+ neighbor foo update-source 192.168.0.1
+ neighbor bar update-source lo0
+@end group
+@end example
+@end deffn
+
+@deffn {BGP} {neighbor @var{peer} default-originate} {}
+@deffnx {BGP} {no neighbor @var{peer} default-originate} {}
+@command{bgpd}'s default is to not announce the default route (0.0.0.0/0) even it
+is in routing table.  When you want to announce default routes to the
+peer, use this command.
+@end deffn
+
+@deffn {BGP} {neighbor @var{peer} port @var{port}} {}
+@deffnx {BGP} {neighbor @var{peer} port @var{port}} {}
+@end deffn
+
+@deffn {BGP} {neighbor @var{peer} send-community} {}
+@deffnx {BGP} {neighbor @var{peer} send-community} {}
+@end deffn
+
+@deffn {BGP} {neighbor @var{peer} weight @var{weight}} {}
+@deffnx {BGP} {no neighbor @var{peer} weight @var{weight}} {}
+This command specifies a default @var{weight} value for the neighbor's
+routes.
+@end deffn
+
+@deffn {BGP} {neighbor @var{peer} maximum-prefix @var{number}} {}
+@deffnx {BGP} {no neighbor @var{peer} maximum-prefix @var{number}} {}
+@end deffn
+
+@deffn {BGP} {neighbor @var{peer} local-as @var{as-number}} {}
+@deffnx {BGP} {neighbor @var{peer} local-as @var{as-number} no-prepend} {}
+@deffnx {BGP} {neighbor @var{peer} local-as @var{as-number} no-prepend replace-as} {}
+@deffnx {BGP} {no neighbor @var{peer} local-as} {}
+Specify an alternate AS for this BGP process when interacting with the
+specified peer.  With no modifiers, the specified local-as is prepended to
+the received AS_PATH when receiving routing updates from the peer, and
+prepended to the outgoing AS_PATH (after the process local AS) when
+transmitting local routes to the peer.
+
+If the no-prepend attribute is specified, then the supplied local-as is not
+prepended to the received AS_PATH.
+
+If the replace-as attribute is specified, then only the supplied local-as is
+prepended to the AS_PATH when transmitting local-route updates to this peer.
+
+Note that replace-as can only be specified if no-prepend is.
+
+This command is only allowed for eBGP peers.
+@end deffn
+
+@deffn {BGP} {neighbor @var{peer} ttl-security hops @var{number}} {}
+@deffnx {BGP} {no neighbor @var{peer} ttl-security hops @var{number}} {}
+This command enforces Generalized TTL Security Mechanism (GTSM), as
+specified in RFC 5082. With this command, only neighbors that are the
+specified number of hops away will be allowed to become neighbors. This
+command is mututally exclusive with @command{ebgp-multihop}.
+@end deffn
+
+@node Peer filtering
+@subsection Peer filtering
+
+@deffn {BGP} {neighbor @var{peer} distribute-list @var{name} [in|out]} {}
+This command specifies a distribute-list for the peer.  @var{direct} is
+@samp{in} or @samp{out}.
+@end deffn
+
+@deffn {BGP command} {neighbor @var{peer} prefix-list @var{name} [in|out]} {}
+@end deffn
+
+@deffn {BGP command} {neighbor @var{peer} filter-list @var{name} [in|out]} {}
+@end deffn
+
+@deffn {BGP} {neighbor @var{peer} route-map @var{name} [in|out]} {}
+Apply a route-map on the neighbor.  @var{direct} must be @code{in} or
+@code{out}.
+@end deffn
+
+@deffn {BGP} {bgp route-reflector allow-outbound-policy} {}
+By default, attribute modification via route-map policy out is not reflected
+on reflected routes. This option allows the modifications to be reflected as
+well. Once enabled, it affects all reflected routes.
+@end deffn
+
+@c -----------------------------------------------------------------------
+@node BGP Peer Group
+@section BGP Peer Group
+
+@deffn {BGP} {neighbor @var{word} peer-group} {}
+This command defines a new peer group.
+@end deffn
+
+@deffn {BGP} {neighbor @var{peer} peer-group @var{word}} {}
+This command bind specific peer to peer group @var{word}.
+@end deffn
+
+@node BGP Address Family
+@section BGP Address Family
+
+Multiprotocol BGP enables BGP to carry routing information for multiple
+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 attribute
+@cite{RFC5512} is supported.
+
+@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 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
+
+@c -----------------------------------------------------------------------
+@node Autonomous System
+@section Autonomous System
+
+The @acronym{AS,Autonomous System} number is one of the essential
+element of BGP.  BGP is a distance vector routing protocol, and the
+AS-Path framework provides distance vector metric and loop detection to
+BGP. @cite{RFC1930, Guidelines for creation, selection, and
+registration of an Autonomous System (AS)} provides some background on
+the concepts of an AS.
+
+The AS number is a two octet value, ranging in value from 1 to 65535.
+The AS numbers 64512 through 65535 are defined as private AS numbers. 
+Private AS numbers must not to be advertised in the global Internet.
+
+@menu
+* Display BGP Routes by AS Path::  
+* AS Path Access List::         
+* Using AS Path in Route Map::  
+* Private AS Numbers::          
+@end menu
+
+@node Display BGP Routes by AS Path
+@subsection Display BGP Routes by AS Path
+
+To show BGP routes which has specific AS path information @code{show
+ip bgp} command can be used.  
+
+@deffn Command {show bgp @{ipv4|ipv6@} regexp @var{line}} {}
+This commands displays BGP routes that matches a regular
+expression @var{line} (@pxref{BGP Regular Expressions}).
+@end deffn
+
+@node AS Path Access List
+@subsection AS Path Access List
+
+AS path access list is user defined AS path.
+
+@deffn {Command} {ip as-path access-list @var{word} @{permit|deny@} @var{line}} {}
+This command defines a new AS path access list.
+@end deffn
+
+@deffn {Command} {no ip as-path access-list @var{word}} {}
+@deffnx {Command} {no ip as-path access-list @var{word} @{permit|deny@} @var{line}} {}
+@end deffn
+
+@node Using AS Path in Route Map
+@subsection Using AS Path in Route Map
+
+@deffn {Route Map} {match as-path @var{word}} {}
+@end deffn
+
+@deffn {Route Map} {set as-path prepend @var{as-path}} {}
+Prepend the given string of AS numbers to the AS_PATH.
+@end deffn
+
+@deffn {Route Map} {set as-path prepend last-as @var{num}} {}
+Prepend the existing last AS number (the leftmost ASN) to the AS_PATH.
+@end deffn
+
+@node Private AS Numbers
+@subsection Private AS Numbers
+
+@c -----------------------------------------------------------------------
+@node BGP Communities Attribute
+@section BGP Communities Attribute
+
+BGP communities attribute is widely used for implementing policy
+routing.  Network operators can manipulate BGP communities attribute
+based on their network policy.  BGP communities attribute is defined
+in @cite{RFC1997, BGP Communities Attribute} and
+@cite{RFC1998, An Application of the BGP Community Attribute
+in Multi-home Routing}.  It is an optional transitive attribute,
+therefore local policy can travel through different autonomous system.
+
+Communities attribute is a set of communities values.  Each
+communities value is 4 octet long.  The following format is used to
+define communities value.
+
+@table @code
+@item AS:VAL
+This format represents 4 octet communities value.  @code{AS} is high
+order 2 octet in digit format.  @code{VAL} is low order 2 octet in
+digit format.  This format is useful to define AS oriented policy
+value.  For example, @code{7675:80} can be used when AS 7675 wants to
+pass local policy value 80 to neighboring peer.
+@item internet
+@code{internet} represents well-known communities value 0.
+@item no-export
+@code{no-export} represents well-known communities value @code{NO_EXPORT}@*
+@r{(0xFFFFFF01)}.  All routes carry this value must not be advertised
+to outside a BGP confederation boundary.  If neighboring BGP peer is
+part of BGP confederation, the peer is considered as inside a BGP
+confederation boundary, so the route will be announced to the peer.
+@item no-advertise
+@code{no-advertise} represents well-known communities value
+@code{NO_ADVERTISE}@*@r{(0xFFFFFF02)}.  All routes carry this value
+must not be advertise to other BGP peers.
+@item local-AS
+@code{local-AS} represents well-known communities value
+@code{NO_EXPORT_SUBCONFED} @r{(0xFFFFFF03)}.  All routes carry this
+value must not be advertised to external BGP peers.  Even if the
+neighboring router is part of confederation, it is considered as
+external BGP peer, so the route will not be announced to the peer.
+@end table
+
+  When BGP communities attribute is received, duplicated communities
+value in the communities attribute is ignored and each communities
+values are sorted in numerical order.
+  
+@menu
+* BGP Community Lists::         
+* Numbered BGP Community Lists::  
+* BGP Community in Route Map::  
+* Display BGP Routes by Community::  
+* Using BGP Communities Attribute::  
+@end menu
+
+@node BGP Community Lists
+@subsection BGP Community Lists
+
+  BGP community list is a user defined BGP communites attribute list.
+BGP community list can be used for matching or manipulating BGP
+communities attribute in updates.
+
+There are two types of community list.  One is standard community
+list and another is expanded community list.  Standard community list
+defines communities attribute.  Expanded community list defines
+communities attribute string with regular expression.  Standard
+community list is compiled into binary format when user define it.
+Standard community list will be directly compared to BGP communities
+attribute in BGP updates.  Therefore the comparison is faster than
+expanded community list.
+
+@deffn Command {ip community-list standard @var{name} @{permit|deny@} @var{community}} {}
+This command defines a new standard community list.  @var{community}
+is communities value.  The @var{community} is compiled into community
+structure.  We can define multiple community list under same name.  In
+that case match will happen user defined order.  Once the
+community list matches to communities attribute in BGP updates it
+return permit or deny by the community list definition.  When there is
+no matched entry, deny will be returned.  When @var{community} is
+empty it matches to any routes.
+@end deffn
+
+@deffn Command {ip community-list expanded @var{name} @{permit|deny@} @var{line}} {}
+This command defines a new expanded community list.  @var{line} is a
+string expression of communities attribute.  @var{line} can be a
+regular expression (@pxref{BGP Regular Expressions}) to match
+the communities attribute in BGP updates.
+@end deffn
+
+@deffn Command {no ip community-list @var{name}} {}
+@deffnx Command {no ip community-list standard @var{name}} {}
+@deffnx Command {no ip community-list expanded @var{name}} {}
+These commands delete community lists specified by @var{name}.  All of
+community lists shares a single name space.  So community lists can be
+removed simpley specifying community lists name.
+@end deffn
+
+@deffn {Command} {show ip community-list} {}
+@deffnx {Command} {show ip community-list @var{name}} {}
+This command displays current community list information.  When
+@var{name} is specified the specified community list's information is
+shown.
+
+@example
+# show ip community-list 
+Named Community standard list CLIST
+    permit 7675:80 7675:100 no-export
+    deny internet
+Named Community expanded list EXPAND
+    permit :
+
+# show ip community-list CLIST
+Named Community standard list CLIST
+    permit 7675:80 7675:100 no-export
+    deny internet
+@end example
+@end deffn
+
+@node Numbered BGP Community Lists
+@subsection Numbered BGP Community Lists
+
+When number is used for BGP community list name, the number has
+special meanings.  Community list number in the range from 1 and 99 is
+standard community list.  Community list number in the range from 100
+to 199 is expanded community list.  These community lists are called
+as numbered community lists.  On the other hand normal community lists
+is called as named community lists.
+
+@deffn Command {ip community-list <1-99> @{permit|deny@} @var{community}} {}
+This command defines a new community list.  <1-99> is standard
+community list number.  Community list name within this range defines
+standard community list.  When @var{community} is empty it matches to
+any routes.
+@end deffn
+
+@deffn Command {ip community-list <100-199> @{permit|deny@} @var{community}} {}
+This command defines a new community list.  <100-199> is expanded
+community list number.  Community list name within this range defines
+expanded community list.
+@end deffn
+
+@deffn Command {ip community-list @var{name} @{permit|deny@} @var{community}} {}
+When community list type is not specifed, the community list type is
+automatically detected.  If @var{community} can be compiled into
+communities attribute, the community list is defined as a standard
+community list.  Otherwise it is defined as an expanded community
+list.  This feature is left for backward compability.  Use of this
+feature is not recommended.
+@end deffn
+
+@node BGP Community in Route Map
+@subsection BGP Community in Route Map
+
+In Route Map (@pxref{Route Map}), we can match or set BGP
+communities attribute.  Using this feature network operator can
+implement their network policy based on BGP communities attribute.
+
+Following commands can be used in Route Map.
+
+@deffn {Route Map} {match community @var{word}} {}
+@deffnx {Route Map} {match community @var{word} exact-match} {}
+This command perform match to BGP updates using community list
+@var{word}.  When the one of BGP communities value match to the one of
+communities value in community list, it is match.  When
+@code{exact-match} keyword is spcified, match happen only when BGP
+updates have completely same communities value specified in the
+community list.
+@end deffn
+
+@deffn {Route Map} {set community none} {}
+@deffnx {Route Map} {set community @var{community}} {}
+@deffnx {Route Map} {set community @var{community} additive} {}
+This command manipulate communities value in BGP updates.  When
+@code{none} is specified as communities value, it removes entire
+communities attribute from BGP updates.  When @var{community} is not
+@code{none}, specified communities value is set to BGP updates.  If
+BGP updates already has BGP communities value, the existing BGP
+communities value is replaced with specified @var{community} value.
+When @code{additive} keyword is specified, @var{community} is appended
+to the existing communities value.
+@end deffn
+
+@deffn {Route Map} {set comm-list @var{word} delete} {}
+This command remove communities value from BGP communities attribute.
+The @var{word} is community list name.  When BGP route's communities
+value matches to the community list @var{word}, the communities value
+is removed.  When all of communities value is removed eventually, the
+BGP update's communities attribute is completely removed.
+@end deffn
+
+@node Display BGP Routes by Community
+@subsection Display BGP Routes by Community
+
+To show BGP routes which has specific BGP communities attribute,
+@code{show bgp @{ipv4|ipv6@}} command can be used. The
+@var{community} and @var{community-list} subcommand can be used.
+
+@deffn Command {show bgp @{ipv4|ipv6@} community} {}
+@deffnx Command {show bgp @{ipv4|ipv6@} community @var{community}} {}
+@deffnx Command {show bgp @{ipv4|ipv6@} community @var{community} exact-match} {}
+@code{show bgp @{ipv4|ipv6@} community} displays BGP routes which has communities
+attribute. Where the address family can be IPv4 or IPv6 among others. When
+@var{community} is specified, BGP routes that matches @var{community} value is
+displayed. For this command, @code{internet} keyword can't be used for
+@var{community} value. When @code{exact-match} is specified, it display only
+routes that have an exact match.
+@end deffn
+
+@deffn Command {show bgp @{ipv4|ipv6@} community-list @var{word}} {}
+@deffnx Command {show bgp @{ipv4|ipv6@} community-list @var{word} exact-match} {}
+This commands display BGP routes for the address family specified that matches
+community list @var{word}. When @code{exact-match} is specified, display only
+routes that have an exact match.
+@end deffn
+
+@node Using BGP Communities Attribute
+@subsection Using BGP Communities Attribute
+
+Following configuration is the most typical usage of BGP communities
+attribute.  AS 7675 provides upstream Internet connection to AS 100.
+When following configuration exists in AS 7675, AS 100 networks
+operator can set local preference in AS 7675 network by setting BGP
+communities attribute to the updates.
+
+@example
+router bgp 7675
+ neighbor 192.168.0.1 remote-as 100
+ address-family ipv4 unicast
+  neighbor 192.168.0.1 route-map RMAP in
+ exit-address-family
+!
+ip community-list 70 permit 7675:70
+ip community-list 70 deny
+ip community-list 80 permit 7675:80
+ip community-list 80 deny
+ip community-list 90 permit 7675:90
+ip community-list 90 deny
+!
+route-map RMAP permit 10
+ match community 70
+ set local-preference 70
+!
+route-map RMAP permit 20
+ match community 80
+ set local-preference 80
+!
+route-map RMAP permit 30
+ match community 90
+ set local-preference 90
+@end example
+
+Following configuration announce 10.0.0.0/8 from AS 100 to AS 7675.
+The route has communities value 7675:80 so when above configuration
+exists in AS 7675, announced route's local preference will be set to
+value 80.
+
+@example
+router bgp 100
+ network 10.0.0.0/8
+ neighbor 192.168.0.2 remote-as 7675
+ address-family ipv4 unicast
+  neighbor 192.168.0.2 route-map RMAP out
+ exit-address-family
+!
+ip prefix-list PLIST permit 10.0.0.0/8
+!
+route-map RMAP permit 10
+ match ip address prefix-list PLIST
+ set community 7675:80
+@end example
+
+Following configuration is an example of BGP route filtering using
+communities attribute.  This configuration only permit BGP routes
+which has BGP communities value 0:80 or 0:90.  Network operator can
+put special internal communities value at BGP border router, then
+limit the BGP routes announcement into the internal network.
+
+@example
+router bgp 7675
+ neighbor 192.168.0.1 remote-as 100
+ address-family ipv4 unicast
+  neighbor 192.168.0.1 route-map RMAP in
+ exit-address-family
+!
+ip community-list 1 permit 0:80 0:90
+!
+route-map RMAP permit in
+ match community 1
+@end example
+
+Following exmaple filter BGP routes which has communities value 1:1.
+When there is no match community-list returns deny.  To avoid
+filtering all of routes, we need to define permit any at last.
+
+@example
+router bgp 7675
+ neighbor 192.168.0.1 remote-as 100
+ address-family ipv4 unicast
+  neighbor 192.168.0.1 route-map RMAP in
+ exit-address-family
+!
+ip community-list standard FILTER deny 1:1
+ip community-list standard FILTER permit
+!
+route-map RMAP permit 10
+ match community FILTER
+@end example
+
+Communities value keyword @code{internet} has special meanings in
+standard community lists.  In below example @code{internet} act as
+match any.  It matches all of BGP routes even if the route does not
+have communities attribute at all.  So community list @code{INTERNET}
+is same as above example's @code{FILTER}.
+
+@example
+ip community-list standard INTERNET deny 1:1
+ip community-list standard INTERNET permit internet
+@end example
+
+Following configuration is an example of communities value deletion.
+With this configuration communities value 100:1 and 100:2 is removed
+from BGP updates.  For communities value deletion, only @code{permit}
+community-list is used.  @code{deny} community-list is ignored.
+
+@example
+router bgp 7675
+ neighbor 192.168.0.1 remote-as 100
+ address-family ipv4 unicast
+  neighbor 192.168.0.1 route-map RMAP in
+ exit-address-family
+!
+ip community-list standard DEL permit 100:1 100:2
+!
+route-map RMAP permit 10
+ set comm-list DEL delete
+@end example
+
+@c -----------------------------------------------------------------------
+@node BGP Extended Communities Attribute
+@section BGP Extended Communities Attribute
+
+BGP extended communities attribute is introduced with MPLS VPN/BGP
+technology.  MPLS VPN/BGP expands capability of network infrastructure
+to provide VPN functionality.  At the same time it requires a new
+framework for policy routing.  With BGP Extended Communities Attribute
+we can use Route Target or Site of Origin for implementing network
+policy for MPLS VPN/BGP.
+
+BGP Extended Communities Attribute is similar to BGP Communities
+Attribute.  It is an optional transitive attribute.  BGP Extended
+Communities Attribute can carry multiple Extended Community value.
+Each Extended Community value is eight octet length.
+
+BGP Extended Communities Attribute provides an extended range
+compared with BGP Communities Attribute.  Adding to that there is a
+type field in each value to provides community space structure.
+
+There are two format to define Extended Community value.  One is AS
+based format the other is IP address based format.
+
+@table @code
+@item AS:VAL
+This is a format to define AS based Extended Community value.
+@code{AS} part is 2 octets Global Administrator subfield in Extended
+Community value.  @code{VAL} part is 4 octets Local Administrator
+subfield.  @code{7675:100} represents AS 7675 policy value 100.
+@item IP-Address:VAL
+This is a format to define IP address based Extended Community value.
+@code{IP-Address} part is 4 octets Global Administrator subfield.
+@code{VAL} part is 2 octets Local Administrator subfield.
+@code{10.0.0.1:100} represents 
+@end table
+
+@menu
+* BGP Extended Community Lists::  
+* BGP Extended Communities in Route Map::  
+@end menu
+
+@node BGP Extended Community Lists
+@subsection BGP Extended Community Lists
+
+Expanded Community Lists is a user defined BGP Expanded Community
+Lists.
+
+@deffn Command {ip extcommunity-list standard @var{name} @{permit|deny@} @var{extcommunity}} {}
+This command defines a new standard extcommunity-list.
+@var{extcommunity} is extended communities value.  The
+@var{extcommunity} is compiled into extended community structure.  We
+can define multiple extcommunity-list under same name.  In that case
+match will happen user defined order.  Once the extcommunity-list
+matches to extended communities attribute in BGP updates it return
+permit or deny based upon the extcommunity-list definition.  When
+there is no matched entry, deny will be returned.  When
+@var{extcommunity} is empty it matches to any routes.
+@end deffn
+
+@deffn Command {ip extcommunity-list expanded @var{name} @{permit|deny@} @var{line}} {}
+This command defines a new expanded extcommunity-list.  @var{line} is
+a string expression of extended communities attribute.  @var{line} can
+be a regular expression (@pxref{BGP Regular Expressions}) to match an
+extended communities attribute in BGP updates.
+@end deffn
+
+@deffn Command {no ip extcommunity-list @var{name}} {}
+@deffnx Command {no ip extcommunity-list standard @var{name}} {}
+@deffnx Command {no ip extcommunity-list expanded @var{name}} {}
+These commands delete extended community lists specified by
+@var{name}.  All of extended community lists shares a single name
+space.  So extended community lists can be removed simpley specifying
+the name.
+@end deffn
+
+@deffn {Command} {show ip extcommunity-list} {}
+@deffnx {Command} {show ip extcommunity-list @var{name}} {}
+This command displays current extcommunity-list information.  When
+@var{name} is specified the community list's information is shown.
+
+@example
+# show ip extcommunity-list 
+@end example
+@end deffn
+
+@node BGP Extended Communities in Route Map
+@subsection BGP Extended Communities in Route Map
+
+@deffn {Route Map} {match extcommunity @var{word}} {}
+@end deffn
+
+@deffn {Route Map} {set extcommunity rt @var{extcommunity}} {}
+This command set Route Target value.
+@end deffn
+
+@deffn {Route Map} {set extcommunity soo @var{extcommunity}} {}
+This command set Site of Origin value.
+@end deffn
+
+@c -----------------------------------------------------------------------
+@node BGP Large Communities Attribute
+@section BGP Large Communities Attribute
+
+The BGP Large Communities attribute was introduced in Feb 2017 with
+@cite{RFC8092, BGP Large Communities Attribute}.
+
+The BGP Large Communities Attribute is similar to the BGP Communities
+Attribute except that it has 3 components instead of two and each of
+which are 4 octets in length. Large Communities bring additional
+functionality and convenience over traditional communities, specifically
+the fact that the @code{GLOBAL} part below is now 4 octets wide allowing
+AS4 operators seamless use.
+
+@table @code
+@item GLOBAL:LOCAL1:LOCAL2
+This is the format to define Large Community values. Referencing
+@cite{RFC8195, Use of BGP Large Communities} the values are commonly
+referred to as follows.
+The @code{GLOBAL} part is a 4 octet Global Administrator field, common
+use of this field is the operators AS number.
+The @code{LOCAL1} part is a 4 octet Local Data Part 1 subfield referred
+to as a function.
+The @code{LOCAL2} part is a 4 octet Local Data Part 2 field and referred
+to as the parameter subfield. @code{65551:1:10} represents AS 65551
+function 1 and parameter 10.
+The referenced RFC above gives some guidelines on recommended usage.
+@end table
+
+@menu
+* BGP Large Community Lists::  
+* BGP Large Communities in Route Map::  
+@end menu
+
+@node BGP Large Community Lists
+@subsection BGP Large Community Lists
+
+Two types of large community lists are supported, namely @code{standard} and
+@code{expanded}.
+
+@deffn Command {ip large-community-list standard @var{name} @{permit|deny@} @var{large-community}} {}
+This command defines a new standard large-community-list.
+@var{large-community} is the Large Community value. We
+can add multiple large communities under same name. In that case
+the match will happen in the user defined order. Once the large-community-list
+matches the Large Communities attribute in BGP updates it will return
+permit or deny based upon the large-community-list definition.  When
+there is no matched entry, a deny will be returned.  When @var{large-community}
+is empty it matches any routes.
+@end deffn
+
+@deffn Command {ip large-community-list expanded @var{name} @{permit|deny@} @var{line}} {}
+This command defines a new expanded large-community-list. Where @var{line} is
+a string matching expression, it will be compared to the entire Large Communities
+attribute as a string, with each large-community in order from lowest to highest.
+@var{line} can also be a regular expression which matches this Large
+Community attribute.
+@end deffn
+
+@deffn Command {no ip large-community-list @var{name}} {}
+@deffnx Command {no ip large-community-list standard @var{name}} {}
+@deffnx Command {no ip large-community-list expanded @var{name}} {}
+These commands delete Large Community lists specified by
+@var{name}. All Large Community lists share a single namespace.
+This means Large Community lists can be removed by simply specifying the name.
+@end deffn
+
+@deffn {Command} {show ip large-community-list} {}
+@deffnx {Command} {show ip large-community-list @var{name}} {}
+This command display current large-community-list information.  When
+@var{name} is specified the community list information is shown.
+@end deffn
+
+@deffn {Command} {show ip bgp large-community-info} {}
+This command displays the current large communities in use.
+@end deffn
+
+@node BGP Large Communities in Route Map
+@subsection BGP Large Communities in Route Map
+
+@deffn {Route Map} {match large-community @var{line}} {}
+Where @var{line} can be a simple string to match, or a regular expression.
+It is very important to note that this match occurs on the entire
+large-community string as a whole, where each large-community is ordered
+from lowest to highest.
+@end deffn
+
+@deffn {Route Map} {set large-community @var{large-community}} {}
+@deffnx {Route Map} {set large-community @var{large-community} @var{large-community}} {}
+@deffnx {Route Map} {set large-community @var{large-community} additive} {}
+These commands are used for setting large-community values. The first
+command will overwrite any large-communities currently present.
+The second specifies two large-communities, which overwrites the current
+large-community list. The third will add a large-community value without
+overwriting other values. Multiple large-community values can be specified.
+@end deffn
+
+@c -----------------------------------------------------------------------
+
+@node Displaying BGP information
+@section Displaying BGP information
+
+@menu
+* Showing BGP information::                 
+* Other BGP commands::            
+@end menu
+
+@node Showing BGP information
+@subsection Showing BGP information
+
+@deffn {Command} {show ip bgp} {}
+@deffnx {Command} {show ip bgp @var{A.B.C.D}} {}
+@deffnx {Command} {show ip bgp @var{X:X::X:X}} {}
+This command displays BGP routes.  When no route is specified it
+display all of IPv4 BGP routes.
+@end deffn
+
+@example
+BGP table version is 0, local router ID is 10.1.1.1
+Status codes: s suppressed, d damped, h history, * valid, > best, i - internal
+Origin codes: i - IGP, e - EGP, ? - incomplete
+
+   Network          Next Hop            Metric LocPrf Weight Path
+*> 1.1.1.1/32       0.0.0.0                  0         32768 i
+
+Total number of prefixes 1
+@end example
+
+@deffn {Command} {show ip bgp regexp @var{line}} {}
+This command displays BGP routes using AS path regular expression
+(@pxref{BGP Regular Expressions}).
+@end deffn
+
+@deffn Command {show ip bgp community @var{community}} {}
+@deffnx Command {show ip bgp community @var{community} exact-match} {}
+This command displays BGP routes using @var{community} (@pxref{Display
+BGP Routes by Community}).
+@end deffn
+
+@deffn Command {show ip bgp community-list @var{word}} {}
+@deffnx Command {show ip bgp community-list @var{word} exact-match} {}
+This command displays BGP routes using community list (@pxref{Display
+BGP Routes by Community}).
+@end deffn
+
+@deffn {Command} {show bgp @{ipv4|ipv6@} summary} {}
+Show a bgp peer summary for the specified address family.
+@end deffn
+
+@deffn {Command} {show bgp @{ipv4|ipv6@} neighbor [@var{peer}]} {}
+This command shows information on a specific BGP @var{peer}.
+@end deffn
+
+@deffn {Command} {show bgp @{ipv4|ipv6@} dampening dampened-paths} {}
+Display paths suppressed due to dampening.
+@end deffn
+
+@deffn {Command} {show bgp @{ipv4|ipv6@} dampening flap-statistics} {}
+Display flap statistics of routes.
+@end deffn
+
+@node Other BGP commands
+@subsection Other BGP commands
+
+@deffn {Command} {clear bgp @{ipv4|ipv6@} *} {}
+Clear all address family peers.
+@end deffn
+
+@deffn {Command} {clear bgp @{ipv4|ipv6@} @var{peer}} {}
+Clear peers which have addresses of X.X.X.X
+@end deffn
+
+@deffn {Command} {clear bgp @{ipv4|ipv6@} @var{peer} soft in} {}
+Clear peer using soft reconfiguration.
+@end deffn
+
+@deffn {Command} {show debug} {}
+@end deffn
+
+@deffn {Command} {debug event} {}
+@end deffn
+
+@deffn {Command} {debug update} {}
+@end deffn
+
+@deffn {Command} {debug keepalive} {}
+@end deffn
+
+@deffn {Command} {no debug event} {}
+@end deffn
+
+@deffn {Command} {no debug update} {}
+@end deffn
+
+@deffn {Command} {no debug keepalive} {}
+@end deffn
+
+@node Capability Negotiation
+@section Capability Negotiation
+
+When adding IPv6 routing information exchange feature to BGP.  There
+were some proposals.  @acronym{IETF,Internet Engineering Task Force}
+@acronym{IDR, Inter Domain Routing} @acronym{WG, Working group} adopted
+a proposal called Multiprotocol Extension for BGP.  The specification
+is described in @cite{RFC2283}.  The protocol does not define new protocols. 
+It defines new attributes to existing BGP.  When it is used exchanging
+IPv6 routing information it is called BGP-4+.  When it is used for
+exchanging multicast routing information it is called MBGP.
+
+@command{bgpd} supports Multiprotocol Extension for BGP.  So if remote
+peer supports the protocol, @command{bgpd} can exchange IPv6 and/or
+multicast routing information.
+
+Traditional BGP did not have the feature to detect remote peer's
+capabilities, e.g. whether it can handle prefix types other than IPv4
+unicast routes.  This was a big problem using Multiprotocol Extension
+for BGP to operational network.  @cite{RFC2842, Capabilities
+Advertisement with BGP-4} adopted a feature called Capability
+Negotiation. @command{bgpd} use this Capability Negotiation to detect
+the remote peer's capabilities.  If the peer is only configured as IPv4
+unicast neighbor, @command{bgpd} does not send these Capability
+Negotiation packets (at least not unless other optional BGP features
+require capability negotation).
+
+By default, Frr will bring up peering with minimal common capability
+for the both sides.  For example, local router has unicast and
+multicast capabilitie and remote router has unicast capability.  In
+this case, the local router will establish the connection with unicast
+only capability. When there are no common capabilities, Frr sends
+Unsupported Capability error and then resets the connection.
+
+If you want to completely match capabilities with remote peer.  Please
+use @command{strict-capability-match} command.
+  
+@deffn {BGP} {neighbor @var{peer} strict-capability-match} {}
+@deffnx {BGP} {no neighbor @var{peer} strict-capability-match} {}
+Strictly compares remote capabilities and local capabilities.  If capabilities
+are different, send Unsupported Capability error then reset connection.
+@end deffn
+
+You may want to disable sending Capability Negotiation OPEN message
+optional parameter to the peer when remote peer does not implement
+Capability Negotiation.  Please use @command{dont-capability-negotiate}
+command to disable the feature.
+
+@deffn {BGP} {neighbor @var{peer} dont-capability-negotiate} {}
+@deffnx {BGP} {no neighbor @var{peer} dont-capability-negotiate} {}
+Suppress sending Capability Negotiation as OPEN message optional
+parameter to the peer.  This command only affects the peer is configured
+other than IPv4 unicast configuration.
+@end deffn
+
+When remote peer does not have capability negotiation feature, remote
+peer will not send any capabilities at all.  In that case, bgp
+configures the peer with configured capabilities.
+
+You may prefer locally configured capabilities more than the negotiated
+capabilities even though remote peer sends capabilities.  If the peer
+is configured by @command{override-capability}, @command{bgpd} ignores
+received capabilities then override negotiated capabilities with
+configured values.
+
+@deffn {BGP} {neighbor @var{peer} override-capability} {}
+@deffnx {BGP} {no neighbor @var{peer} override-capability} {}
+Override the result of Capability Negotiation with local configuration.
+Ignore remote peer's capability value.
+@end deffn
+
+@node Route Reflector
+@section Route Reflector
+
+@deffn {BGP} {bgp cluster-id @var{a.b.c.d}} {}
+@end deffn
+
+@deffn {BGP} {neighbor @var{peer} route-reflector-client} {}
+@deffnx {BGP} {no neighbor @var{peer} route-reflector-client} {}
+@end deffn
+
+@node Route Server
+@section Route Server
+
+At an Internet Exchange point, many ISPs are connected to each other by
+external BGP peering.  Normally these external BGP connection are done by
+@samp{full mesh} method.  As with internal BGP full mesh formation,
+this method has a scaling problem.
+
+This scaling problem is well known.  Route Server is a method to resolve
+the problem.  Each ISP's BGP router only peers to Route Server.  Route
+Server serves as BGP information exchange to other BGP routers.  By
+applying this method, numbers of BGP connections is reduced from
+O(n*(n-1)/2) to O(n).
+
+Unlike normal BGP router, Route Server must have several routing tables
+for managing different routing policies for each BGP speaker.  We call the
+routing tables as different @code{view}s.  @command{bgpd} can work as
+normal BGP router or Route Server or both at the same time.
+
+@menu
+* Multiple instance::           
+* BGP instance and view::       
+* Routing policy::              
+* Viewing the view::            
+@end menu
+
+@node Multiple instance
+@subsection Multiple instance
+
+To enable multiple view function of @code{bgpd}, you must turn on
+multiple instance feature beforehand.
+
+@deffn {Command} {bgp multiple-instance} {}
+Enable BGP multiple instance feature.  After this feature is enabled,
+you can make multiple BGP instances or multiple BGP views.
+@end deffn
+
+@deffn {Command} {no bgp multiple-instance} {}
+Disable BGP multiple instance feature.  You can not disable this feature
+when BGP multiple instances or views exist.
+@end deffn
+
+When you want to make configuration more Cisco like one, 
+
+@deffn {Command} {bgp config-type cisco} {}
+Cisco compatible BGP configuration output.
+@end deffn
+
+When bgp config-type cisco is specified, 
+
+``no synchronization'' is displayed.
+``no auto-summary'' is displayed.
+
+``network'' and ``aggregate-address'' argument is displayed as
+``A.B.C.D M.M.M.M''
+
+Frr: network 10.0.0.0/8
+Cisco: network 10.0.0.0
+
+Frr: aggregate-address 192.168.0.0/24
+Cisco: aggregate-address 192.168.0.0 255.255.255.0
+
+Community attribute handling is also different.  If there is no
+configuration is specified community attribute and extended community
+attribute are sent to neighbor.  When user manually disable the
+feature community attribute is not sent to the neighbor.  In case of
+@command{bgp config-type cisco} is specified, community attribute is not
+sent to the neighbor by default.  To send community attribute user has
+to specify @command{neighbor A.B.C.D send-community} command.
+
+@example
+!
+router bgp 1
+ neighbor 10.0.0.1 remote-as 1
+ address-family ipv4 unicast
+  no neighbor 10.0.0.1 send-community
+ exit-address-family
+!
+router bgp 1
+ neighbor 10.0.0.1 remote-as 1
+ address-family ipv4 unicast
+  neighbor 10.0.0.1 send-community
+ exit-address-family
+!
+@end example
+
+@deffn {Command} {bgp config-type zebra} {}
+Frr style BGP configuration.  This is default.
+@end deffn
+
+@node BGP instance and view
+@subsection BGP instance and view
+
+BGP instance is a normal BGP process.  The result of route selection
+goes to the kernel routing table.  You can setup different AS at the
+same time when BGP multiple instance feature is enabled.
+
+@deffn {Command} {router bgp @var{as-number}} {}
+Make a new BGP instance.  You can use arbitrary word for the @var{name}.
+@end deffn
+
+@example
+@group
+bgp multiple-instance
+!
+router bgp 1
+ neighbor 10.0.0.1 remote-as 2
+ neighbor 10.0.0.2 remote-as 3
+!
+router bgp 2
+ neighbor 10.0.0.3 remote-as 4
+ neighbor 10.0.0.4 remote-as 5
+@end group
+@end example
+
+BGP view is almost same as normal BGP process. The result of
+route selection does not go to the kernel routing table.  BGP view is
+only for exchanging BGP routing information.
+
+@deffn {Command} {router bgp @var{as-number} view @var{name}} {}
+Make a new BGP view.  You can use arbitrary word for the @var{name}.  This
+view's route selection result does not go to the kernel routing table.
+@end deffn
+
+With this command, you can setup Route Server like below.
+
+@example
+@group
+bgp multiple-instance
+!
+router bgp 1 view 1
+ neighbor 10.0.0.1 remote-as 2
+ neighbor 10.0.0.2 remote-as 3
+!
+router bgp 2 view 2
+ neighbor 10.0.0.3 remote-as 4
+ neighbor 10.0.0.4 remote-as 5
+@end group
+@end example
+
+@node Routing policy
+@subsection Routing policy
+
+You can set different routing policy for a peer.  For example, you can
+set different filter for a peer.
+
+@example
+@group
+bgp multiple-instance
+!
+router bgp 1 view 1
+ neighbor 10.0.0.1 remote-as 2
+ address-family ipv4 unicast
+  neighbor 10.0.0.1 distribute-list 1 in
+ exit-address-family
+!
+router bgp 1 view 2
+ neighbor 10.0.0.1 remote-as 2
+ address-family ipv4 unicast
+  neighbor 10.0.0.1 distribute-list 2 in
+ exit-address-family
+@end group
+@end example
+
+This means BGP update from a peer 10.0.0.1 goes to both BGP view 1 and view
+2.  When the update is inserted into view 1, distribute-list 1 is
+applied.  On the other hand, when the update is inserted into view 2,
+distribute-list 2 is applied.
+
+@node Viewing the view
+@subsection Viewing the view
+
+To display routing table of BGP view, you must specify view name.
+
+@deffn {Command} {show ip bgp view @var{name}} {}
+Display routing table of BGP view @var{name}.
+@end deffn
+
+@node BGP Regular Expressions
+@section BGP Regular Expressions
+
+BGP regular expressions are based on @code{POSIX 1003.2} regular
+expressions. The following description is just a quick subset of the
+@code{POSIX} regular expressions. Adding to that, the special character
+'_' is added.
+
+@table @code
+@item .
+Matches any single character.
+@item *
+Matches 0 or more occurrences of pattern.
+@item +
+Matches 1 or more occurrences of pattern.
+@item ?
+Match 0 or 1 occurrences of pattern.
+@item ^
+Matches the beginning of the line.
+@item $
+Matches the end of the line.
+@item _
+Character @code{_} has special meanings in BGP regular expressions.
+It matches to space and comma , and AS set delimiter @{ and @} and AS
+confederation delimiter @code{(} and @code{)}.  And it also matches to
+the beginning of the line and the end of the line.  So @code{_} can be
+used for AS value boundaries match. This character technically evaluates
+to @code{(^|[,@{@}() ]|$)}.
+@end table
+
+@node How to set up a 6-Bone connection
+@section How to set up a 6-Bone connection
+
+
+@example
+@group
+zebra configuration 
+=================== 
+!  
+! Actually there is no need to configure zebra 
+!
+
+bgpd configuration
+==================
+!
+! This means that routes go through zebra and into the kernel.
+!
+router zebra
+!
+! MP-BGP configuration
+!
+router bgp 7675
+ bgp router-id 10.0.0.1
+ neighbor 3ffe:1cfa:0:2:2a0:c9ff:fe9e:f56 remote-as @var{as-number}
+!
+ address-family ipv6
+ network 3ffe:506::/32
+ neighbor 3ffe:1cfa:0:2:2a0:c9ff:fe9e:f56 activate
+ neighbor 3ffe:1cfa:0:2:2a0:c9ff:fe9e:f56 route-map set-nexthop out
+ neighbor 3ffe:1cfa:0:2:2c0:4fff:fe68:a231 remote-as @var{as-number}
+ neighbor 3ffe:1cfa:0:2:2c0:4fff:fe68:a231 route-map set-nexthop out
+ exit-address-family
+!
+ipv6 access-list all permit any
+!
+! Set output nexthop address.
+!
+route-map set-nexthop permit 10
+ match ipv6 address all
+ set ipv6 nexthop global 3ffe:1cfa:0:2:2c0:4fff:fe68:a225
+ set ipv6 nexthop local fe80::2c0:4fff:fe68:a225
+!
+! logfile FILENAME is obsolete.  Please use log file FILENAME
+
+log file bgpd.log
+!
+@end group
+@end example
+
+@node Dump BGP packets and table
+@section Dump BGP packets and table
+
+@deffn Command {dump bgp all @var{path} [@var{interval}]} {}
+@deffnx Command {dump bgp all-et @var{path} [@var{interval}]} {}
+@deffnx Command {no dump bgp all [@var{path}] [@var{interval}]} {}
+Dump all BGP packet and events to @var{path} file.
+If @var{interval} is set, a new file will be created for echo @var{interval} of seconds.
+The path @var{path} can be set with date and time formatting (strftime).
+The type â€˜all-et’ enables support for Extended Timestamp Header (@pxref{Packet Binary Dump Format}).
+(@pxref{Packet Binary Dump Format})
+@end deffn 
+
+@deffn Command {dump bgp updates @var{path} [@var{interval}]} {}
+@deffnx Command {dump bgp updates-et @var{path} [@var{interval}]} {}
+@deffnx Command {no dump bgp updates [@var{path}] [@var{interval}]} {}
+Dump only BGP updates messages to @var{path} file.
+If @var{interval} is set, a new file will be created for echo @var{interval} of seconds.
+The path @var{path} can be set with date and time formatting (strftime).
+The type â€˜updates-et’ enables support for Extended Timestamp Header (@pxref{Packet Binary Dump Format}).
+@end deffn
+
+@deffn Command {dump bgp routes-mrt @var{path}} {}
+@deffnx Command {dump bgp routes-mrt @var{path} @var{interval}} {}
+@deffnx Command {no dump bgp route-mrt [@var{path}] [@var{interval}]} {}
+Dump whole BGP routing table to @var{path}.  This is heavy process.
+The path @var{path} can be set with date and time formatting (strftime).
+If @var{interval} is set, a new file will be created for echo @var{interval} of seconds.
+@end deffn
+
+Note: the interval variable can also be set using hours and minutes: 04h20m00.
+
+
+@node BGP Configuration Examples
+@section BGP Configuration Examples
+
+Example of a session to an upstream, advertising only one prefix to it.
+
+@example
+router bgp 64512
+ bgp router-id 10.236.87.1
+ neighbor upstream peer-group
+ neighbor upstream remote-as 64515
+ neighbor upstream capability dynamic
+ neighbor 10.1.1.1 peer-group upstream
+ neighbor 10.1.1.1 description ACME ISP
+
+ address-family ipv4 unicast
+  network 10.236.87.0/24
+  neighbor upstream prefix-list pl-allowed-adv out
+ exit-address-family
+!
+ip prefix-list pl-allowed-adv seq 5 permit 82.195.133.0/25
+ip prefix-list pl-allowed-adv seq 10 deny any
+
+@end example
+
+A more complex example. With upstream, peer and customer sessions.
+Advertising global prefixes and NO_EXPORT prefixes and providing
+actions for customer routes based on community values. Extensive use of
+route-maps and the 'call' feature to support selective advertising of
+prefixes. This example is intended as guidance only, it has NOT been
+tested and almost certainly containts silly mistakes, if not serious
+flaws.
+
+@example
+router bgp 64512
+ bgp router-id 10.236.87.1
+ neighbor upstream capability dynamic
+ neighbor cust capability dynamic
+ neighbor peer capability dynamic
+ neighbor 10.1.1.1 remote-as 64515
+ neighbor 10.1.1.1 peer-group upstream
+ neighbor 10.2.1.1 remote-as 64516
+ neighbor 10.2.1.1 peer-group upstream
+ neighbor 10.3.1.1 remote-as 64517
+ neighbor 10.3.1.1 peer-group cust-default
+ neighbor 10.3.1.1 description customer1
+ neighbor 10.4.1.1 remote-as 64518
+ neighbor 10.4.1.1 peer-group cust
+ neighbor 10.4.1.1 description customer2
+ neighbor 10.5.1.1 remote-as 64519
+ neighbor 10.5.1.1 peer-group peer
+ neighbor 10.5.1.1 description peer AS 1
+ neighbor 10.6.1.1 remote-as 64520
+ neighbor 10.6.1.1 peer-group peer
+ neighbor 10.6.1.1 description peer AS 2
+
+ address-family ipv4 unicast
+  network 10.123.456.0/24
+  network 10.123.456.128/25 route-map rm-no-export
+  neighbor upstream route-map rm-upstream-out out
+  neighbor cust route-map rm-cust-in in
+  neighbor cust route-map rm-cust-out out
+  neighbor cust send-community both
+  neighbor peer route-map rm-peer-in in
+  neighbor peer route-map rm-peer-out out
+  neighbor peer send-community both
+  neighbor 10.3.1.1 prefix-list pl-cust1-network in
+  neighbor 10.4.1.1 prefix-list pl-cust2-network in
+  neighbor 10.5.1.1 prefix-list pl-peer1-network in
+  neighbor 10.6.1.1 prefix-list pl-peer2-network in
+ exit-address-family
+!
+ip prefix-list pl-default permit 0.0.0.0/0
+!
+ip prefix-list pl-upstream-peers permit 10.1.1.1/32
+ip prefix-list pl-upstream-peers permit 10.2.1.1/32
+!
+ip prefix-list pl-cust1-network permit 10.3.1.0/24
+ip prefix-list pl-cust1-network permit 10.3.2.0/24
+!
+ip prefix-list pl-cust2-network permit 10.4.1.0/24
+!
+ip prefix-list pl-peer1-network permit 10.5.1.0/24
+ip prefix-list pl-peer1-network permit 10.5.2.0/24
+ip prefix-list pl-peer1-network permit 192.168.0.0/24
+!
+ip prefix-list pl-peer2-network permit 10.6.1.0/24
+ip prefix-list pl-peer2-network permit 10.6.2.0/24
+ip prefix-list pl-peer2-network permit 192.168.1.0/24
+ip prefix-list pl-peer2-network permit 192.168.2.0/24
+ip prefix-list pl-peer2-network permit 172.16.1/24
+!
+ip as-path access-list asp-own-as permit ^$
+ip as-path access-list asp-own-as permit _64512_
+!
+! #################################################################
+! Match communities we provide actions for, on routes receives from
+! customers. Communities values of <our-ASN>:X, with X, have actions:
+!
+! 100 - blackhole the prefix
+! 200 - set no_export
+! 300 - advertise only to other customers
+! 400 - advertise only to upstreams
+! 500 - set no_export when advertising to upstreams
+! 2X00 - set local_preference to X00
+!
+! blackhole the prefix of the route
+ip community-list standard cm-blackhole permit 64512:100
+!
+! set no-export community before advertising
+ip community-list standard cm-set-no-export permit 64512:200
+!
+! advertise only to other customers
+ip community-list standard cm-cust-only permit 64512:300
+!
+! advertise only to upstreams
+ip community-list standard cm-upstream-only permit 64512:400
+!
+! advertise to upstreams with no-export
+ip community-list standard cm-upstream-noexport permit 64512:500
+!
+! set local-pref to least significant 3 digits of the community
+ip community-list standard cm-prefmod-100 permit 64512:2100
+ip community-list standard cm-prefmod-200 permit 64512:2200
+ip community-list standard cm-prefmod-300 permit 64512:2300
+ip community-list standard cm-prefmod-400 permit 64512:2400
+ip community-list expanded cme-prefmod-range permit 64512:2...
+!
+! Informational communities
+!
+! 3000 - learned from upstream
+! 3100 - learned from customer
+! 3200 - learned from peer
+!
+ip community-list standard cm-learnt-upstream permit 64512:3000
+ip community-list standard cm-learnt-cust permit 64512:3100
+ip community-list standard cm-learnt-peer permit 64512:3200
+!
+! ###################################################################
+! Utility route-maps
+!
+! These utility route-maps generally should not used to permit/deny
+! routes, i.e. they do not have meaning as filters, and hence probably
+! should be used with 'on-match next'. These all finish with an empty
+! permit entry so as not interfere with processing in the caller.
+!
+route-map rm-no-export permit 10
+ set community additive no-export
+route-map rm-no-export permit 20
+!
+route-map rm-blackhole permit 10
+ description blackhole, up-pref and ensure it cant escape this AS
+ set ip next-hop 127.0.0.1
+ set local-preference 10
+ set community additive no-export
+route-map rm-blackhole permit 20
+!
+! Set local-pref as requested
+route-map rm-prefmod permit 10
+ match community cm-prefmod-100
+ set local-preference 100
+route-map rm-prefmod permit 20
+ match community cm-prefmod-200
+ set local-preference 200
+route-map rm-prefmod permit 30
+ match community cm-prefmod-300
+ set local-preference 300
+route-map rm-prefmod permit 40
+ match community cm-prefmod-400
+ set local-preference 400
+route-map rm-prefmod permit 50
+!
+! Community actions to take on receipt of route.
+route-map rm-community-in permit 10
+ description check for blackholing, no point continuing if it matches.
+ match community cm-blackhole
+ call rm-blackhole
+route-map rm-community-in permit 20
+ match community cm-set-no-export
+ call rm-no-export
+ on-match next
+route-map rm-community-in permit 30
+ match community cme-prefmod-range
+ call rm-prefmod
+route-map rm-community-in permit 40
+!
+! #####################################################################
+! Community actions to take when advertising a route.
+! These are filtering route-maps, 
+!
+! Deny customer routes to upstream with cust-only set.
+route-map rm-community-filt-to-upstream deny 10
+ match community cm-learnt-cust
+ match community cm-cust-only
+route-map rm-community-filt-to-upstream permit 20
+!
+! Deny customer routes to other customers with upstream-only set.
+route-map rm-community-filt-to-cust deny 10
+ match community cm-learnt-cust
+ match community cm-upstream-only
+route-map rm-community-filt-to-cust permit 20
+!
+! ###################################################################
+! The top-level route-maps applied to sessions. Further entries could
+! be added obviously..
+!
+! Customers
+route-map rm-cust-in permit 10
+ call rm-community-in
+ on-match next
+route-map rm-cust-in permit 20
+ set community additive 64512:3100
+route-map rm-cust-in permit 30
+!
+route-map rm-cust-out permit 10
+ call rm-community-filt-to-cust
+ on-match next
+route-map rm-cust-out permit 20
+!
+! Upstream transit ASes
+route-map rm-upstream-out permit 10
+ description filter customer prefixes which are marked cust-only
+ call rm-community-filt-to-upstream
+ on-match next
+route-map rm-upstream-out permit 20
+ description only customer routes are provided to upstreams/peers
+ match community cm-learnt-cust
+!
+! Peer ASes
+! outbound policy is same as for upstream
+route-map rm-peer-out permit 10
+ call rm-upstream-out
+!
+route-map rm-peer-in permit 10
+ set community additive 64512:3200
+@end example
+
+@include rpki.texi
diff --git a/doc/install.texi b/doc/install.texi
new file mode 100644 (file)
index 0000000..d0d5680
--- /dev/null
@@ -0,0 +1,291 @@
+@node  Installation
+@chapter Installation
+
+@cindex How to install Frr
+@cindex Installation
+@cindex Installing Frr
+@cindex Building the system
+@cindex Making Frr
+
+There are three steps for installing the software: configuration,
+compilation, and installation.
+
+@menu
+* Configure the Software::
+* Build the Software::
+* Install the Software::
+@end menu
+
+The easiest way to get Frr running is to issue the following
+commands:
+
+@example
+% configure
+% make
+% make install
+@end example
+
+@node Configure the Software
+@section Configure the Software
+
+@menu
+* The Configure script and its options::
+* Least-Privilege support::
+* Linux notes::
+@end menu
+
+@node The Configure script and its options
+@subsection The Configure script and its options
+
+@cindex Configuration options
+@cindex Options for configuring
+@cindex Build options
+@cindex Distribution configuration
+@cindex Options to @code{./configure}
+Frr has an excellent configure script which automatically detects most
+host configurations.  There are several additional configure options to
+customize the build to include or exclude specific features and dependencies.
+
+@table @option
+@item --disable-zebra
+Do not build zebra daemon.
+@item --disable-ripd
+Do not build ripd.
+@item --disable-ripngd
+Do not build ripngd.
+@item --disable-ospfd
+Do not build ospfd.
+@item --disable-ospf6d
+Do not build ospf6d.
+@item --disable-bgpd
+Do not build bgpd.
+@item --disable-bgp-announce
+Make @command{bgpd} which does not make bgp announcements at all.  This
+feature is good for using @command{bgpd} as a BGP announcement listener.
+@item --enable-datacenter
+Enable system defaults to work as if in a Data Center. See defaults.h
+for what is changed by this configure option.
+@item --enable-snmp
+Enable SNMP support.  By default, SNMP support is disabled.
+@item --disable-ospfapi
+Disable support for OSPF-API, an API to interface directly with ospfd.
+OSPF-API is enabled if --enable-opaque-lsa is set.
+@item --disable-ospfclient
+Disable building of the example OSPF-API client.
+@item --disable-ospf-ri
+Disable support for OSPF Router Information (RFC4970 & RFC5088) this
+requires support for Opaque LSAs and Traffic Engineering.
+@item --disable-isisd
+Do not build isisd.
+@item --enable-isis-topology
+Enable IS-IS topology generator.
+@item --enable-isis-te
+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
+Pass the @command{-rdynamic} option to the linker driver.  This is in most
+cases neccessary for getting usable backtraces.  This option defaults to on
+if the compiler is detected as gcc, but giving an explicit enable/disable is
+suggested.
+@item --disable-backtrace
+Controls backtrace support for the crash handlers. This is autodetected by
+default. Using the switch will enforce the requested behaviour, failing with
+an error if support is requested but not available.  On BSD systems, this
+needs libexecinfo, while on glibc support for this is part of libc itself.
+@item --enable-dev-build
+Turn on some options for compiling FRR within a development environment in
+mind.  Specifically turn on -g3 -O0 for compiling options and add inclusion
+of grammar sandbox.
+@item --enable-fuzzing
+Turn on some compile options to allow you to run fuzzing tools
+against the system.  This tools is intended as a developer
+only tool and should not be used for normal operations
+@end table
+
+You may specify any combination of the above options to the configure
+script.  By default, the executables are placed in @file{/usr/local/sbin} 
+and the configuration files in @file{/usr/local/etc}. The @file{/usr/local/}
+installation prefix and other directories may be changed using the following 
+options to the configuration script.
+
+@table @option
+@item --prefix=@var{prefix}
+Install architecture-independent files in @var{prefix} [/usr/local].
+@item --sysconfdir=@var{dir}
+Look for configuration files in @var{dir} [@var{prefix}/etc]. Note
+that sample configuration files will be installed here.
+@item --localstatedir=@var{dir}
+Configure zebra to use @var{dir} for local state files, such
+as pid files and unix sockets.
+@end table
+
+@example
+% ./configure --disable-snmp
+@end example
+
+This command will configure zebra and the routing daemons.
+
+@node Least-Privilege support
+@subsection Least-Privilege support
+
+@cindex Frr Least-Privileges
+@cindex Frr Privileges
+
+Additionally, you may configure zebra to drop its elevated privileges
+shortly after startup and switch to another user. The configure script will
+automatically try to configure this support. There are three configure
+options to control the behaviour of Frr daemons.
+
+@table @option
+@item --enable-user=@var{user}
+Switch to user @var{ARG} shortly after startup, and run as user @var{ARG}
+in normal operation.
+@item --enable-group=@var{group}
+Switch real and effective group to @var{group} shortly after
+startup. 
+@item --enable-vty-group=@var{group}
+Create Unix Vty sockets (for use with vtysh) with group owndership set to
+@var{group}. This allows one to create a seperate group which is
+restricted to accessing only the Vty sockets, hence allowing one to
+delegate this group to individual users, or to run vtysh setgid to
+this group.
+@end table
+
+The default user and group which will be configured is 'frr' if no user
+or group is specified. Note that this user or group requires write access to
+the local state directory (see --localstatedir) and requires at least read
+access, and write access if you wish to allow daemons to write out their
+configuration, to the configuration directory (see --sysconfdir).
+
+On systems which have the 'libcap' capabilities manipulation library
+(currently only linux), the frr system will retain only minimal
+capabilities required, further it will only raise these capabilities for
+brief periods. On systems without libcap, frr will run as the user
+specified and only raise its uid back to uid 0 for brief periods.
+
+@node Linux notes
+@subsection Linux Notes
+
+@cindex Configuring Frr
+@cindex Building on Linux boxes
+@cindex Linux configurations
+
+There are several options available only to @sc{gnu}/Linux systems:
+@footnote{@sc{gnu}/Linux has very flexible kernel configuration features}.  If
+you use @sc{gnu}/Linux, make sure that the current kernel configuration is
+what you want.  Frr will run with any kernel configuration but some
+recommendations do exist.
+
+@table @var
+
+@item CONFIG_NETLINK
+Kernel/User netlink socket. This is a brand new feature which enables an
+advanced interface between the Linux kernel and zebra (@pxref{Kernel Interface}).
+
+@item CONFIG_RTNETLINK
+Routing messages.
+This makes it possible to receive netlink routing messages.  If you
+specify this option, @command{zebra} can detect routing information
+updates directly from the kernel (@pxref{Kernel Interface}).
+
+@item CONFIG_IP_MULTICAST
+IP: multicasting.  
+This option should be specified when you use @command{ripd} (@pxref{RIP}) or
+@command{ospfd} (@pxref{OSPFv2}) because these protocols use multicast.
+
+@end table
+
+IPv6 support has been added in @sc{gnu}/Linux kernel version 2.2.  If you
+try to use the Frr IPv6 feature on a @sc{gnu}/Linux kernel, please
+make sure the following libraries have been installed.  Please note that
+these libraries will not be needed when you uses @sc{gnu} C library 2.1
+or upper.
+
+@table @code
+
+@item inet6-apps
+The @code{inet6-apps} package includes basic IPv6 related libraries such
+as @code{inet_ntop} and @code{inet_pton}.  Some basic IPv6 programs such
+as @command{ping}, @command{ftp}, and @command{inetd} are also
+included. The @code{inet-apps} can be found at
+@uref{ftp://ftp.inner.net/pub/ipv6/}.
+
+@item net-tools
+The @code{net-tools} package provides an IPv6 enabled interface and
+routing utility.  It contains @command{ifconfig}, @command{route},
+@command{netstat}, and other tools.  @code{net-tools} may be found at
+@uref{http://www.tazenda.demon.co.uk/phil/net-tools/}.
+
+@end table
+@c A - end of footnote 
+
+@node Build the Software
+@section Build the Software
+
+After configuring the software, you will need to compile it for your
+system. Simply issue the command @command{make} in the root of the source
+directory and the software will be compiled. Cliff Note versions of
+different compilation examples can be found in the doc/Building_FRR_on_XXX.md
+files.  If you have *any* problems at this stage, be certain to send a
+bug report @xref{Bug Reports}.
+
+@example
+% ./bootstrap.sh
+% ./configure <appropriate to your system>
+% make
+@end example
+@c A - End of node, Building the Software
+
+
+@node Install the Software
+@comment  node-name,  next,  previous,  up
+@section Install the Software
+
+Installing the software to your system consists of copying the compiled
+programs and supporting files to a standard location. After the
+installation process has completed, these files have been copied
+from your work directory to @file{/usr/local/bin}, and @file{/usr/local/etc}.
+
+To install the Frr suite, issue the following command at your shell
+prompt: @command{make install}.
+
+@example
+%
+% make install
+%
+@end example
+
+Frr daemons have their own terminal interface or VTY.  After
+installation, you have to setup each beast's port number to connect to
+them.  Please add the following entries to @file{/etc/services}.
+
+@example
+zebrasrv      2600/tcp           # zebra service
+zebra         2601/tcp           # zebra vty
+ripd          2602/tcp           # RIPd vty
+ripngd        2603/tcp           # RIPngd vty
+ospfd         2604/tcp           # OSPFd vty
+bgpd          2605/tcp           # BGPd vty
+ospf6d        2606/tcp           # OSPF6d vty
+ospfapi       2607/tcp           # ospfapi
+isisd         2608/tcp           # ISISd vty
+nhrpd         2610/tcp           # nhrpd vty
+pimd          2611/tcp           # PIMd vty
+@end example
+
+If you use a FreeBSD newer than 2.2.8, the above entries are already
+added to @file{/etc/services} so there is no need to add it. If you
+specify a port number when starting the daemon, these entries may not be
+needed.
+
+You may need to make changes to the config files in
+@file{@value{INSTALL_PREFIX_ETC}/*.conf}. @xref{Config Commands}.
diff --git a/doc/isisd.texi b/doc/isisd.texi
new file mode 100644 (file)
index 0000000..404698d
--- /dev/null
@@ -0,0 +1,433 @@
+@cindex ISIS
+@node ISIS
+@chapter ISIS
+
+@acronym{ISIS,Intermediate System to Intermediate System} is a routing protocol
+which is described in @cite{ISO10589, RFC1195, RFC5308}.  ISIS is an
+@acronym{IGP,Interior Gateway Protocol}.  Compared with @acronym{RIP},
+@acronym{ISIS} can provide scalable network support and faster
+convergence times like @acronym{OSPF}. ISIS is widely used in large networks such as
+@acronym{ISP,Internet Service Provider} and carrier backbone networks.
+
+@menu
+* Configuring isisd::
+* ISIS router::
+* ISIS Timer::
+* ISIS region::
+* ISIS interface::
+* Showing ISIS information::
+* ISIS Traffic Engineering::
+* Debugging ISIS::
+* ISIS Configuration Examples::
+@end menu
+
+@node Configuring isisd
+@section Configuring isisd
+
+There are no @command{isisd} specific options.  Common options can be
+specified (@pxref{Common Invocation Options}) to @command{isisd}.
+@command{isisd} needs to acquire interface information from
+@command{zebra} in order to function. Therefore @command{zebra} must be
+running before invoking @command{isisd}. Also, if @command{zebra} is
+restarted then @command{isisd} must be too.
+
+Like other daemons, @command{isisd} configuration is done in @acronym{ISIS}
+specific configuration file @file{isisd.conf}.
+
+@node ISIS router
+@section ISIS router
+
+To start ISIS process you have to specify the ISIS router. As of this
+writing, @command{isisd} does not support multiple ISIS processes.
+
+@deffn Command {router isis WORD} {}
+@deffnx Command {no router isis WORD} {}
+@anchor{router isis WORD}Enable or disable the ISIS process by specifying the ISIS domain with 'WORD'.
+@command{isisd} does not yet support multiple ISIS processes but you must specify
+the name of ISIS process. The ISIS process name 'WORD' is then used for interface
+(see command @ref{ip router isis WORD}).
+@end deffn
+
+@deffn {ISIS Command} {net XX.XXXX. ... .XXX.XX} {}
+@deffnx {ISIS Command} {no net XX.XXXX. ... .XXX.XX} {}
+Set/Unset network entity title (NET) provided in ISO format.
+@end deffn
+
+@deffn {ISIS Command} {hostname dynamic} {}
+@deffnx {ISIS Command} {no hostname dynamic} {}
+Enable support for dynamic hostname.
+@end deffn
+
+@deffn {ISIS Command} {area-password [clear | md5] <password>} {}
+@deffnx {ISIS Command} {domain-password [clear | md5] <password>} {}
+@deffnx {ISIS Command} {no area-password} {}
+@deffnx {ISIS Command} {no domain-password} {}
+Configure the authentication password for an area, respectively a domain,
+as clear text or md5 one.
+@end deffn
+
+@deffn {ISIS Command} {log-adjacency-changes} {}
+@deffnx {ISIS Command} {no log-adjacency-changes} {}
+Log changes in adjacency state.
+@end deffn
+
+@deffn {ISIS Command} {metric-style [narrow | transition | wide]} {}
+@deffnx {ISIS Command} {no metric-style} {}
+@anchor{metric-style}Set old-style (ISO 10589) or new-style packet formats:
+  - narrow      Use old style of TLVs with narrow metric
+  - transition  Send and accept both styles of TLVs during transition
+  - wide        Use new style of TLVs to carry wider metric
+@end deffn
+
+@deffn {ISIS Command} {set-overload-bit} {}
+@deffnx {ISIS Command} {no set-overload-bit} {}
+Set overload bit to avoid any transit traffic.
+@end deffn
+
+@node ISIS Timer
+@section ISIS Timer
+
+@deffn {ISIS Command} {lsp-gen-interval <1-120>} {}
+@deffnx {ISIS Command} {lsp-gen-interval [level-1 | level-2] <1-120>} {}
+@deffnx {ISIS Command} {no lsp-gen-interval} {}
+@deffnx {ISIS Command} {no lsp-gen-interval [level-1 | level-2]} {}
+Set minimum interval in seconds between regenerating same LSP,
+globally, for an area (level-1) or a domain (level-2).
+@end deffn
+
+@deffn {ISIS Command} {lsp-refresh-interval <1-65235>} {}
+@deffnx {ISIS Command} {lsp-refresh-interval [level-1 | level-2] <1-65235>} {}
+@deffnx {ISIS Command} {no lsp-refresh-interval} {}
+@deffnx {ISIS Command} {no lsp-refresh-interval [level-1 | level-2]} {}
+Set LSP refresh interval in seconds, globally, for an area (level-1) or a domain (level-2).
+@end deffn
+
+@deffn {ISIS Command} {lsp-refresh-interval <1-65235>} {}
+@deffnx {ISIS Command} {lsp-refresh-interval [level-1 | level-2] <1-65235>} {}
+@deffnx {ISIS Command} {no lsp-refresh-interval} {}
+@deffnx {ISIS Command} {no lsp-refresh-interval [level-1 | level-2]} {}
+Set LSP refresh interval in seconds, globally, for an area (level-1) or a domain (level-2).
+@end deffn
+
+@deffn {ISIS Command} {max-lsp-lifetime <360-65535>} {}
+@deffnx {ISIS Command} {max-lsp-lifetime [level-1 | level-2] <360-65535>} {}
+@deffnx {ISIS Command} {no max-lsp-lifetime} {}
+@deffnx {ISIS Command} {no max-lsp-lifetime [level-1 | level-2]} {}
+Set LSP maximum LSP lifetime in seconds, globally, for an area (level-1) or a domain (level-2).
+@end deffn
+
+@deffn {ISIS Command} {spf-interval <1-120>} {}
+@deffnx {ISIS Command} {spf-interval [level-1 | level-2] <1-120>} {}
+@deffnx {ISIS Command} {no spf-interval} {}
+@deffnx {ISIS Command} {no spf-interval [level-1 | level-2]} {}
+Set minimum interval between consecutive SPF calculations in seconds.
+@end deffn
+
+@node ISIS region
+@section ISIS region
+
+@deffn {ISIS Command} {is-type [level-1 | level-1-2 | level-2-only]} {}
+@deffnx {ISIS Command} {no is-type} {}
+Define the ISIS router behavior:
+ - level-1       Act as a station router only
+ - level-1-2     Act as both a station router and an area router
+ - level-2-only  Act as an area router only
+@end deffn
+
+@node ISIS interface
+@section ISIS interface
+
+@deffn {Interface Command} {ip router isis WORD} {}
+@deffnx {Interface Command} {no ip router isis WORD} {}
+@anchor{ip router isis WORD}Activate ISIS adjacency on this interface. Note that the name
+of ISIS instance must be the same as the one used to configure the ISIS process
+(see command @ref{router isis WORD}).
+@end deffn
+
+@deffn {Interface Command} {isis circuit-type [level-1 | level-1-2 | level-2]} {}
+@deffnx {Interface Command} {no isis circuit-type} {}
+Configure circuit type for interface:
+  - level-1       Level-1 only adjacencies are formed
+  - level-1-2     Level-1-2 adjacencies are formed
+  - level-2-only  Level-2 only adjacencies are formed
+@end deffn
+
+@deffn {Interface Command} {isis csnp-interval <1-600>} {}
+@deffnx {Interface Command} {isis csnp-interval <1-600> [level-1 | level-2]} {}
+@deffnx {Interface Command} {no isis csnp-interval} {}
+@deffnx {Interface Command} {no isis csnp-interval [level-1 | level-2]} {}
+Set CSNP interval in seconds globally, for an area (level-1) or a domain (level-2).
+@end deffn
+
+@deffn {Interface Command} {isis hello padding} {}
+Add padding to IS-IS hello packets.
+@end deffn
+
+@deffn {Interface Command} {isis hello-interval <1-600>} {}
+@deffnx {Interface Command} {isis hello-interval <1-600> [level-1 | level-2]} {}
+@deffnx {Interface Command} {no isis hello-interval} {}
+@deffnx {Interface Command} {no isis hello-interval [level-1 | level-2]} {}
+Set Hello interval in seconds globally, for an area (level-1) or a domain (level-2).
+@end deffn
+
+@deffn {Interface Command} {isis hello-multiplier <2-100>} {}
+@deffnx {Interface Command} {isis hello-multiplier <2-100> [level-1 | level-2]} {}
+@deffnx {Interface Command} {no isis hello-multiplier} {}
+@deffnx {Interface Command} {no isis hello-multiplier [level-1 | level-2]} {}
+Set multiplier for Hello holding time globally, for an area (level-1) or a domain (level-2).
+@end deffn
+
+@deffn {Interface Command} {isis metric [<0-255> | <0-16777215>]} {}
+@deffnx {Interface Command} {isis metric [<0-255> | <0-16777215>] [level-1 | level-2]} {}
+@deffnx {Interface Command} {no isis metric} {}
+@deffnx {Interface Command} {no isis metric [level-1 | level-2]} {}
+Set default metric value globally, for an area (level-1) or a domain (level-2).
+Max value depend if metric support narrow or wide value (see command @ref{metric-style}).
+@end deffn
+
+@deffn {Interface Command} {isis network point-to-point} {}
+@deffnx {Interface Command} {no isis network point-to-point} {}
+Set network type to 'Point-to-Point' (broadcast by default).
+@end deffn
+
+@deffn {Interface Command} {isis passive} {}
+@deffnx {Interface Command} {no isis passive} {}
+Configure the passive mode for this interface.
+@end deffn
+
+@deffn {Interface Command} {isis password [clear | md5] <password>} {}
+@deffnx {Interface Command} {no isis password} {}
+Configure the authentication password (clear or encoded text) for the interface.
+@end deffn
+
+@deffn {Interface Command} {isis priority <0-127>} {}
+@deffnx {Interface Command} {isis priority <0-127> [level-1 | level-2]} {}
+@deffnx {Interface Command} {no isis priority} {}
+@deffnx {Interface Command} {no isis priority [level-1 | level-2]} {}
+Set priority for Designated Router election, globally, for the area (level-1)
+or the domain (level-2).
+@end deffn
+
+@deffn {Interface Command} {isis psnp-interval <1-120>} {}
+@deffnx {Interface Command} {isis psnp-interval <1-120> [level-1 | level-2]} {}
+@deffnx {Interface Command} {no isis psnp-interval} {}
+@deffnx {Interface Command} {no isis psnp-interval [level-1 | level-2]} {}
+Set PSNP interval in seconds globally, for an area (level-1) or a domain (level-2).
+@end deffn
+
+@node Showing ISIS information
+@section Showing ISIS information
+
+@deffn {Command} {show isis summary} {}
+Show summary information about ISIS.
+@end deffn
+
+@deffn {Command} {show isis hostname} {}
+Show information about ISIS node.
+@end deffn
+
+@deffn {Command} {show isis interface} {}
+@deffnx {Command} {show isis interface detail} {}
+@deffnx {Command} {show isis interface <interface name>} {}
+Show state and configuration of ISIS specified interface, or all
+interfaces if no interface is given with or without details.
+@end deffn
+
+@deffn {Command} {show isis neighbor} {}
+@deffnx {Command} {show isis neighbor <System Id>} {}
+@deffnx {Command} {show isis neighbor detail} {}
+Show state and information of ISIS specified neighbor, or all
+neighbors if no system id is given with or without details.
+@end deffn
+
+@deffn {Command} {show isis database} {}
+@deffnx {Command} {show isis database [detail]} {}
+@deffnx {Command} {show isis database <LSP id> [detail]} {}
+@deffnx {Command} {show isis database detail <LSP id>} {}
+Show the ISIS database globally, for a specific LSP id without or with details.
+@end deffn
+
+@deffn {Command} {show isis topology} {}
+@deffnx {Command} {show isis topology [level-1|level-2]} {}
+Show topology IS-IS paths to Intermediate Systems, globally,
+in area (level-1) or domain (level-2).
+@end deffn
+
+@deffn {Command} {show ip route isis} {}
+Show the ISIS routing table, as determined by the most recent SPF calculation.
+@end deffn
+
+@node ISIS Traffic Engineering
+@section Traffic Engineering
+
+@deffn {ISIS Command} {mpls-te on} {}
+@deffnx {ISIS Command} {no mpls-te} {}
+Enable Traffic Engineering LSP flooding.
+@end deffn
+
+@deffn {ISIS Command} {mpls-te router-address <A.B.C.D>} {}
+@deffnx {ISIS Command} {no mpls-te router-address} {}
+Configure stable IP address for MPLS-TE.
+@end deffn
+
+@deffn {Command} {show isis mpls-te interface} {}
+@deffnx {Command} {show isis mpls-te interface @var{interface}} {}
+Show MPLS Traffic Engineering parameters for all or specified interface.
+@end deffn
+
+@deffn {Command} {show isis mpls-te router} {}
+Show Traffic Engineering router parameters.
+@end deffn
+
+@node Debugging ISIS
+@section Debugging ISIS
+
+@deffn {Command} {debug isis adj-packets} {}
+@deffnx {Command} {no debug isis adj-packets} {}
+IS-IS Adjacency related packets.
+@end deffn
+
+@deffn {Command} {debug isis checksum-errors} {}
+@deffnx {Command} {no debug isis checksum-errors} {}
+IS-IS LSP checksum errors.
+@end deffn
+
+@deffn {Command} {debug isis events} {}
+@deffnx {Command} {no debug isis events} {}
+IS-IS Events.
+@end deffn
+
+@deffn {Command} {debug isis local-updates} {}
+@deffnx {Command} {no debug isis local-updates} {}
+IS-IS local update packets.
+@end deffn
+
+@deffn {Command} {debug isis packet-dump} {}
+@deffnx {Command} {no debug isis packet-dump} {}
+IS-IS packet dump.
+@end deffn
+
+@deffn {Command} {debug isis protocol-errors} {}
+@deffnx {Command} {no debug isis protocol-errors} {}
+IS-IS LSP protocol errors.
+@end deffn
+
+@deffn {Command} {debug isis route-events} {}
+@deffnx {Command} {no debug isis route-events} {}
+IS-IS Route related events.
+@end deffn
+
+@deffn {Command} {debug isis snp-packets} {}
+@deffnx {Command} {no debug isis snp-packets} {}
+IS-IS CSNP/PSNP packets.
+@end deffn
+
+@deffn {Command} {debug isis spf-events} {}
+@deffnx {Command} {debug isis spf-statistics} {}
+@deffnx {Command} {debug isis spf-triggers} {}
+@deffnx {Command} {no debug isis spf-events} {}
+@deffnx {Command} {no debug isis spf-statistics} {}
+@deffnx {Command} {no debug isis spf-triggers} {}
+IS-IS Shortest Path First Events, Timing and Statistic Data
+and triggering events.
+@end deffn
+
+@deffn {Command} {debug isis update-packets} {}
+@deffnx {Command} {no debug isis update-packets} {}
+Update related packets.
+@end deffn
+
+@deffn {Command} {show debugging isis} {}
+Print which ISIS debug level is activate.
+@end deffn
+
+@node ISIS Configuration Examples
+@section ISIS Configuration Examples
+A simple example, with MD5 authentication enabled:
+
+@example
+@group
+!
+interface eth0
+ ip router isis FOO
+ isis network point-to-point
+ isis circuit-type level-2-only
+!
+router isis FOO
+net 47.0023.0000.0000.0000.0000.0000.0000.1900.0004.00
+ metric-style wide
+ is-type level-2-only
+@end group
+@end example
+
+
+A Traffic Engineering configuration, with Inter-ASv2 support.
+
+ - First, the 'zebra.conf' part:
+
+@example
+@group
+hostname HOSTNAME
+password PASSWORD
+log file /var/log/zebra.log
+!
+interface eth0
+ ip address 10.2.2.2/24
+ 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
+ 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
+
+ - Then the 'isisd.conf' itself:
+
+@example
+@group
+hostname HOSTNAME
+password PASSWORD
+log file /var/log/isisd.log
+!
+!
+interface eth0
+ ip router isis FOO
+!
+interface eth1
+ ip router isis FOO
+!
+!
+router isis FOO
+ isis net 47.0023.0000.0000.0000.0000.0000.0000.1900.0004.00
+  mpls-te on
+  mpls-te router-address 10.1.1.1
+!
+line vty
+@end group
+@end example
diff --git a/doc/ospfd.texi b/doc/ospfd.texi
new file mode 100644 (file)
index 0000000..26a7637
--- /dev/null
@@ -0,0 +1,930 @@
+
+@cindex OSPFv2
+@node OSPFv2
+@chapter OSPFv2
+
+@acronym{OSPF,Open Shortest Path First} version 2 is a routing protocol
+which is described in @cite{RFC2328, OSPF Version 2}.  OSPF is an
+@acronym{IGP,Interior Gateway Protocol}.  Compared with @acronym{RIP},
+@acronym{OSPF} can provide scalable network support and faster
+convergence times.  OSPF is widely used in large networks such as
+@acronym{ISP,Internet Service Provider} backbone and enterprise
+networks.
+
+@menu
+* OSPF Fundamentals::
+* Configuring ospfd::           
+* OSPF router::                 
+* OSPF area::                   
+* OSPF interface::              
+* Redistribute routes to OSPF::  
+* Showing OSPF information::    
+* Opaque LSA::
+* OSPF Traffic Engineering::
+* Router Information::
+* Debugging OSPF::              
+* OSPF Configuration Examples::
+@end menu
+
+@include ospf_fundamentals.texi
+
+@node Configuring ospfd
+@section Configuring ospfd
+
+There are no @command{ospfd} specific options.  Common options can be
+specified (@pxref{Common Invocation Options}) to @command{ospfd}.
+@command{ospfd} needs to acquire interface information from
+@command{zebra} in order to function. Therefore @command{zebra} must be
+running before invoking @command{ospfd}. Also, if @command{zebra} is
+restarted then @command{ospfd} must be too.
+
+Like other daemons, @command{ospfd} configuration is done in @acronym{OSPF}
+specific configuration file @file{ospfd.conf}.
+
+@node OSPF router
+@section OSPF router
+
+To start OSPF process you have to specify the OSPF router.  As of this
+writing, @command{ospfd} does not support multiple OSPF processes.
+
+@deffn Command {router ospf} {}
+@deffnx Command {no router ospf} {}
+Enable or disable the OSPF process.  @command{ospfd} does not yet
+support multiple OSPF processes.  So you can not specify an OSPF process
+number.
+@end deffn
+
+@deffn {OSPF Command} {ospf router-id @var{a.b.c.d}} {}
+@deffnx {OSPF Command} {no ospf router-id} {}
+@anchor{ospf router-id}This sets the router-ID of the OSPF process. The
+router-ID may be an IP address of the router, but need not be - it can
+be any arbitrary 32bit number. However it MUST be unique within the
+entire OSPF domain to the OSPF speaker - bad things will happen if
+multiple OSPF speakers are configured with the same router-ID! If one
+is not specified then @command{ospfd} will obtain a router-ID
+automatically from @command{zebra}.
+@end deffn
+
+@deffn {OSPF Command} {ospf abr-type @var{type}} {}
+@deffnx {OSPF Command} {no ospf abr-type @var{type}} {}
+@var{type} can be cisco|ibm|shortcut|standard. The "Cisco" and "IBM" types
+are equivalent.
+
+The OSPF standard for ABR behaviour does not allow an ABR to consider
+routes through non-backbone areas when its links to the backbone are
+down, even when there are other ABRs in attached non-backbone areas
+which still can reach the backbone - this restriction exists primarily
+to ensure routing-loops are avoided.
+
+With the "Cisco" or "IBM" ABR type, the default in this release of
+Frr, this restriction is lifted, allowing an ABR to consider
+summaries learnt from other ABRs through non-backbone areas, and hence
+route via non-backbone areas as a last resort when, and only when,
+backbone links are down.
+
+Note that areas with fully-adjacent virtual-links are considered to be
+"transit capable" and can always be used to route backbone traffic, and
+hence are unaffected by this setting (@pxref{OSPF virtual-link}).
+
+More information regarding the behaviour controlled by this command can
+be found in @cite{RFC 3509, Alternative Implementations of OSPF Area
+Border Routers}, and @cite{draft-ietf-ospf-shortcut-abr-02.txt}.
+
+Quote: "Though the definition of the @acronym{ABR,Area Border Router}
+in the OSPF specification does not require a router with multiple
+attached areas to have a backbone connection, it is actually
+necessary to provide successful routing to the inter-area and
+external destinations. If this requirement is not met, all traffic
+destined for the areas not connected to such an ABR or out of the
+OSPF domain, is dropped.  This document describes alternative ABR
+behaviors implemented in Cisco and IBM routers."
+@end deffn
+
+@deffn {OSPF Command} {ospf rfc1583compatibility} {}
+@deffnx {OSPF Command} {no ospf rfc1583compatibility} {}
+@cite{RFC2328}, the sucessor to @cite{RFC1583}, suggests according
+to section G.2 (changes) in section 16.4 a change to the path
+preference algorithm that prevents possible routing loops that were
+possible in the old version of OSPFv2. More specifically it demands
+that inter-area paths and intra-area backbone path are now of equal preference
+but still both preferred to external paths.
+
+This command should NOT be set normally.
+@end deffn
+
+@deffn {OSPF Command} {log-adjacency-changes [detail]} {}
+@deffnx {OSPF Command} {no log-adjacency-changes [detail]} {}
+Configures ospfd to log changes in adjacency.  With the optional
+detail argument, all changes in adjacency status are shown.  Without detail,
+only changes to full or regressions are shown.
+@end deffn
+
+@deffn {OSPF Command} {passive-interface @var{interface}} {}
+@deffnx {OSPF Command} {no passive-interface @var{interface}} {}
+@anchor{OSPF passive-interface} Do not speak OSPF interface on the
+given interface, but do advertise the interface as a stub link in the
+router-@acronym{LSA,Link State Advertisement} for this router. This
+allows one to advertise addresses on such connected interfaces without
+having to originate AS-External/Type-5 LSAs (which have global flooding
+scope) - as would occur if connected addresses were redistributed into
+OSPF (@pxref{Redistribute routes to OSPF})@. This is the only way to
+advertise non-OSPF links into stub areas.
+@end deffn
+
+@deffn {OSPF Command} {timers throttle spf @var{delay} @var{initial-holdtime} @var{max-holdtime}} {}
+@deffnx {OSPF Command} {no timers throttle spf} {}
+This command sets the initial @var{delay}, the @var{initial-holdtime}
+and the @var{maximum-holdtime} between when SPF is calculated and the
+event which triggered the calculation. The times are specified in
+milliseconds and must be in the range of 0 to 600000 milliseconds.
+
+The @var{delay} specifies the minimum amount of time to delay SPF
+calculation (hence it affects how long SPF calculation is delayed after
+an event which occurs outside of the holdtime of any previous SPF
+calculation, and also serves as a minimum holdtime).
+
+Consecutive SPF calculations will always be seperated by at least
+'hold-time' milliseconds. The hold-time is adaptive and initially is
+set to the @var{initial-holdtime} configured with the above command.
+Events which occur within the holdtime of the previous SPF calculation
+will cause the holdtime to be increased by @var{initial-holdtime}, bounded
+by the @var{maximum-holdtime} configured with this command. If the adaptive
+hold-time elapses without any SPF-triggering event occuring then 
+the current holdtime is reset to the @var{initial-holdtime}. The current
+holdtime can be viewed with @ref{show ip ospf}, where it is expressed as 
+a multiplier of the @var{initial-holdtime}.
+
+@example
+@group
+router ospf
+ timers throttle spf 200 400 10000
+@end group
+@end example
+
+In this example, the @var{delay} is set to 200ms, the @var{initial
+holdtime} is set to 400ms and the @var{maximum holdtime} to 10s. Hence
+there will always be at least 200ms between an event which requires SPF
+calculation and the actual SPF calculation. Further consecutive SPF
+calculations will always be seperated by between 400ms to 10s, the
+hold-time increasing by 400ms each time an SPF-triggering event occurs
+within the hold-time of the previous SPF calculation.
+
+This command supercedes the @command{timers spf} command in previous Frr
+releases.
+@end deffn
+
+@deffn {OSPF Command} {max-metric router-lsa [on-startup|on-shutdown] <5-86400>} {}
+@deffnx {OSPF Command} {max-metric router-lsa administrative} {}
+@deffnx {OSPF Command} {no max-metric router-lsa [on-startup|on-shutdown|administrative]} {}
+This enables @cite{RFC3137, OSPF Stub Router Advertisement} support,
+where the OSPF process describes its transit links in its router-LSA as
+having infinite distance so that other routers will avoid calculating
+transit paths through the router while still being able to reach
+networks through the router.
+
+This support may be enabled administratively (and indefinitely) or
+conditionally. Conditional enabling of max-metric router-lsas can be
+for a period of seconds after startup and/or for a period of seconds
+prior to shutdown. 
+
+Enabling this for a period after startup allows OSPF to converge fully
+first without affecting any existing routes used by other routers,
+while still allowing any connected stub links and/or redistributed
+routes to be reachable. Enabling this for a period of time in advance
+of shutdown allows the router to gracefully excuse itself from the OSPF
+domain. 
+
+Enabling this feature administratively allows for administrative
+intervention for whatever reason, for an indefinite period of time.
+Note that if the configuration is written to file, this administrative
+form of the stub-router command will also be written to file. If
+@command{ospfd} is restarted later, the command will then take effect
+until manually deconfigured.
+
+Configured state of this feature as well as current status, such as the
+number of second remaining till on-startup or on-shutdown ends, can be
+viewed with the @ref{show ip ospf} command.
+@end deffn
+
+@deffn {OSPF Command} {auto-cost reference-bandwidth <1-4294967>} {}
+@deffnx {OSPF Command} {no auto-cost reference-bandwidth} {}
+@anchor{OSPF auto-cost reference-bandwidth}This sets the reference
+bandwidth for cost calculations, where this bandwidth is considered
+equivalent to an OSPF cost of 1, specified in Mbits/s. The default is
+100Mbit/s (i.e. a link of bandwidth 100Mbit/s or higher will have a
+cost of 1. Cost of lower bandwidth links will be scaled with reference
+to this cost).
+
+This configuration setting MUST be consistent across all routers within the
+OSPF domain.
+@end deffn
+
+@deffn {OSPF Command} {network @var{a.b.c.d/m} area @var{a.b.c.d}} {}
+@deffnx {OSPF Command} {network @var{a.b.c.d/m} area @var{<0-4294967295>}} {}
+@deffnx {OSPF Command} {no network @var{a.b.c.d/m} area @var{a.b.c.d}} {}
+@deffnx {OSPF Command} {no network @var{a.b.c.d/m} area @var{<0-4294967295>}} {}
+@anchor{OSPF network command}
+This command specifies the OSPF enabled interface(s).  If the interface has
+an address from range 192.168.1.0/24 then the command below enables ospf
+on this interface so router can provide network information to the other
+ospf routers via this interface.
+
+@example
+@group
+router ospf
+ network 192.168.1.0/24 area 0.0.0.0
+@end group
+@end example
+
+Prefix length in interface must be equal or bigger (ie. smaller network) than
+prefix length in network statement. For example statement above doesn't enable
+ospf on interface with address 192.168.1.1/23, but it does on interface with
+address 192.168.1.129/25.
+
+Note that the behavior when there is a peer address
+defined on an interface changed after release 0.99.7.
+Currently, if a peer prefix has been configured,
+then we test whether the prefix in the network command contains
+the destination prefix.  Otherwise, we test whether the network command prefix
+contains the local address prefix of the interface. 
+
+In some cases it may be more convenient to enable OSPF on a per
+interface/subnet basis (@pxref{OSPF ip ospf area command}).
+
+@end deffn
+
+@node OSPF area
+@section OSPF area
+
+@deffn {OSPF Command} {area @var{a.b.c.d} range @var{a.b.c.d/m}} {}
+@deffnx {OSPF Command} {area <0-4294967295> range @var{a.b.c.d/m}} {}
+@deffnx {OSPF Command} {no area @var{a.b.c.d} range @var{a.b.c.d/m}} {}
+@deffnx {OSPF Command} {no area <0-4294967295> range @var{a.b.c.d/m}} {}
+Summarize intra area paths from specified area into one Type-3 summary-LSA
+announced to other areas. This command can be used only in ABR and ONLY
+router-LSAs (Type-1) and network-LSAs (Type-2) (ie. LSAs with scope area) can
+be summarized. Type-5 AS-external-LSAs can't be summarized - their scope is AS.
+Summarizing Type-7 AS-external-LSAs isn't supported yet by Frr.
+
+@example
+@group
+router ospf
+ network 192.168.1.0/24 area 0.0.0.0
+ network 10.0.0.0/8 area 0.0.0.10
+ area 0.0.0.10 range 10.0.0.0/8
+@end group
+@end example
+
+With configuration above one Type-3 Summary-LSA with routing info 10.0.0.0/8 is
+announced into backbone area if area 0.0.0.10 contains at least one intra-area
+network (ie. described with router or network LSA) from this range.
+@end deffn
+
+@deffn {OSPF Command} {area @var{a.b.c.d} range IPV4_PREFIX not-advertise} {}
+@deffnx {OSPF Command} {no area @var{a.b.c.d} range IPV4_PREFIX not-advertise} {}
+Instead of summarizing intra area paths filter them - ie. intra area paths from this
+range are not advertised into other areas.
+This command makes sense in ABR only.
+@end deffn
+
+@deffn {OSPF Command} {area @var{a.b.c.d} range IPV4_PREFIX substitute IPV4_PREFIX} {}
+@deffnx {OSPF Command} {no area @var{a.b.c.d} range IPV4_PREFIX substitute IPV4_PREFIX} {}
+Substitute summarized prefix with another prefix.
+
+@example
+@group
+router ospf
+ network 192.168.1.0/24 area 0.0.0.0
+ network 10.0.0.0/8 area 0.0.0.10
+ area 0.0.0.10 range 10.0.0.0/8 substitute 11.0.0.0/8
+@end group
+@end example
+
+One Type-3 summary-LSA with routing info 11.0.0.0/8 is announced into backbone area if
+area 0.0.0.10 contains at least one intra-area network (ie. described with router-LSA or
+network-LSA) from range 10.0.0.0/8.
+This command makes sense in ABR only.
+@end deffn
+
+@deffn {OSPF Command} {area @var{a.b.c.d} virtual-link @var{a.b.c.d}} {}
+@deffnx {OSPF Command} {area <0-4294967295> virtual-link @var{a.b.c.d}} {}
+@deffnx {OSPF Command} {no area @var{a.b.c.d} virtual-link @var{a.b.c.d}} {}
+@deffnx {OSPF Command} {no area <0-4294967295> virtual-link @var{a.b.c.d}} {}
+@anchor{OSPF virtual-link}
+@end deffn
+
+@deffn {OSPF Command} {area @var{a.b.c.d} shortcut} {}
+@deffnx {OSPF Command} {area <0-4294967295> shortcut} {}
+@deffnx {OSPF Command} {no area @var{a.b.c.d} shortcut} {}
+@deffnx {OSPF Command} {no area <0-4294967295> shortcut} {}
+Configure the area as Shortcut capable. See @cite{RFC3509}. This requires
+that the 'abr-type' be set to 'shortcut'.
+@end deffn
+
+@deffn {OSPF Command} {area @var{a.b.c.d} stub} {}
+@deffnx {OSPF Command} {area <0-4294967295> stub} {}
+@deffnx {OSPF Command} {no area @var{a.b.c.d} stub} {}
+@deffnx {OSPF Command} {no area <0-4294967295> stub} {}
+Configure the area to be a stub area. That is, an area where no router
+originates routes external to OSPF and hence an area where all external 
+routes are via the ABR(s). Hence, ABRs for such an area do not need
+to pass AS-External LSAs (type-5s) or ASBR-Summary LSAs (type-4) into the
+area. They need only pass Network-Summary (type-3) LSAs into such an area,
+along with a default-route summary.
+@end deffn
+
+@deffn {OSPF Command} {area @var{a.b.c.d} stub no-summary} {}
+@deffnx {OSPF Command} {area <0-4294967295> stub no-summary} {}
+@deffnx {OSPF Command} {no area @var{a.b.c.d} stub no-summary} {}
+@deffnx {OSPF Command} {no area <0-4294967295> stub no-summary} {}
+Prevents an @command{ospfd} ABR from injecting inter-area 
+summaries into the specified stub area.
+@end deffn
+
+@deffn {OSPF Command} {area @var{a.b.c.d} default-cost <0-16777215>} {}
+@deffnx {OSPF Command} {no area @var{a.b.c.d} default-cost <0-16777215>} {}
+Set the cost of default-summary LSAs announced to stubby areas.
+@end deffn
+
+@deffn {OSPF Command} {area @var{a.b.c.d} export-list NAME} {}
+@deffnx {OSPF Command} {area <0-4294967295> export-list NAME} {}
+@deffnx {OSPF Command} {no area @var{a.b.c.d} export-list NAME} {}
+@deffnx {OSPF Command} {no area <0-4294967295> export-list NAME} {}
+Filter Type-3 summary-LSAs announced to other areas originated from intra-
+area paths from specified area.
+
+@example
+@group
+router ospf
+ network 192.168.1.0/24 area 0.0.0.0
+ network 10.0.0.0/8 area 0.0.0.10
+ area 0.0.0.10 export-list foo
+!
+access-list foo permit 10.10.0.0/16
+access-list foo deny any
+@end group
+@end example
+
+With example above any intra-area paths from area 0.0.0.10 and from range
+10.10.0.0/16 (for example 10.10.1.0/24 and 10.10.2.128/30) are announced into
+other areas as Type-3 summary-LSA's, but any others (for example 10.11.0.0/16
+or 10.128.30.16/30) aren't.
+
+This command is only relevant if the router is an ABR for the specified
+area.
+@end deffn
+
+@deffn {OSPF Command} {area @var{a.b.c.d} import-list NAME} {}
+@deffnx {OSPF Command} {area <0-4294967295> import-list NAME} {}
+@deffnx {OSPF Command} {no area @var{a.b.c.d} import-list NAME} {}
+@deffnx {OSPF Command} {no area <0-4294967295> import-list NAME} {}
+Same as export-list, but it applies to paths announced into specified area as
+Type-3 summary-LSAs.
+@end deffn
+
+@deffn {OSPF Command} {area @var{a.b.c.d} filter-list prefix NAME in} {}
+@deffnx {OSPF Command} {area @var{a.b.c.d} filter-list prefix NAME out} {}
+@deffnx {OSPF Command} {area <0-4294967295> filter-list prefix NAME in} {}
+@deffnx {OSPF Command} {area <0-4294967295> filter-list prefix NAME out} {}
+@deffnx {OSPF Command} {no area @var{a.b.c.d} filter-list prefix NAME in} {}
+@deffnx {OSPF Command} {no area @var{a.b.c.d} filter-list prefix NAME out} {}
+@deffnx {OSPF Command} {no area <0-4294967295> filter-list prefix NAME in} {}
+@deffnx {OSPF Command} {no area <0-4294967295> filter-list prefix NAME out} {}
+Filtering Type-3 summary-LSAs to/from area using prefix lists. This command
+makes sense in ABR only.
+@end deffn
+
+@deffn {OSPF Command} {area @var{a.b.c.d} authentication} {}
+@deffnx {OSPF Command} {area <0-4294967295> authentication} {}
+@deffnx {OSPF Command} {no area @var{a.b.c.d} authentication} {}
+@deffnx {OSPF Command} {no area <0-4294967295> authentication} {}
+Specify that simple password authentication should be used for the given
+area.
+@end deffn
+
+@deffn {OSPF Command} {area @var{a.b.c.d} authentication message-digest} {}
+@deffnx {OSPF Command} {area <0-4294967295> authentication message-digest} {}
+
+@anchor{area authentication message-digest}Specify that OSPF packets
+must be authenticated with MD5 HMACs within the given area. Keying
+material must also be configured on a per-interface basis (@pxref{ip
+ospf message-digest-key}).
+
+MD5 authentication may also be configured on a per-interface basis
+(@pxref{ip ospf authentication message-digest}). Such per-interface
+settings will override any per-area authentication setting.
+@end deffn
+
+@node OSPF interface
+@section OSPF interface
+
+@deffn {Interface Command} {ip ospf area @var{AREA} [@var{ADDR}]} {} 
+@deffnx {Interface Command} {no ip ospf area [@var{ADDR}]} {}
+@anchor{OSPF ip ospf area command}
+
+Enable OSPF on the interface, optionally restricted to just the IP address
+given by @var{ADDR}, putting it in the @var{AREA} area. Per interface area
+settings take precedence to network commands (@pxref{OSPF network command}).
+
+If you have a lot of interfaces, and/or a lot of subnets, then enabling OSPF
+via this command may result in a slight performance improvement.
+
+@end deffn
+
+@deffn {Interface Command} {ip ospf authentication-key @var{AUTH_KEY}} {}
+@deffnx {Interface Command} {no ip ospf authentication-key} {}
+Set OSPF authentication key to a simple password.  After setting @var{AUTH_KEY},
+all OSPF packets are authenticated. @var{AUTH_KEY} has length up to 8 chars.
+
+Simple text password authentication is insecure and deprecated in favour of
+MD5 HMAC authentication (@pxref{ip ospf authentication message-digest}).
+@end deffn
+
+@deffn {Interface Command} {ip ospf authentication message-digest} {}
+@anchor{ip ospf authentication message-digest}Specify that MD5 HMAC
+authentication must be used on this interface. MD5 keying material must
+also be configured (@pxref{ip ospf message-digest-key}). Overrides any
+authentication enabled on a per-area basis (@pxref{area
+authentication message-digest}).
+
+Note that OSPF MD5 authentication requires that time never go backwards
+(correct time is NOT important, only that it never goes backwards), even
+across resets, if ospfd is to be able to promptly reestabish adjacencies
+with its neighbours after restarts/reboots. The host should have system
+time be set at boot from an external or non-volatile source (eg battery backed clock, NTP,
+etc.) or else the system clock should be periodically saved to non-volative
+storage and restored at boot if MD5 authentication is to be expected to work
+reliably.
+@end deffn
+
+@deffn {Interface Command} {ip ospf message-digest-key KEYID md5 KEY} {}
+@deffnx {Interface Command} {no ip ospf message-digest-key} {}
+@anchor{ip ospf message-digest-key}Set OSPF authentication key to a
+cryptographic password.  The cryptographic algorithm is MD5.  
+
+KEYID identifies secret key used to create the message digest. This ID
+is part of the protocol and must be consistent across routers on a
+link.
+
+KEY is the actual message digest key, of up to 16 chars (larger strings
+will be truncated), and is associated with the given KEYID.
+@end deffn
+
+@deffn {Interface Command} {ip ospf cost <1-65535>} {}
+@deffnx {Interface Command} {no ip ospf cost} {}
+Set link cost for the specified interface.  The cost value is set to router-LSA's
+metric field and used for SPF calculation.
+@end deffn
+
+@deffn {Interface Command} {ip ospf dead-interval <1-65535>} {}
+@deffnx {Interface Command} {ip ospf dead-interval minimal hello-multiplier <2-20>} {}
+@deffnx {Interface Command} {no ip ospf dead-interval} {}
+@anchor{ip ospf dead-interval minimal} Set number of seconds for
+RouterDeadInterval timer value used for Wait Timer and Inactivity
+Timer.  This value must be the same for all routers attached to a
+common network.  The default value is 40 seconds.
+
+If 'minimal' is specified instead, then the dead-interval is set to 1
+second and one must specify a hello-multiplier. The hello-multiplier
+specifies how many Hellos to send per second, from 2 (every 500ms) to
+20 (every 50ms). Thus one can have 1s convergence time for OSPF. If this form
+is specified, then the hello-interval advertised in Hello packets is set to
+0 and the hello-interval on received Hello packets is not checked, thus 
+the hello-multiplier need NOT be the same across multiple routers on a common
+link.
+@end deffn
+
+@deffn {Interface Command} {ip ospf hello-interval <1-65535>} {}
+@deffnx {Interface Command} {no ip ospf hello-interval} {}
+Set number of seconds for HelloInterval timer value.  Setting this value,
+Hello packet will be sent every timer value seconds on the specified interface.
+This value must be the same for all routers attached to a common network.
+The default value is 10 seconds.
+
+This command has no effect if @ref{ip ospf dead-interval minimal} is also 
+specified for the interface.
+@end deffn
+
+@deffn {Interface Command} {ip ospf network (broadcast|non-broadcast|point-to-multipoint|point-to-point)} {}
+@deffnx {Interface Command} {no ip ospf network} {}
+Set explicitly network type for specifed interface.
+@end deffn
+
+@deffn {Interface Command} {ip ospf priority <0-255>} {}
+@deffnx {Interface Command} {no ip ospf priority} {}
+Set RouterPriority integer value.  The router with the highest priority
+will be more eligible to become Designated Router.  Setting the value
+to 0, makes the router ineligible to become Designated Router. The
+default value is 1.
+@end deffn
+
+@deffn {Interface Command} {ip ospf retransmit-interval <1-65535>} {}
+@deffnx {Interface Command} {no ip ospf retransmit interval} {}
+Set number of seconds for RxmtInterval timer value.  This value is used
+when retransmitting Database Description and Link State Request packets.
+The default value is 5 seconds.
+@end deffn
+
+@deffn {Interface Command} {ip ospf transmit-delay} {}
+@deffnx {Interface Command} {no ip ospf transmit-delay} {}
+Set number of seconds for InfTransDelay value.  LSAs' age should be 
+incremented by this value when transmitting.
+The default value is 1 seconds.
+@end deffn
+
+@deffn {Interface Command} {ip ospf area (A.B.C.D|<0-4294967295>)} {}
+@deffnx {Interface Command} {no ip ospf area} {}
+Enable ospf on an interface and set associated area.
+@end deffn
+
+@node Redistribute routes to OSPF
+@section Redistribute routes to OSPF
+
+@deffn {OSPF Command} {redistribute (kernel|connected|static|rip|bgp)} {}
+@deffnx {OSPF Command} {redistribute (kernel|connected|static|rip|bgp) @var{route-map}} {}
+@deffnx {OSPF Command} {redistribute (kernel|connected|static|rip|bgp) metric-type (1|2)} {}
+@deffnx {OSPF Command} {redistribute (kernel|connected|static|rip|bgp) metric-type (1|2) route-map @var{word}} {}
+@deffnx {OSPF Command} {redistribute (kernel|connected|static|rip|bgp) metric <0-16777214>} {}
+@deffnx {OSPF Command} {redistribute (kernel|connected|static|rip|bgp) metric <0-16777214> route-map @var{word}} {}
+@deffnx {OSPF Command} {redistribute (kernel|connected|static|rip|bgp) metric-type (1|2) metric <0-16777214>} {}
+@deffnx {OSPF Command} {redistribute (kernel|connected|static|rip|bgp) metric-type (1|2) metric <0-16777214> route-map @var{word}} {}
+@deffnx {OSPF Command} {no redistribute (kernel|connected|static|rip|bgp)} {}
+@anchor{OSPF redistribute}Redistribute routes of the specified protocol
+or kind into OSPF, with the metric type and metric set if specified,
+filtering the routes using the given route-map if specified.
+Redistributed routes may also be filtered with distribute-lists, see
+@ref{ospf distribute-list}.
+
+Redistributed routes are distributed as into OSPF as Type-5 External
+LSAs into links to areas that accept external routes, Type-7 External LSAs
+for NSSA areas and are not redistributed at all into Stub areas, where
+external routes are not permitted.
+
+Note that for connected routes, one may instead use
+@dfn{passive-interface}, see @ref{OSPF passive-interface}.
+@end deffn
+
+@deffn {OSPF Command} {default-information originate} {}
+@deffnx {OSPF Command} {default-information originate metric <0-16777214>} {}
+@deffnx {OSPF Command} {default-information originate metric <0-16777214> metric-type (1|2)} {}
+@deffnx {OSPF Command} {default-information originate metric <0-16777214> metric-type (1|2) route-map @var{word}} {}
+@deffnx {OSPF Command} {default-information originate always} {}
+@deffnx {OSPF Command} {default-information originate always metric <0-16777214>} {}
+@deffnx {OSPF Command} {default-information originate always metric <0-16777214> metric-type (1|2)} {}
+@deffnx {OSPF Command} {default-information originate always metric <0-16777214> metric-type (1|2) route-map @var{word}} {}
+@deffnx {OSPF Command} {no default-information originate} {}
+Originate an AS-External (type-5) LSA describing a default route into
+all external-routing capable areas, of the specified metric and metric
+type. If the 'always' keyword is given then the default is always
+advertised, even when there is no default present in the routing table.
+@end deffn
+
+@deffn {OSPF Command} {distribute-list NAME out (kernel|connected|static|rip|ospf} {}
+@deffnx {OSPF Command} {no distribute-list NAME out (kernel|connected|static|rip|ospf} {}
+@anchor{ospf distribute-list}Apply the access-list filter, NAME, to
+redistributed routes of the given type before allowing the routes to
+redistributed into OSPF (@pxref{OSPF redistribute}).
+@end deffn
+
+@deffn {OSPF Command} {default-metric <0-16777214>} {}
+@deffnx {OSPF Command} {no default-metric} {}
+@end deffn
+
+@deffn {OSPF Command} {distance <1-255>} {}
+@deffnx {OSPF Command} {no distance <1-255>} {}
+@end deffn
+
+@deffn {OSPF Command} {distance ospf (intra-area|inter-area|external) <1-255>} {}
+@deffnx {OSPF Command} {no distance ospf} {}
+@end deffn
+
+@deffn {Command} {router zebra} {}
+@deffnx {Command} {no router zebra} {}
+@end deffn
+
+@node Showing OSPF information
+@section Showing OSPF information
+
+@deffn {Command} {show ip ospf} {}
+@anchor{show ip ospf}Show information on a variety of general OSPF and
+area state and configuration information.
+@end deffn
+
+@deffn {Command} {show ip ospf interface [INTERFACE]} {}
+Show state and configuration of OSPF the specified interface, or all
+interfaces if no interface is given.
+@end deffn
+
+@deffn {Command} {show ip ospf neighbor} {}
+@deffnx {Command} {show ip ospf neighbor INTERFACE} {}
+@deffnx {Command} {show ip ospf neighbor detail} {}
+@deffnx {Command} {show ip ospf neighbor INTERFACE detail} {}
+@end deffn
+
+@deffn {Command} {show ip ospf database} {}
+@end deffn
+
+@deffn {Command} {show ip ospf database (asbr-summary|external|network|router|summary)} {}
+@deffnx {Command} {show ip ospf database (asbr-summary|external|network|router|summary) @var{link-state-id}} {}
+@deffnx {Command} {show ip ospf database (asbr-summary|external|network|router|summary) @var{link-state-id} adv-router @var{adv-router}} {}
+@deffnx {Command} {show ip ospf database (asbr-summary|external|network|router|summary) adv-router @var{adv-router}} {}
+@deffnx {Command} {show ip ospf database (asbr-summary|external|network|router|summary) @var{link-state-id} self-originate} {}
+@deffnx {Command} {show ip ospf database (asbr-summary|external|network|router|summary) self-originate} {}
+@end deffn
+
+@deffn {Command} {show ip ospf database max-age} {}
+@end deffn
+
+@deffn {Command} {show ip ospf database self-originate} {}
+@end deffn
+
+@deffn {Command} {show ip ospf route} {}
+Show the OSPF routing table, as determined by the most recent SPF calculation.
+@end deffn
+
+@node Opaque LSA
+@section Opaque LSA
+
+@deffn {OSPF Command} {ospf opaque-lsa} {}
+@deffnx {OSPF Command} {capability opaque} {}
+@deffnx {OSPF Command} {no ospf opaque-lsa} {}
+@deffnx {OSPF Command} {no capability opaque} {}
+@command{ospfd} support Opaque LSA (RFC2370) as fondment for MPLS Traffic Engineering LSA. Prior to used MPLS TE, opaque-lsa must be enable in the configuration file. Alternate command could be "mpls-te on" (@ref{OSPF Traffic Engineering}).
+@end deffn
+
+@deffn {Command} {show ip ospf database (opaque-link|opaque-area|opaque-external)} {}
+@deffnx {Command} {show ip ospf database (opaque-link|opaque-area|opaque-external) @var{link-state-id}} {}
+@deffnx {Command} {show ip ospf database (opaque-link|opaque-area|opaque-external) @var{link-state-id} adv-router @var{adv-router}} {}
+@deffnx {Command} {show ip ospf database (opaque-link|opaque-area|opaque-external) adv-router @var{adv-router}} {}
+@deffnx {Command} {show ip ospf database (opaque-link|opaque-area|opaque-external) @var{link-state-id} self-originate} {}
+@deffnx {Command} {show ip ospf database (opaque-link|opaque-area|opaque-external) self-originate} {}
+Show Opaque LSA from the database.
+@end deffn
+
+@node OSPF Traffic Engineering
+@section Traffic Engineering
+
+@deffn {OSPF Command} {mpls-te on} {}
+@deffnx {OSPF Command} {no mpls-te} {}
+Enable Traffic Engineering LSA flooding.
+@end deffn
+
+@deffn {OSPF Command} {mpls-te router-address <A.B.C.D>} {}
+@deffnx {OSPF Command} {no mpls-te} {}
+Configure stable IP address for MPLS-TE. This IP address is then advertise in Opaque LSA Type-10 TLV=1 (TE)
+option 1 (Router-Address).
+@end deffn
+
+@deffn {OSPF Command} {mpls-te inter-as area <area-id>|as} {}
+@deffnx {OSPF Command} {no mpls-te inter-as} {}
+Enable RFC5392 suuport - Inter-AS TE v2 - to flood Traffic Engineering parameters of Inter-AS link.
+2 modes are supported: AREA and AS; LSA are flood in AREA <area-id> with Opaque Type-10,
+respectively in AS with Opaque Type-11. In all case, Opaque-LSA TLV=6.
+@end deffn
+
+@deffn {Command} {show ip ospf mpls-te interface} {}
+@deffnx {Command} {show ip ospf mpls-te interface @var{interface}} {}
+Show MPLS Traffic Engineering parameters for all or specified interface.
+@end deffn
+
+@deffn {Command} {show ip ospf mpls-te router} {}
+Show Traffic Engineering router parameters.
+@end deffn
+
+@node Router Information
+@section Router Information
+
+@deffn {OSPF Command} {router-info [as | area <A.B.C.D>]} {}
+@deffnx {OSPF Command} {no router-info} {}
+Enable Router Information (RFC4970) LSA advertisement with AS scope (default) or Area scope flooding
+when area is specified.
+@end deffn
+
+@deffn {OSPF Command} {pce address <A.B.C.D>} {}
+@deffnx {OSPF Command} {no pce address} {}
+@deffnx {OSPF Command} {pce domain as <0-65535>} {}
+@deffnx {OSPF Command} {no pce domain as <0-65535>} {}
+@deffnx {OSPF Command} {pce neighbor as <0-65535>} {}
+@deffnx {OSPF Command} {no pce neighbor as <0-65535>} {}
+@deffnx {OSPF Command} {pce flag BITPATTERN} {}
+@deffnx {OSPF Command} {no pce flag} {}
+@deffnx {OSPF Command} {pce scope BITPATTERN} {}
+@deffnx {OSPF Command} {no pce scope} {}
+The commands are conform to RFC 5088 and allow OSPF router announce Path Compuatation Elemenent (PCE) capabilities
+through the Router Information (RI) LSA. Router Information must be enable prior to this. The command set/unset
+respectively the PCE IP adress, Autonomous System (AS) numbers of controlled domains, neighbor ASs, flag and scope.
+For flag and scope, please refer to RFC5088 for the BITPATTERN recognition. Multiple 'pce neighbor' command could
+be specified in order to specify all PCE neighbours.
+@end deffn
+
+@deffn {Command} {show ip ospf router-info} {}
+Show Router Capabilities flag.
+@end deffn
+@deffn {Command} {show ip ospf router-info pce} {}
+Show Router Capabilities PCE parameters.
+@end deffn
+
+@node Debugging OSPF
+@section Debugging OSPF
+
+@deffn {Command} {debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all) (send|recv) [detail]} {}
+@deffnx {Command} {no debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all) (send|recv) [detail]} {}
+Dump Packet for debugging
+@end deffn
+
+@deffn {Command} {debug ospf ism} {}
+@deffnx {Command} {debug ospf ism (status|events|timers)} {}
+@deffnx {Command} {no debug ospf ism} {}
+@deffnx {Command} {no debug ospf ism (status|events|timers)} {}
+Show debug information of Interface State Machine
+@end deffn
+
+@deffn {Command} {debug ospf nsm} {}
+@deffnx {Command} {debug ospf nsm (status|events|timers)} {}
+@deffnx {Command} {no debug ospf nsm} {}
+@deffnx {Command} {no debug ospf nsm (status|events|timers)} {}
+Show debug information of Network State Machine
+@end deffn
+
+@deffn {Command} {debug ospf event} {}
+@deffnx {Command} {no debug ospf event} {}
+Show debug information of OSPF event
+@end deffn
+
+@deffn {Command} {debug ospf nssa} {}
+@deffnx {Command} {no debug ospf nssa} {}
+Show debug information about Not So Stub Area
+@end deffn
+
+@deffn {Command} {debug ospf lsa} {}
+@deffnx {Command} {debug ospf lsa (generate|flooding|refresh)} {}
+@deffnx {Command} {no debug ospf lsa} {}
+@deffnx {Command} {no debug ospf lsa (generate|flooding|refresh)} {}
+Show debug detail of Link State messages
+@end deffn
+
+@deffn {Command} {debug ospf te} {}
+@deffnx {Command} {no debug ospf te} {}
+Show debug information about Traffic Engineering LSA
+@end deffn
+
+@deffn {Command} {debug ospf zebra} {}
+@deffnx {Command} {debug ospf zebra (interface|redistribute)} {}
+@deffnx {Command} {no debug ospf zebra} {}
+@deffnx {Command} {no debug ospf zebra (interface|redistribute)} {}
+Show debug information of ZEBRA API
+@end deffn
+
+@deffn {Command} {show debugging ospf} {}
+@end deffn
+
+@node OSPF Configuration Examples
+@section OSPF Configuration Examples
+A simple example, with MD5 authentication enabled:
+
+@example
+@group
+!
+interface bge0
+ ip ospf authentication message-digest
+ ip ospf message-digest-key 1 md5 ABCDEFGHIJK
+!
+router ospf
+ network 192.168.0.0/16 area 0.0.0.1
+ area 0.0.0.1 authentication message-digest
+@end group
+@end example
+
+An @acronym{ABR} router, with MD5 authentication and performing summarisation
+of networks between the areas:
+
+@example
+@group
+!
+password ABCDEF
+log file /var/log/frr/ospfd.log
+service advanced-vty
+!
+interface eth0
+ ip ospf authentication message-digest
+ ip ospf message-digest-key 1 md5 ABCDEFGHIJK
+!
+interface ppp0
+!
+interface br0
+ ip ospf authentication message-digest
+ ip ospf message-digest-key 2 md5 XYZ12345
+!
+router ospf
+ ospf router-id 192.168.0.1
+ redistribute connected
+ passive interface ppp0
+ network 192.168.0.0/24 area 0.0.0.0
+ network 10.0.0.0/16 area 0.0.0.0
+ network 192.168.1.0/24 area 0.0.0.1
+ area 0.0.0.0 authentication message-digest
+ area 0.0.0.0 range 10.0.0.0/16
+ area 0.0.0.0 range 192.168.0.0/24
+ area 0.0.0.1 authentication message-digest
+ area 0.0.0.1 range 10.2.0.0/16
+!
+@end group
+@end example
+
+A Traffic Engineering configuration, with Inter-ASv2 support.
+
+ - First, the 'zebra.conf' part:
+
+@example
+@group
+hostname HOSTNAME
+password PASSWORD
+log file /var/log/zebra.log
+!
+interface eth0
+ ip address 198.168.1.1/24
+ 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
+ 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
+
+ - Then the 'ospfd.conf' itself:
+
+@example
+@group
+hostname HOSTNAME
+password PASSWORD
+log file /var/log/ospfd.log
+!
+!
+interface eth0
+ ip ospf hello-interval 60
+ ip ospf dead-interval 240
+!
+interface eth1
+ ip ospf hello-interval 60
+ ip ospf dead-interval 240
+!
+!
+router ospf
+ ospf router-id 192.168.1.1
+ network 192.168.0.0/16 area 1
+ ospf opaque-lsa
+  mpls-te
+  mpls-te router-address 192.168.1.1
+  mpls-te inter-as area 1
+!
+line vty
+@end group
+@end example
+
+A router information example with PCE advsertisement:
+
+@example
+@group
+!
+router ospf
+ ospf router-id 192.168.1.1
+ network 192.168.0.0/16 area 1
+ capability opaque
+  mpls-te
+  mpls-te router-address 192.168.1.1
+ router-info area 0.0.0.1
+  pce address 192.168.1.1
+  pce flag 0x80
+  pce domain as 65400
+  pce neighbor as 65500
+  pce neighbor as 65200
+  pce scope 0x80
+!
+@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
diff --git a/doc/routemap.texi b/doc/routemap.texi
new file mode 100644 (file)
index 0000000..3e683f4
--- /dev/null
@@ -0,0 +1,285 @@
+@node Route Map
+@chapter Route Map
+
+Route maps provide a means to both filter and/or apply actions to
+route, hence allowing policy to be applied to routes.
+
+@menu
+* Route Map Command::
+* Route Map Match Command::
+* Route Map Set Command::
+* Route Map Call Command::
+* Route Map Exit Action Command::
+* Route Map Examples::
+@end menu
+
+Route-maps are an ordered list of route-map entries. Each entry may
+specify up to four distincts sets of clauses:
+
+@table @samp
+@item Matching Policy
+
+This specifies the policy implied if the @samp{Matching Conditions} are
+met or not met, and which actions of the route-map are to be taken, if
+any. The two possibilities are:
+
+@itemize @minus
+@item
+@samp{permit}: If the entry matches, then carry out the @samp{Set
+Actions}. Then finish processing the route-map, permitting the route,
+unless an @samp{Exit Action} indicates otherwise.
+
+@item
+@samp{deny}: If the entry matches, then finish processing the route-map and
+deny the route (return @samp{deny}).
+@end itemize
+
+The @samp{Matching Policy} is specified as part of the command which
+defines the ordered entry in the route-map. See below.
+
+@item Matching Conditions
+
+A route-map entry may, optionally, specify one or more conditions which
+must be matched if the entry is to be considered further, as governed
+by the Match Policy. If a route-map entry does not explicitely specify
+any matching conditions, then it always matches.
+
+@item Set Actions
+
+A route-map entry may, optionally, specify one or more @samp{Set
+Actions} to set or modify attributes of the route.
+
+@item Call Action
+
+Call to another route-map, after any @samp{Set Actions} have been
+carried out. If the route-map called returns @samp{deny} then
+processing of the route-map finishes and the route is denied,
+regardless of the @samp{Matching Policy} or the @samp{Exit Policy}. If
+the called route-map returns @samp{permit}, then @samp{Matching Policy}
+and @samp{Exit Policy} govern further behaviour, as normal.
+
+@item Exit Policy
+
+An entry may, optionally, specify an alternative @samp{Exit Policy} to
+take if the entry matched, rather than the normal policy of exiting the
+route-map and permitting the route. The two possibilities are:
+
+@itemize @minus 
+@item
+@samp{next}: Continue on with processing of the route-map entries.
+
+@item
+@samp{goto N}: Jump ahead to the first route-map entry whose order in
+the route-map is >= N. Jumping to a previous entry is not permitted.
+@end itemize
+@end table
+
+The default action of a route-map, if no entries match, is to deny.
+I.e. a route-map essentially has as its last entry an empty @samp{deny}
+entry, which matches all routes. To change this behaviour, one must
+specify an empty @samp{permit} entry as the last entry in the route-map.
+
+To summarise the above:
+
+@multitable {permit} {action} {No Match}
+@headitem           @tab Match  @tab No Match
+@item @emph{Permit} @tab action @tab cont
+@item @emph{Deny}   @tab deny   @tab cont
+@end multitable
+
+@table @samp
+
+@item action
+@itemize @minus
+@item
+Apply @emph{set} statements
+
+@item
+If @emph{call} is present, call given route-map. If that returns a @samp{deny}, finish
+processing and return @samp{deny}.
+
+@item
+If @samp{Exit Policy} is @emph{next}, goto next route-map entry
+
+@item
+If @samp{Exit Policy} is @emph{goto}, goto first entry whose order in the list
+is >= the given order.
+
+@item
+Finish processing the route-map and permit the route.
+@end itemize
+
+@item deny
+@itemize @minus
+@item
+The route is denied by the route-map (return @samp{deny}).
+@end itemize
+
+@item cont
+@itemize @minus
+@item
+goto next route-map entry
+@end itemize
+@end table
+
+@node Route Map Command
+@section Route Map Command
+
+@deffn {Command} {route-map @var{route-map-name} (permit|deny) @var{order}} {}
+
+Configure the @var{order}'th entry in @var{route-map-name} with
+@samp{Match Policy} of either @emph{permit} or @emph{deny}.
+
+@end deffn
+
+@node Route Map Match Command
+@section Route Map Match Command
+
+@deffn {Route-map Command} {match ip address @var{access_list}} {}
+Matches the specified @var{access_list}
+@end deffn
+
+@deffn {Route-map Command} {match ip address @var{prefix-list}} {}
+Matches the specified @var{prefix-list}
+@end deffn
+
+@deffn {Route-map Command} {match ip address prefix-len @var{0-32}} {}
+Matches the specified @var{prefix-len}.  This is a Zebra specific command.
+@end deffn
+
+@deffn {Route-map Command} {match ipv6 address @var{access_list}} {}
+Matches the specified @var{access_list}
+@end deffn
+
+@deffn {Route-map Command} {match ipv6 address @var{prefix-list}} {}
+Matches the specified @var{prefix-list}
+@end deffn
+
+@deffn {Route-map Command} {match ipv6 address prefix-len @var{0-128}} {}
+Matches the specified @var{prefix-len}.  This is a Zebra specific command.
+@end deffn
+
+@deffn {Route-map Command} {match ip next-hop @var{ipv4_addr}} {}
+Matches the specified @var{ipv4_addr}.
+@end deffn
+
+@deffn {Route-map Command} {match aspath @var{as_path}} {}
+Matches the specified @var{as_path}.
+@end deffn
+
+@deffn {Route-map Command} {match metric @var{metric}} {}
+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
+
+@deffn {Route-map Command} {match community @var{community_list}} {}
+Matches the specified  @var{community_list}
+@end deffn
+
+@deffn {Route-map Command} {match peer @var{ipv4_addr}} {}
+This is a BGP specific match command.  Matches the peer ip address
+if the neighbor was specified in this manner.
+@end deffn
+
+@deffn {Route-map Command} {match peer @var{ipv6_addr}} {}
+This is a BGP specific match command.  Matches the peer ipv6
+address if the neighbor was specified in this manner.
+@end deffn
+
+@deffn {Route-map Command} {match peer @var{interface_name}} {}
+This is a BGP specific match command.  Matches the peer
+interface name specified if the neighbor was specified
+in this manner.
+@end deffn
+
+@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
+
+@deffn {Route-map Command} {set local-preference @var{local_pref}} {}
+Set the BGP local preference to @var{local_pref}. 
+@end deffn
+
+@deffn {Route-map Command} {set weight @var{weight}} {}
+Set the route's weight.
+@end deffn
+
+@deffn {Route-map Command} {set metric @var{metric}} {}
+@anchor{routemap set metric}
+Set the BGP attribute MED.
+@end deffn
+
+@deffn {Route-map Command} {set as-path prepend @var{as_path}} {}
+Set the BGP AS path to prepend.
+@end deffn
+
+@deffn {Route-map Command} {set community @var{community}} {}
+Set the BGP community attribute.
+@end deffn
+
+@deffn {Route-map Command} {set ipv6 next-hop global @var{ipv6_address}} {}
+Set the BGP-4+ global IPv6 nexthop address.
+@end deffn
+
+@deffn {Route-map Command} {set ipv6 next-hop local @var{ipv6_address}} {}
+Set the BGP-4+ link local IPv6 nexthop address.
+@end deffn
+
+@node Route Map Call Command
+@section Route Map Call Command
+
+@deffn {Route-map Command} {call @var{name}} {}
+Call route-map @var{name}. If it returns deny, deny the route and
+finish processing the route-map.
+@end deffn
+
+@node Route Map Exit Action Command
+@section Route Map Exit Action Command
+
+@deffn {Route-map Command} {on-match next} {}
+@deffnx {Route-map Command} {continue} {}
+Proceed on to the next entry in the route-map.
+@end deffn
+
+@deffn {Route-map Command} {on-match goto @var{N}} {}
+@deffnx {Route-map Command} {continue @var{N}} {}
+Proceed processing the route-map at the first entry whose order is >= N
+@end deffn
+
+@node Route Map Examples
+@section Route Map Examples
+
+A simple example of a route-map:
+
+@example
+@group
+route-map test permit 10
+ match ip address 10
+ set local-preference 200
+@end group
+@end example
+
+This means that if a route matches ip access-list number 10 it's
+local-preference value is set to 200.
+
+See @ref{BGP Configuration Examples} for examples of more sophisticated
+useage of route-maps, including of the @samp{call} action.
index 4ba69394b2cb53ec88d5ac1a47e21511a042ae65..06f124679f8963a7f206ff485f39b4de9fc19f5b 100644 (file)
@@ -871,33 +871,19 @@ 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 :rfc:`4364` and :rfc:`4659`, and
-Encapsulation information :rfc:`5512` is supported.
+Encapsulation attribute :rfc:`5512` is supported.
 
-.. index:: show ip bgp vpnv4 all
-.. clicmd:: show ip bgp vpnv4 all
+.. index:: show ip bgp ipv4 vpn
+.. clicmd:: show ip bgp ipv4 vpn
 
-.. index:: show ipv6 bgp vpn all
-.. clicmd:: show ipv6 bgp vpn all
+.. index:: show ipv6 bgp ipv6 vpn
+.. clicmd:: show ipv6 bgp ipv6 vpn
 
    Print active IPV4 or IPV6 routes advertised via the VPN SAFI.
 
-.. index:: show ip bgp encap all
-.. clicmd:: show ip bgp encap all
-
-.. index:: show ipv6 bgp encap all
-.. clicmd:: show ipv6 bgp encap all
-
-   Print active IPV4 or IPV6 routes advertised via the Encapsulation SAFI.
-
-.. index:: show bgp ipv4 encap summary
-.. clicmd:: show bgp ipv4 encap summary
-
 .. index:: show bgp ipv4 vpn summary
 .. clicmd:: show bgp ipv4 vpn summary
 
-.. index:: show bgp ipv6 encap summary
-.. clicmd:: show bgp ipv6 encap summary
-
 .. index:: show bgp ipv6 vpn summary
 .. clicmd:: show bgp ipv6 vpn summary
 
index b133b8c9201a9e858fc6bce33e1eaee11fc18ab2..7cd2153dc3e5eafbe0de2ee3902a9c42540d3e3f 100644 (file)
@@ -16,8 +16,8 @@ Both IP/Layer 3 (L3) VNs, and IP with Ethernet/Layer 2 (L2) VNs are supported.
 
 BGP, with IP VPNs and Tunnel Encapsulation, is used to distribute VN
 information between NVAs. BGP based IP VPN support is defined in :rfc:`4364`,
-and :rfc:`4659`. Both the Encapsulation Subsequent Address Family Identifier
-(SAFI) and the Tunnel Encapsulation Attribute, :rfc:`5512` are supported.
+and :rfc:`4659`. Encapsulation information is provided via the Tunnel
+Encapsulation Attribute, :rfc:`5512`.
 
 The protocol that is used to communicate routing and Ethernet / Layer 2 (L2)
 forwarding information between NVAs and NVEs is referred to as the Remote
@@ -40,30 +40,26 @@ following areas:
 
 - :dfn:`General VNC` configuration applies to general VNC operation and is
   primarily used to control the method used to advertise tunnel information.
-  - :dfn:`Remote Forwarder Protocol (RFP)` configuration relates to the protocol
-    used between NVAs and NVEs.
-    - :dfn:`VNC Defaults` provides default parameters for registered NVEs.
-      - :dfn:`VNC NVE Group` provides for configuration of a specific set of
-        registered NVEs and overrides default parameters.
-        - :dfn:`Redistribution` and :dfn:`Export` control VNC-GW operation, i.e., the
-          import/export of routing information between VNC and customer edge routers
-          (:abbr:`CE`s) operating within a VN.
 
+- :dfn:`Remote Forwarder Protocol (RFP)` configuration relates to the protocol
+  used between NVAs and NVEs.
 
-        .. _General_VNC_Configuration:
+- :dfn:`VNC Defaults` provides default parameters for registered NVEs.
 
-     General VNC Configuration
-     -------------------------
+- :dfn:`VNC NVE Group` provides for configuration of a specific set of
+  registered NVEs and overrides default parameters.
 
-     .. clicmd:: vnc advertise-un-method encap-safi|encap-attr
+- :dfn:`Redistribution` and :dfn:`Export` control VNC-GW operation, i.e., the
+  import/export of routing information between VNC and customer edge routers
+  (:abbr:`CE` s) operating within a VN.
 
-  Advertise NVE underlay-network IP addresses using the encapsulation SAFI
-  (`encap-safi`) or the UN address sub-TLV of the Tunnel Encapsulation
-  attribute (`encap-attr`). When `encap-safi` is used, neighbors under
-  `address-family encap` and/or `address-family encapv6` must be configured.
-  The default is `encap-attr`.
 
-  .. _RFP_Related_Configuration:
+.. _General_VNC_Configuration:
+
+.. General VNC Configuration
+.. -------------------------
+
+.. _RFP_Related_Configuration:
 
 RFP Related Configuration
 -------------------------
@@ -96,9 +92,9 @@ Enter VNC configuration mode for specifying VNC default behaviors. Use
 
 ::
 
-vnc defaults
-... various VNC defaults
-exit-vnc
+   vnc defaults
+   ... various VNC defaults
+   exit-vnc
 
 
 These are the statements that can appear between ``vnc defaults`` and
@@ -118,43 +114,42 @@ These are the statements that can appear between ``vnc defaults`` and
    in one of the following forms:
 
    - ``IPv4-address:two-byte-integer``
-     - ``four-byte-autonomous-system-number:two-byte-integer``
-       - ``two-byte-autonomous-system-number:four-byte-integer``
+   - ``four-byte-autonomous-system-number:two-byte-integer``
+   - ``two-byte-autonomous-system-number:four-byte-integer``
 
-       If no default import RT list is specified, then the default import RT list
-       is empty. If no default export RT list is specified, then the default export
-       RT list is empty.
+   If no default import RT list is specified, then the default import RT list
+   is empty. If no default export RT list is specified, then the default export
+   RT list is empty.
 
-       A complete definition of these parameters is given below
-       (:ref:`VNC_NVE_Group_Configuration`).
+   A complete definition of these parameters is given below
+   (:ref:`VNC_NVE_Group_Configuration`).
 
-       .. index:: rd route-distinguisher
-       .. clicmd:: rd ROUTE-DISTINGUISHER
+.. index:: rd route-distinguisher
+.. clicmd:: rd ROUTE-DISTINGUISHER
 
    Specify the default route distinguisher (RD) for routes advertised via BGP
    VPNs. The route distinguisher must be in one of four forms:
 
     - ``IPv4-address:two-byte-integer``
-      - ``four-byte-autonomous-system-number:two-byte-integer``
-        - ``two-byte-autonomous-system-number:four-byte-integer``
-          - ``auto:vn:two-byte-integer``
+    - ``four-byte-autonomous-system-number:two-byte-integer``
+    - ``two-byte-autonomous-system-number:four-byte-integer``
+    - ``auto:vn:two-byte-integer``
 
-          If RD is specified in the defaults section, the default RD value is
-          `two-byte-autonomous-system-number=0`:`four-byte-integer=0`.
+    If RD is specified in the defaults section, the default RD value is
+    `two-byte-autonomous-system-number=0:four-byte-integer=0`.
 
-          A complete definition of this parameter is given below
-          (:ref:`VNC_NVE_Group_Configuration`).
+    A complete definition of this parameter is given below
+    (:ref:`VNC_NVE_Group_Configuration`).
 
-          .. index:: l2rd NVE-ID-VALUE
-
-       .. clicmd:: l2rd NVE-ID-VALUE
+.. index:: l2rd NVE-ID-VALUE
+.. clicmd:: l2rd NVE-ID-VALUE
 
    Set the value used to distinguish NVEs connected to the same logical
    Ethernet segment (i.e., L2VPN).  A complete definition of this parameter is
    given below (:ref:`VNC_NVE_Group_Configuration`).
 
-   .. index:: response-lifetime LIFETIME|infinite
-   .. clicmd:: response-lifetime LIFETIME|infinite
+.. index:: response-lifetime LIFETIME|infinite
+.. clicmd:: response-lifetime LIFETIME|infinite
 
    Specify the default lifetime to be included in RFP response messages sent to
    NVEs.
@@ -163,25 +158,23 @@ These are the statements that can appear between ``vnc defaults`` and
    (:ref:`VNC_NVE_Group_Configuration`).
 
 .. index:: export bgp|zebra route-map MAP-NAME
-
 .. clicmd:: export bgp|zebra route-map MAP-NAME
 
-Specify that the named route-map should be applied to routes being exported
-to bgp or zebra.
+   Specify that the named route-map should be applied to routes being exported
+   to bgp or zebra.
 
 .. index:: export bgp|zebra no route-map
-
 .. clicmd:: export bgp|zebra no route-map
 
-Specify that no route-map should be applied to routes being exported to bgp
-or zebra.
+   Specify that no route-map should be applied to routes being exported to bgp
+   or zebra.
 
 .. index:: exit-vnc
 .. clicmd:: exit-vnc
 
    Exit VNC configuration mode.
 
-   .. _VNC_NVE_Group_Configuration:
+.. _VNC_NVE_Group_Configuration:
 
 VNC NVE Group Configuration
 ---------------------------
@@ -210,9 +203,9 @@ Defaults section.
 
   ::
 
-  vnc nve-group group1
-  ... configuration commands
-  exit-vnc
+     vnc nve-group group1
+     ... configuration commands
+     exit-vnc
 
 
 .. index:: no vnc nve-group NAME
@@ -222,73 +215,73 @@ Defaults section.
 
    The following statements are valid in an NVE group definition:
 
-   .. index:: l2rd NVE-ID-VALUE
-   .. clicmd:: l2rd NVE-ID-VALUE
+.. index:: l2rd NVE-ID-VALUE
+.. clicmd:: l2rd NVE-ID-VALUE
 
-Set the value used to distinguish NVEs connected to the same physical
-Ethernet segment (i.e., at the same location) [#]_.
+   Set the value used to distinguish NVEs connected to the same physical
+   Ethernet segment (i.e., at the same location) [#]_.
 
-The nve-id subfield may be specified as either a literal value in the range
-1-255, or it may be specified as `auto:vn`, which means to use the
-least-significant octet of the originating NVE's VN address.
+   The nve-id subfield may be specified as either a literal value in the range
+   1-255, or it may be specified as `auto:vn`, which means to use the
+   least-significant octet of the originating NVE's VN address.
 
 .. index:: prefix vn|un A.B.C.D/M|X:X::X:X/M
 .. clicmd:: prefix vn|un A.B.C.D/M|X:X::X:X/M
 
-  Specify the matching prefix for this NVE group by either virtual-network
-  address (`vn`) or underlay-network address (`un`). Either or both
-  virtual-network and underlay-network prefixes may be specified. Subsequent
-  virtual-network or underlay-network values within a `vnc nve-group`
-  `exit-vnc` block override their respective previous values.
+   Specify the matching prefix for this NVE group by either virtual-network
+   address (`vn`) or underlay-network address (`un`). Either or both
+   virtual-network and underlay-network prefixes may be specified. Subsequent
+   virtual-network or underlay-network values within a `vnc nve-group`
+   `exit-vnc` block override their respective previous values.
 
-  These prefixes are used only for determining assignments of NVEs to NVE
-  Groups.
+   These prefixes are used only for determining assignments of NVEs to NVE
+   Groups.
 
-  .. index:: rd ROUTE-DISTINGUISHER
-  .. clicmd:: rd ROUTE-DISTINGUISHER
+.. index:: rd ROUTE-DISTINGUISHER
+.. clicmd:: rd ROUTE-DISTINGUISHER
 
    Specify the route distinguisher for routes advertised via BGP
    VPNs. The route distinguisher must be in one of these forms:
 
    - ``IPv4-address:two-byte-integer``
-     - ``four-byte-autonomous-system-number:two-byte-integer``
-       - ``two-byte-autonomous-system-number:four-byte-integer``
-         - ``auto:vn:`two-byte-integer`
-
-         Routes originated by NVEs in the NVE group will use the group's specified
-         `route-distinguisher` when they are advertised via BGP.  If the `auto` form
-         is specified, it means that a matching NVE has its RD set to
-         ``rd_type=IP=1:IPv4-address=VN-address:two-byte-integer``, for IPv4 VN
-         addresses and
-         ``rd_type=IP=1`:`IPv4-address=Last-four-bytes-of-VN-address:two-byte-integer``,
-         for IPv6 VN addresses.
+   - ``four-byte-autonomous-system-number:two-byte-integer``
+   - ``two-byte-autonomous-system-number:four-byte-integer``
+   - ``auto:vn:`two-byte-integer`
+
+   Routes originated by NVEs in the NVE group will use the group's specified
+   `route-distinguisher` when they are advertised via BGP.  If the `auto` form
+   is specified, it means that a matching NVE has its RD set to
+   ``rd_type=IP=1:IPv4-address=VN-address:two-byte-integer``, for IPv4 VN
+   addresses and
+   ``rd_type=IP=1:IPv4-address=Last-four-bytes-of-VN-address:two-byte-integer``,
+   for IPv6 VN addresses.
+
+   If the NVE group definition does not specify a `route-distinguisher`, then
+   the default `route-distinguisher` is used.  If neither a group nor a default
+   `route-distinguisher` is configured, then the advertised RD is set to
+   ``two-byte-autonomous-system-number=0:four-byte-integer=0``.
+
+.. index:: response-lifetime LIFETIME|infinite
+.. clicmd:: response-lifetime LIFETIME|infinite
+
+   Specify the response lifetime, in seconds, to be included in RFP response
+   messages sent to NVEs. If the value 'infinite' is given, an infinite
+   lifetime will be used.
+
+   Note that this parameter is not the same as the lifetime supplied by NVEs in
+   RFP registration messages. This parameter does not affect the lifetime value
+   attached to routes sent by this server via BGP.
+
+   If the NVE group definition does not specify a `response-lifetime`, the
+   default `response-lifetime` will be used.  If neither a group nor a default
+   `response-lifetime` is configured, the value 3600 will be used. The maximum
+   response lifetime is 2147483647.
 
-         If the NVE group definition does not specify a `route-distinguisher`, then
-         the default `route-distinguisher` is used.  If neither a group nor a default
-         `route-distinguisher` is configured, then the advertised RD is set to
-         ``two-byte-autonomous-system-number=0:four-byte-integer=0``.
-
-         .. index:: response-lifetime LIFETIME|infinite
-         .. clicmd:: response-lifetime LIFETIME|infinite
-
-      Specify the response lifetime, in seconds, to be included in RFP response
-      messages sent to NVEs. If the value 'infinite' is given, an infinite
-      lifetime will be used.
-
-      Note that this parameter is not the same as the lifetime supplied by NVEs in
-      RFP registration messages. This parameter does not affect the lifetime value
-      attached to routes sent by this server via BGP.
-
-      If the NVE group definition does not specify a `response-lifetime`, the
-      default `response-lifetime` will be used.  If neither a group nor a default
-      `response-lifetime` is configured, the value 3600 will be used. The maximum
-      response lifetime is 2147483647.
-
-      .. index:: rt export RT-LIST
-      .. clicmd:: rt export RT-LIST
+.. index:: rt export RT-LIST
+.. clicmd:: rt export RT-LIST
 
-   .. index:: rt import RT-LIST
-   .. clicmd:: rt import RT-LIST
+.. index:: rt import RT-LIST
+.. clicmd:: rt import RT-LIST
 
 .. index:: rt both RT-LIST
 .. clicmd:: rt both RT-LIST
@@ -297,9 +290,9 @@ least-significant octet of the originating NVE's VN address.
    space-separated list of route targets, each element of which is
    in one of the following forms:
 
-   ``IPv4-address:two-byte-integer``
-   ``four-byte-autonomous-system-number:two-byte-integer``
-   ``two-byte-autonomous-system-number:four-byte-integer``
+   ``IPv4-address:two-byte-integer``
+   ``four-byte-autonomous-system-number:two-byte-integer``
+   ``two-byte-autonomous-system-number:four-byte-integer``
 
    The first form, `rt export`, specifies an `export rt-list`.  The `export
    rt-list` will be attached to routes originated by NVEs in the NVE group
@@ -311,8 +304,7 @@ least-significant octet of the originating NVE's VN address.
 
    The second form, `rt import` specifies an `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 `ENCAP` `SAFI` (when `vnc advertise-un-method
-   encap-safi` is set) routes must have RT lists that have at least one
+   group, incoming BGP VPN routes must have RT lists that have at least one
    route target in common with the group's `import rt-list`.
 
    If the NVE group definition does not specify an import filter, then the
@@ -560,7 +552,6 @@ Redistribution Command Syntax
 .. index:: no vnc redistribute ipv4|ipv6 bgp|bgp-direct|bgp-direct-to-nve-groups|connected|kernel|ospf|rip|static
 .. clicmd:: no vnc redistribute ipv4|ipv6 bgp|bgp-direct|bgp-direct-to-nve-groups|connected|kernel|ospf|rip|static
 
-
    Import (or do not import) prefixes from another routing protocols. Specify
    both the address family to import (`ipv4` or `ipv6`) and the protocol
    (`bgp`, `bgp-direct`, `bgp-direct-to-nve-groups`, `connected`, `kernel`,
@@ -573,7 +564,6 @@ Redistribution Command Syntax
 .. index:: vnc redistribute mode plain|nve-group|resolve-nve
 .. clicmd:: vnc redistribute mode plain|nve-group|resolve-nve
 
-
    Redistribute routes from other protocols into VNC using the specified mode.
    Not all combinations of modes and protocols are supported.
 
@@ -583,7 +573,6 @@ Redistribution Command Syntax
 .. index:: no vnc redistribute nve-group GROUP-NAME
 .. clicmd:: no vnc redistribute nve-group GROUP-NAME
 
-
    When using `nve-group` mode, assign (or do not assign) the NVE group
    `group-name` to routes redistributed from another routing protocol.
    `group-name` must be configured using `vnc nve-group`.
@@ -595,7 +584,6 @@ Redistribution Command Syntax
 .. index:: vnc redistribute lifetime LIFETIME|infinite
 .. clicmd:: vnc redistribute lifetime LIFETIME|infinite
 
-
    Assign a registration lifetime, either `lifetime` seconds or `infinite`, to
    prefixes redistributed from other routing protocols as if they had been
    received via RFP registration messages from an NVE. `lifetime` can be any
@@ -604,7 +592,6 @@ Redistribution Command Syntax
 .. index:: vnc redistribute resolve-nve roo-ec-local-admin 0-65536
 .. clicmd:: vnc redistribute resolve-nve roo-ec-local-admin 0-65536
 
-
    Assign a value to the local-administrator subfield used in the
    Route Origin extended community that is assigned to routes exported
    under the `resolve-nve` mode. The default value is `5226`.
@@ -657,7 +644,6 @@ a corresponding `redistribute vnc-direct` statement.
 .. index:: export bgp|zebra mode none|group-nve|registering-nve|ce
 .. clicmd:: export bgp|zebra mode none|group-nve|registering-nve|ce
 
-
    Specify how routes should be exported to bgp or zebra.  If the mode is
    `none`, routes are not exported.  If the mode is `group-nve`, routes are
    exported according to nve-group or vrf-policy group configuration
@@ -671,7 +657,7 @@ a corresponding `redistribute vnc-direct` statement.
    The next hop of the exported route is set to the encoded NVE connected CE
    Router.
 
-  The default for both bgp and zebra is mode `none`.
+   The default for both bgp and zebra is mode `none`.
 
 .. index:: vnc export bgp|zebra group-nve group GROUP-NAME
 .. clicmd:: vnc export bgp|zebra group-nve group GROUP-NAME
@@ -697,14 +683,13 @@ a corresponding `redistribute vnc-direct` statement.
 .. index:: export bgp|zebra no ipv4|ipv6 prefix-list
 .. clicmd:: export bgp|zebra no ipv4|ipv6 prefix-list
 
-    When export mode is `ce` or `registering-nve`,
-    specifies that no prefix-list should be applied to routes
-    being exported to bgp or zebra.
+   When export mode is `ce` or `registering-nve`,
+   specifies that no prefix-list should be applied to routes
+   being exported to bgp or zebra.
 
 .. index:: export bgp|zebra route-map MAP-NAME
 .. clicmd:: export bgp|zebra route-map MAP-NAME
 
-
    When export mode is `ce` or `registering-nve`, specifies that the named
    route-map should be applied to routes being exported to bgp or zebra.
 
@@ -903,7 +888,6 @@ related information:
 .. index:: show memory vnc
 .. clicmd:: show memory vnc
 
-
    Print the number of memory items allocated by the NVA.
 
 .. _Example_VNC_and_VNC-GW_Configurations:
@@ -911,6 +895,606 @@ related information:
 Example VNC and VNC-GW Configurations
 =====================================
 
+.. _vnc-mesh-nva-config:
+
+Mesh NVA Configuration
+----------------------
+
+This example includes three NVAs, nine NVEs, and two NVE groups. Note that
+while not shown, a single physical device may support multiple logical NVEs.
+:figure:`fig-vnc-mesh` shows ``code NVA-1`` (192.168.1.100), ``NVA 2``
+(192.168.1.101), and ``NVA 3`` (192.168.1.102), which are connected in a full
+mesh. Each is a member of the autonomous system 64512. Each NVA provides VNC
+services to three NVE clients in the 172.16.0.0/16 virtual-network address
+range. The 172.16.0.0/16 address range is partitioned into two NVE groups,
+``group1`` (172.16.0.0/17) and ``group2`` (172.16.128.0/17).
+
+Each NVE belongs to either NVE group ``group1`` or NVE group
+``group2``.  The NVEs ``NVE 1``, ``NVE 2``, @code{NVE
+4}, ``NVE 7``, and ``NVE 8`` are members of the NVE group
+``group1``.  The NVEs ``NVE 3``, ``NVE 5``, @code{NVE
+6}, and ``NVE 9`` are members of the NVE group ``group2``.
+
+Each NVA advertises NVE underlay-network IP addresses using the
+Tunnel Encapsulation Attribute.
+
+.. _vnc-fig-vnc-mesh:
+.. figure:: ../figure/fig-vnc-mesh.png
+   :align: center
+   :alt: Three-way Mesh
+
+   A three-way full mesh with three NVEs per NVA.
+
+:file:`bgpd.conf` for ``NVA 1`` (192.168.1.100):::
+
+   router bgp 64512
+
+       bgp router-id 192.168.1.100
+
+       neighbor 192.168.1.101  remote-as 64512
+       neighbor 192.168.1.102  remote-as 64512
+
+       address-family ipv4 vpn
+           neighbor 192.168.1.101 activate
+           neighbor 192.168.1.102 activate
+       exit-address-family
+
+       vnc defaults
+           rd 64512:1
+           response-lifetime 200
+           rt both 1000:1 1000:2
+       exit-vnc
+
+       vnc nve-group group1
+           prefix vn 172.16.0.0/17
+           rt both 1000:1
+       exit-vnc
+
+       vnc nve-group group2
+           prefix vn 172.16.128.0/17
+           rt both 1000:2
+       exit-vnc
+
+   exit
+
+:file:`bgpd.conf` for ``NVA 2`` (192.168.1.101):::
+
+   router bgp 64512
+
+       bgp router-id 192.168.1.101
+
+       neighbor 192.168.1.100  remote-as 64512
+       neighbor 192.168.1.102  remote-as 64512
+
+       address-family ipv4 vpn
+           neighbor 192.168.1.100 activate
+           neighbor 192.168.1.102 activate
+       exit-address-family
+
+       vnc nve-group group1
+           prefix vn 172.16.0.0/17
+           rd 64512:1
+           response-lifetime 200
+           rt both 1000:1 1000:2
+       exit-vnc
+   exit
+
+:file:`bgpd.conf` for ``NVA 3`` (192.168.1.102):::
+
+   router bgp 64512
+
+       bgp router-id 192.168.1.102
+
+       neighbor 192.168.1.101  remote-as 64512
+       neighbor 192.168.1.102  remote-as 64512
+
+       address-family ipv4 vpn
+           neighbor 192.168.1.100 activate
+           neighbor 192.168.1.101 activate
+       exit-address-family
+
+       vnc defaults
+           rd 64512:1
+           response-lifetime 200
+           rt both 1000:1 1000:2
+       exit-vnc
+
+       vnc nve-group group1
+           prefix vn 172.16.128.0/17
+       exit-vnc
+   exit
+
+
+Mesh NVA and VNC-GW Configuration
+---------------------------------
+
+This example includes two NVAs, each with two associated NVEs, and two VNC-GWs,
+each supporting two CE routers physically attached to the four NVEs. Note that
+this example is showing a more complex configuration where VNC-GW is separated
+from normal NVA functions; it is equally possible to simplify the configuration
+and combine NVA and VNC-GW functions in a single FRR instance.
+
+.. _vnc-fig-vnc-gw:
+.. figure:: ../figures/fig-vnc-gw.png
+   :align: center
+   :alt: FRR VNC Gateway
+
+   Meshed NVEs and VNC-GWs
+
+As shown in :figure:`fig-vnc-gw`, NVAs and VNC-GWs are connected in a full iBGP
+mesh. The VNC-GWs each have two CEs configured as route-reflector clients.
+Each client provides BGP updates with unicast routes that the VNC-GW reflects
+to the other client. The VNC-GW also imports these unicast routes into VPN
+routes to be shared with the other VNC-GW and the two NVAs. This route
+importation is controlled with the ``vnc redistribute`` statements shown in the
+configuration. Similarly, registrations sent by NVEs via RFP to the NVAs are
+exported by the VNC-GWs to the route-reflector clients as unicast routes. RFP
+registrations exported this way have a next-hop address of the CE behind the
+connected (registering) NVE. Exporting VNC routes as IPv4 unicast is enabled
+with the ``vnc export`` command below.
+
+The configuration for ``VNC-GW 1`` is shown below.::
+
+   router bgp 64512
+    bgp router-id 192.168.1.101
+    bgp cluster-id 1.2.3.4
+    neighbor 192.168.1.102 remote-as 64512
+    neighbor 192.168.1.103 remote-as 64512
+    neighbor 192.168.1.104 remote-as 64512
+    neighbor 172.16.1.2 remote-as 64512
+    neighbor 172.16.2.2 remote-as 64512
+    !
+    address-family ipv4 unicast
+     redistribute vnc-direct
+     no neighbor 192.168.1.102 activate
+     no neighbor 192.168.1.103 activate
+     no neighbor 192.168.1.104 activate
+     neighbor 172.16.1.2 route-reflector-client
+     neighbor 172.16.2.2 route-reflector-client
+    exit-address-family
+    !
+    address-family ipv4 vpn
+      neighbor 192.168.1.102 activate
+      neighbor 192.168.1.103 activate
+      neighbor 192.168.1.104 activate
+    exit-address-family
+    vnc export bgp mode ce
+    vnc redistribute mode resolve-nve
+    vnc redistribute ipv4 bgp-direct
+    exit
+
+Note that in the VNC-GW configuration, the neighboring VNC-GW and NVAs each
+have a statement disabling the IPv4 unicast address family. IPv4 unicast is on
+by default and this prevents the other VNC-GW and NVAs from learning unicast
+routes advertised by the route-reflector clients.
+
+Configuration for ``NVA 2``:::
+
+   router bgp 64512
+    bgp router-id 192.168.1.104
+    neighbor 192.168.1.101 remote-as 64512
+    neighbor 192.168.1.102 remote-as 64512
+    neighbor 192.168.1.103 remote-as 64512
+    !
+    address-family ipv4 unicast
+     no neighbor 192.168.1.101 activate
+     no neighbor 192.168.1.102 activate
+     no neighbor 192.168.1.103 activate
+    exit-address-family
+    !
+    address-family ipv4 vpn
+      neighbor 192.168.1.101 activate
+      neighbor 192.168.1.102 activate
+      neighbor 192.168.1.103 activate
+    exit-address-family
+    !
+    vnc defaults
+     response-lifetime 3600
+     exit-vnc
+    vnc nve-group nve1
+     prefix vn 172.16.1.1/32
+     response-lifetime 3600
+     rt both 1000:1 1000:2
+     exit-vnc
+    vnc nve-group nve2
+     prefix vn 172.16.2.1/32
+     response-lifetime 3600
+     rt both 1000:1 1000:2
+     exit-vnc
+    exit
+
+.. TBD make this its own example:
+..
+.. @float Figure,fig:fig-vnc-gw-rr
+.. @center @image{fig-vnc-gw-rr,400pt,,Frr VNC Gateway with RR}
+.. @end float
+.. An NVA can also import unicast routes from BGP without advertising the
+.. imported routes as VPN routes.  Such imported routes, while not
+.. distributed to other NVAs or VNC-GWs, are are available to NVEs via
+.. RFP query messages sent to the NVA. @ref{fig:fig-vnc-gw-rr}
+.. shows an example topology where unicast routes are imported into NVAs
+.. from a Route Reflector.  (@pxref{Route Reflector} for route reflector
+.. configuration details.)  The following three lines can be added to the
+.. ``NVA 1`` and ``NVA 2`` configurations to import routes into VNC
+.. for local VNC use:
+..
+.. @verbatim
+..  neighbor 192.168.1.105 remote-as 64512
+..  vnc redistribute mode plain
+..  vnc redistribute ipv4 bgp-direct-to-nve-groups
+.. @end verbatim
+
+.. _vnc-with-frr-route-reflector-config:
+
+VNC with FRR Route Reflector Configuration
+------------------------------------------
+
+A route reflector eliminates the need for a fully meshed NVA network by acting
+as the hub between NVAs. :figure:`vnc-fig-vnc-frr-route-reflector` shows BGP
+route reflector ``BGP Route Reflector 1`` (192.168.1.100) as a route reflector
+for NVAs ``NVA 2``(192.168.1.101) and ``NVA 3`` (192.168.1.102).
+
+@float Figure,fig:fig-vnc-frr-route-reflector @center
+@image{fig-vnc-frr-route-reflector,400pt,,Frr Route Reflector} @caption{Two
+NVAs and a BGP Route Reflector} @end float
+
+.. _vnc-fig-vnc-frr-route-reflector:
+.. figure:: ../figures/fig-vnc-frr-route-reflector.png
+   :align: center
+   :alt: FRR Route Reflector
+
+   Two NVAs and a BGP Route Reflector
+
+``NVA 2`` and ``NVA 3`` advertise NVE underlay-network IP addresses using the
+Tunnel Encapsulation Attribute. ``BGP Route Reflector 1`` ``reflects''
+advertisements from ``NVA 2`` to ``NVA 3`` and vice versa.
+
+As in the example of :ref:`vnc-mesh-nva-config`, there are two NVE groups.  The
+172.16.0.0/16 address range is partitioned into two NVE groups, ``group1``
+(172.16.0.0/17) and ``group2`` (172.16.128.0/17).  The NVE ``NVE 4``, ``NVE
+7``, and ``NVE 8`` are members of the NVE group ``group1``.  The NVEs ``NVE
+5``, ``NVE 6``, and ``NVE 9`` are members of the NVE group ``group2``.
+
+:file:`bgpd.conf` for ``BGP Route Reflector 1`` on 192.168.1.100:::
+
+   router bgp 64512
+
+       bgp router-id 192.168.1.100
+
+       neighbor 192.168.1.101 remote-as 64512
+       neighbor 192.168.1.101 port 7179
+       neighbor 192.168.1.101 description iBGP-client-192-168-1-101
+
+       neighbor 192.168.1.102 remote-as 64512
+       neighbor 192.168.1.102 port 7179
+       neighbor 192.168.1.102 description iBGP-client-192-168-1-102
+
+       address-family ipv4 unicast
+           neighbor 192.168.1.101 route-reflector-client
+           neighbor 192.168.1.102 route-reflector-client
+       exit-address-family
+
+       address-family ipv4 vpn
+           neighbor 192.168.1.101 activate
+           neighbor 192.168.1.102 activate
+
+           neighbor 192.168.1.101 route-reflector-client
+           neighbor 192.168.1.102 route-reflector-client
+       exit-address-family
+
+   exit
+
+:file:`bgpd.conf` for ``NVA 2`` on 192.168.1.101:::
+
+   router bgp 64512
+
+       bgp router-id 192.168.1.101
+
+       neighbor 192.168.1.100  remote-as 64512
+
+       address-family ipv4 vpn
+           neighbor 192.168.1.100 activate
+       exit-address-family
+
+       vnc nve-group group1
+           prefix vn 172.16.0.0/17
+           rd 64512:1
+           response-lifetime 200
+           rt both 1000:1 1000:2
+       exit-vnc
+   exit
+
+:file:`bgpd.conf` for ``NVA 2`` on 192.168.1.102:::
+
+  router bgp 64512
+
+      bgp router-id 192.168.1.102
+
+      neighbor 192.168.1.100  remote-as 64512
+
+      address-family ipv4 vpn
+          neighbor 192.168.1.100 activate
+      exit-address-family
+
+      vnc defaults
+          rd 64512:1
+          response-lifetime 200
+          rt both 1000:1 1000:2
+      exit-vnc
+
+      vnc nve-group group1
+          prefix vn 172.16.128.0/17
+      exit-vnc
+  exit
+
+While not shown, an NVA can also be configured as a route reflector.
+
+.. _vnc-with-commercial-route-reflector-config:
+
+VNC with Commercial Route Reflector Configuration
+-------------------------------------------------
+
+This example is identical to :ref:`vnc-with-frr-route-reflector-configuration`
+with the exception that the route reflector is a commercial router. Only the
+VNC-relevant configuration is provided.
+
+.. figure:: ../figures/fig-vnc-commercial-route-reflector
+   :align: center
+   :alt: Commercial Route Reflector
+
+   Two NVAs with a commercial route reflector
+
+:file:`bgpd.conf` for BGP route reflector ``Commercial Router`` on 192.168.1.104:::
+
+   version 8.5R1.13;
+   routing-options {
+       rib inet.0 {
+           static {
+               route 172.16.0.0/16 next-hop 192.168.1.104;
+           }
+       }
+       autonomous-system 64512;
+       resolution {
+           rib inet.3 {
+               resolution-ribs inet.0;
+           }
+           rib bgp.l3vpn.0 {
+               resolution-ribs inet.0;
+           }
+       }
+   }
+   protocols {
+       bgp {
+           advertise-inactive;
+           family inet {
+               labeled-unicast;
+           }
+          group 1 {
+               type internal;
+               advertise-inactive;
+               advertise-peer-as;
+               import h;
+               family inet {
+                   unicast;
+               }
+               family inet-vpn {
+                   unicast;
+               }
+               cluster 192.168.1.104;
+               neighbor 192.168.1.101;
+               neighbor 192.168.1.102;
+           }
+       }
+   }
+   policy-options {
+       policy-statement h {
+           from protocol bgp;
+           then {
+               as-path-prepend 64512;
+               accept;
+           }
+       }
+   }
+
+:file:`bgpd.conf` for ``NVA 2`` on 192.168.1.101:::
+
+   router bgp 64512
+
+       bgp router-id 192.168.1.101
+
+       neighbor 192.168.1.100  remote-as 64512
+
+       address-family ipv4 vpn
+           neighbor 192.168.1.100 activate
+       exit-address-family
+
+       vnc nve-group group1
+           prefix vn 172.16.0.0/17
+           rd 64512:1
+           response-lifetime 200
+           rt both 1000:1 1000:2
+       exit-vnc
+   exit
+
+:file:`bgpd.conf` for ``NVA 3`` on 192.168.1.102:::
+
+   router bgp 64512
+
+       bgp router-id 192.168.1.102
+
+       neighbor 192.168.1.100  remote-as 64512
+
+       address-family ipv4 vpn
+           neighbor 192.168.1.100 activate
+       exit-address-family
+
+       vnc defaults
+           rd 64512:1
+           response-lifetime 200
+           rt both 1000:1 1000:2
+       exit-vnc
+
+       vnc nve-group group1
+           prefix vn 172.16.128.0/17
+       exit-vnc
+   exit
+
+VNC with Redundant Route Reflectors Configuration
+-------------------------------------------------
+
+This example combines the previous two
+(:ref:`vnc-with-frr-route-reflector-config` and
+:ref:`vnc-with-commercial-route-reflector-config`) into a redundant route
+reflector configuration.  BGP route reflectors ``BGP Route Reflector 1`` and
+``Commercial Router`` are the route reflectors for NVAs ``NVA 2`` and ``NVA
+3``.  The two NVAs have connections to both route reflectors.
+
+.. figure:: ../fig-vnc-redundant-route-reflectors.png
+   :align: center
+   :alt: Redundant Route Reflectors
+
+   FRR-based NVA with redundant route reflectors
+
+:file:`bgpd.conf` for ``Bgpd Route Reflector 1`` on 192.168.1.100:::
+
+   router bgp 64512
+
+    bgp router-id 192.168.1.100
+    bgp cluster-id 192.168.1.100
+
+    neighbor 192.168.1.104 remote-as 64512
+
+    neighbor 192.168.1.101 remote-as 64512
+    neighbor 192.168.1.101 description iBGP-client-192-168-1-101
+    neighbor 192.168.1.101 route-reflector-client
+
+    neighbor 192.168.1.102 remote-as 64512
+    neighbor 192.168.1.102 description iBGP-client-192-168-1-102
+    neighbor 192.168.1.102 route-reflector-client
+
+    address-family ipv4 vpn
+     neighbor 192.168.1.101 activate
+     neighbor 192.168.1.102 activate
+     neighbor 192.168.1.104 activate
+
+     neighbor 192.168.1.101 route-reflector-client
+     neighbor 192.168.1.102 route-reflector-client
+    exit-address-family
+   exit
+
+:file:`bgpd.conf` for ``NVA 2`` on 192.168.1.101:::
+
+    router bgp 64512
+
+     bgp router-id 192.168.1.101
+
+     neighbor 192.168.1.100  remote-as 64512
+     neighbor 192.168.1.104  remote-as 64512
+
+     address-family ipv4 vpn
+      neighbor 192.168.1.100 activate
+      neighbor 192.168.1.104 activate
+     exit-address-family
+
+     vnc nve-group group1
+      prefix vn 172.16.0.0/17
+      rd 64512:1
+      response-lifetime 200
+      rt both 1000:1 1000:2
+     exit-vnc
+    exit
+
+:file:`bgpd.conf` for ``NVA 3`` on 192.168.1.102:::
+
+   router bgp 64512
+
+    bgp router-id 192.168.1.102
+
+    neighbor 192.168.1.100  remote-as 64512
+    neighbor 192.168.1.104  remote-as 64512
+
+    address-family ipv4 vpn
+     neighbor 192.168.1.100 activate
+     neighbor 192.168.1.104 activate
+    exit-address-family
+
+    vnc defaults
+     rd 64512:1
+     response-lifetime 200
+     rt both 1000:1 1000:2
+    exit-vnc
+
+    vnc nve-group group1
+     prefix vn 172.16.128.0/17
+    exit-vnc
+   exit
+
+:file:`bgpd.conf` for the Commercial Router route reflector on 192.168.1.104:::
+
+   routing-options {
+       rib inet.0 {
+           static {
+               route 172.16.0.0/16 next-hop 192.168.1.104;
+           }
+       }
+       autonomous-system 64512;
+       resolution {
+           rib inet.3 {
+               resolution-ribs inet.0;
+           }
+           rib bgp.l3vpn.0 {
+               resolution-ribs inet.0;
+           }
+       }
+   }
+   protocols {
+       bgp {
+           advertise-inactive;
+           family inet {
+               labeled-unicast;
+           }
+          group 1 {
+               type internal;
+               advertise-inactive;
+               advertise-peer-as;
+               import h;
+               family inet {
+                   unicast;
+               }
+               family inet-vpn {
+                   unicast;
+               }
+               cluster 192.168.1.104;
+               neighbor 192.168.1.101;
+               neighbor 192.168.1.102;
+           }
+
+          group 2 {
+               type internal;
+               advertise-inactive;
+               advertise-peer-as;
+               import h;
+               family inet {
+                   unicast;
+               }
+               family inet-vpn {
+                   unicast;
+               }
+               neighbor 192.168.1.100;
+           }
+
+       }
+   }
+   policy-options {
+       policy-statement h {
+           from protocol bgp;
+           then {
+               as-path-prepend 64512;
+               accept;
+           }
+       }
+   }
+
 .. [#] The nve-id is carriedin the route distinguisher. It is the second octet
        of the eight-octet route distinguisher generated for Ethernet / L2
        advertisements. The first octet is a constant 0xFF, and the third
diff --git a/doc/vnc.texi b/doc/vnc.texi
new file mode 100644 (file)
index 0000000..6193d3c
--- /dev/null
@@ -0,0 +1,1593 @@
+@c -*-texinfo-*-
+@c This is part of the Frr Manual.
+@c @value{COPYRIGHT_STR}
+@c See file frr.texi for copying conditions.
+
+@node VNC and VNC-GW
+@chapter VNC and VNC-GW
+This chapter describes how to use
+Virtual Network Control (@acronym{VNC}) services,
+including Network Virtualization Authority (@acronym{NVA}) and 
+VNC Gateway (@acronym{VNC-GW}) functions.
+Background information on NVAs, 
+Network Virtualization Edges (@acronym{NVE}s), underlay networks (@acronym{UN}s),
+and virtual networks (@acronym{VN}s) is available from the  
+@url{https://datatracker.ietf.org/wg/nvo3,IETF Network Virtualization Overlays (@acronym{NVO3}) Working Group}.
+VNC Gateways (@acronym{VNC-GW}s) support the import/export of routing
+information between VNC and customer edge routers (@acronym{CE}s)
+operating within a VN.  Both IP/Layer 3 (L3) VNs, and IP with
+Ethernet/Layer 2 (L2) VNs are supported.
+
+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 }.  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.
+
+The protocol that is used to communicate routing and Ethernet / Layer 2
+(L2) forwarding information between NVAs and NVEs is referred to as the
+Remote Forwarder Protocol (RFP). @code{OpenFlow} is an example
+RFP.  Specific RFP implementations may choose to implement either a
+@code{hard-state} or @code{soft-state} prefix and address registration
+model.  To support a @code{soft-state} refresh model, a @var{lifetime}
+in seconds is associated with all registrations and responses.
+
+The chapter also provides sample configurations for basic example scenarios.  
+
+@menu
+* Configuring VNC Services::
+* Manual Address Control::
+* Other VNC-Related Commands::
+* Example VNC and VNC-GW Configurations::
+* Release Notes::
+@end menu
+
+@node Configuring VNC Services
+@section Configuring VNC
+
+Virtual Network Control (@acronym{VNC}) service configuration commands
+appear in the @code{router bgp} section of the BGPD configuration file
+(@pxref{BGP Configuration Examples}). The commands are broken down into
+the following areas:
+
+@menu
+* General VNC Configuration::
+* RFP Related Configuration::
+* VNC Defaults Configuration::
+* VNC NVE Group Configuration::
+* VNC L2 Group Configuration::
+* Configuring Redistribution of Routes from Other Routing Protocols::
+* Configuring Export of Routes to Other Routing Protocols::
+@end menu
+
+@code{General VNC} configuration applies to general VNC operation and is
+primarily used to control the method used to advertise tunnel
+information.  
+
+@code{Remote Forwarder Protocol (RFP)} configuration relates to the
+protocol used between NVAs and NVEs.  
+
+@code{VNC Defaults} provides default parameters for registered NVEs.
+
+@code{VNC NVE Group} provides for configuration of a specific set of 
+registered NVEs and overrides default parameters.
+
+@code{Redistribution} and @code{Export} control VNC-GW operation, i.e.,
+the  import/export of routing
+information between VNC and customer edge routers (@acronym{CE}s)
+operating within a VN.
+
+@node General VNC Configuration
+@subsection General VNC Configuration
+
+@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
+@subsection RFP Related Configuration 
+
+The protocol that is used to communicate routing and Ethernet / L2
+forwarding information between NVAs and NVEs is referred to as the
+Remote Forwarder Protocol (RFP).  Currently, only a simple example RFP
+is included in Frr.  Developers may use this example as a starting
+point to integrate Frr with an RFP of their choosing, e.g.,
+@code{OpenFlow}.  The example code includes the following sample
+configuration: 
+
+@deffn {RFP} {rfp example-config-value @var{VALUE}} 
+This is a simple example configuration parameter included as part of the
+RFP example code.  @code{VALUE} must be in the range of 0 to 4294967295.
+@end deffn
+
+@node VNC Defaults Configuration
+@subsection VNC Defaults Configuration
+
+The VNC Defaults section allows the user to specify default values for
+configuration parameters for all registered NVEs.
+Default values are overridden by @ref{VNC NVE Group Configuration}. 
+
+@deffn {VNC} {vnc defaults} {}
+Enter VNC configuration mode for specifying VNC default behaviors.  Use
+@code{exit-vnc} to leave VNC configuration mode.  @code{vnc
+defaults} is optional.
+
+@example
+vnc defaults
+  ... various VNC defaults
+exit-vnc
+@end example
+@end deffn
+
+These are the statements that can appear between @code{vnc defaults}
+and @code{exit-vnc}.
+
+@deffn {VNC} {rt import @var{rt-list}} {}
+@deffnx {VNC} {rt export @var{rt-list}} {}
+@deffnx {VNC} {rt both @var{rt-list}} {}
+
+Specify default route target import and export lists.  @var{rt-list} is a
+space-separated list of route targets, each element of which is
+in one of the following forms:
+@itemize
+@item @var{IPv4-address}:@var{two-byte-integer}
+@item @var{four-byte-autonomous-system-number}:@var{two-byte-integer}
+@item @var{two-byte-autonomous-system-number}:@var{four-byte-integer}
+@end itemize
+
+If no default import RT list is specified, then the default import RT
+list is empty.
+If no default export RT list is specified, then the default export RT
+list is empty.
+
+A complete definition of these parameters is
+given below (@pxref{VNC NVE Group Configuration}).
+
+@end deffn
+
+@deffn {VNC} {rd @var{route-distinguisher}}
+
+Specify the default route distinguisher (RD) for routes advertised via BGP
+VPNs.  The route distinguisher must be in one of four forms:
+@itemize
+@item @var{IPv4-address}:@var{two-byte-integer}
+@item @var{four-byte-autonomous-system-number}:@var{two-byte-integer}
+@item @var{two-byte-autonomous-system-number}:@var{four-byte-integer}
+@item auto:vn:@var{two-byte-integer}
+@end itemize
+
+If RD is specified in the defaults section, the default RD
+value is @var{two-byte-autonomous-system-number=0}:@var{four-byte-integer=0}.
+
+A complete definition of this parameter is
+given below (@pxref{VNC NVE Group Configuration}).
+@end deffn
+
+@deffn {VNC} {l2rd @var{nve-id-value}}
+Set the value used to distinguish NVEs connected to the same logical
+Ethernet segment (i.e., L2VPN).
+
+A complete definition of this parameter is
+given below (@pxref{VNC NVE Group Configuration}).
+@end deffn
+
+@deffn {VNC} {response-lifetime @var{lifetime}|infinite} {}
+Specify the default lifetime to be included in RFP
+response messages sent to NVEs.
+
+A complete definition of this parameter is
+given below (@pxref{VNC NVE Group Configuration}).
+
+@end deffn
+
+@deffn {VNC} {export bgp|zebra route-map MAP-NAME}
+Specify that the named route-map should be applied to routes
+being exported to bgp or zebra.
+@end deffn
+
+@deffn {VNC} {export bgp|zebra no route-map}
+Specify that no route-map should be applied to routes
+being exported to bgp or zebra.
+@end deffn
+
+@deffn {VNC} {export bgp|zebra ipv4|ipv6 prefix-list LIST-NAME}
+Specify that the named prefix-list filter should be applied to
+routes being exported to bgp or zebra.
+Prefix-lists for ipv4 and ipv6 are independent of each other.
+@end deffn
+
+@deffn {VNC} {export bgp|zebra no ipv4|ipv6 prefix-list}
+Specify that no prefix-list filter should be applied to
+routes being exported to bgp or zebra.
+@end deffn
+
+@deffn {VNC} {exit-vnc} {}
+Exit VNC configuration mode.
+@end deffn
+
+@c The following example @code{vnc defaults} defines a route target import-export
+@c list for the route targets 1000:1 and 1000:2; a default route
+@c distinguisher, 4444:10; and a default response lifetime of 500
+@c seconds.
+@c 
+@c @example
+@c vnc defaults
+@c     rt both 1000:1 1000:2
+@c     rd 4444:10
+@c     response-lifetime 500
+@c exit-vnc
+@c @end example
+
+@node VNC NVE Group Configuration
+@subsection VNC NVE Group Configuration
+
+A NVE Group corresponds to a specific set of NVEs.  A Client NVE is
+assigned to an NVE Group based on whether there is a match for either
+its virtual or underlay network address against the VN and/or UN address
+prefixes specified in the NVE Group definition.  When an NVE Group
+definition specifies both VN and UN address prefixes, then an NVE must
+match both prefixes in order to be assigned to the NVE Group.  In the
+event that multiple NVE Groups match based on VN and/or UN addresses,
+the NVE is assigned to the first NVE Group listed in the configuration.  
+If an NVE is not assigned to an NVE Group, its messages will be ignored.
+
+Configuration values specified for an NVE group apply to all
+member NVEs and override configuration values specified in the VNC
+Defaults section.
+
+@strong{At least one @code{nve-group} is mandatory for useful VNC
+operation.}
+
+@deffn {VNC} {vnc nve-group @var{name}} {}
+Enter VNC configuration mode for defining the NVE group @var{name}.  
+Use @code{exit} or @code{exit-vnc} to exit group configuration mode.
+
+@example
+vnc nve-group group1
+  ... configuration commands
+exit-vnc
+@end example
+@end deffn
+
+@deffn {VNC} {no vnc nve-group @var{name}} {}
+Delete the NVE group named @var{name}.
+@end deffn
+
+The following statements are valid in an NVE group definition:
+
+@deffn {VNC} {l2rd @var{nve-id-value}}
+Set the value used to distinguish NVEs connected to the same physical
+Ethernet segment (i.e., at the same location)@footnote{The nve-id is
+carried in the route
+distinguisher.  It is the second octet of the eight-octet route
+distinguisher generated for Ethernet / L2 advertisements.
+The first octet is a constant 0xFF, and the third through eighth
+octets are set to the L2 ethernet address being advertised.}
+
+The nve-id subfield may be specified as either a literal value
+in the range 1-255, or it may be specified as @code{auto:vn}, which
+means to use the least-significant octet of the originating
+NVE's VN address.
+@end deffn
+
+@deffn {VNC} {prefix vn|un A.B.C.D/M|X:X::X:X/M} {}
+@anchor{prefix}
+Specify the matching prefix for this NVE group by either virtual-network address
+(@code{vn}) or underlay-network address (@code{un}). Either or both virtual-network
+and underlay-network prefixes may be specified.  Subsequent virtual-network or
+underlay-network values within a @code{vnc nve-group} @code{exit-vnc}
+block override their respective previous values.
+
+These prefixes are used only for determining assignments of NVEs
+to NVE Groups.
+@end deffn
+
+@deffn {VNC} {rd @var{route-distinguisher}}
+Specify the route distinguisher for routes advertised via BGP
+VPNs.  The route distinguisher must be in one of these forms:
+@itemize
+@item @var{IPv4-address}:@var{two-byte-integer}
+@item @var{four-byte-autonomous-system-number}:@var{two-byte-integer}
+@item @var{two-byte-autonomous-system-number}:@var{four-byte-integer}
+@item auto:vn:@var{two-byte-integer}
+@end itemize
+
+Routes originated by NVEs in the NVE group will use
+the group's specified @var{route-distinguisher} when they are
+advertised via BGP. 
+If the @code{auto} form is specified, it means that a matching NVE has
+its RD set to
+@var{rd_type=IP=1}:@var{IPv4-address=VN-address}:@var{two-byte-integer},
+for IPv4 VN addresses and
+@var{rd_type=IP=1}:@var{IPv4-address=Last-four-bytes-of-VN-address}:@var{two-byte-integer},
+for IPv6 VN addresses.
+
+If the NVE group definition does not specify a @var{route-distinguisher},
+then the default @var{route-distinguisher} is used.
+If neither a group nor a default @var{route-distinguisher} is
+configured, then the advertised RD is set to
+@var{two-byte-autonomous-system-number=0}:@var{four-byte-integer=0}.
+@end deffn
+
+@deffn {VNC} {response-lifetime @var{lifetime}|infinite} {}
+Specify the response lifetime, in seconds, to be included in RFP
+response messages sent to NVEs.  If the value
+``infinite'' is given, an infinite lifetime will be used.
+
+Note that this parameter is not the same as the lifetime supplied by
+NVEs in RFP registration messages. This parameter does not affect
+the lifetime value attached to routes sent by this server via BGP.
+
+If the NVE group definition does not specify a @var{response-lifetime},
+the default @var{response-lifetime} will be used.
+If neither a group nor a default @var{response-lifetime} is configured,
+the value 3600 will be used.  The maximum response lifetime is 2147483647.
+@end deffn
+
+@deffn {VNC} {rt export @var{rt-list}} {}
+@deffnx {VNC} {rt import @var{rt-list}} {}
+@deffnx {VNC} {rt both @var{rt-list}} {}
+Specify route target import and export lists.  @var{rt-list} is a
+space-separated list of route targets, each element of which is
+in one of the following forms:
+@itemize
+@item @var{IPv4-address}:@var{two-byte-integer}
+@item @var{four-byte-autonomous-system-number}:@var{two-byte-integer}
+@item @var{two-byte-autonomous-system-number}:@var{four-byte-integer}
+@end itemize
+
+The first form, @code{rt export}, specifies an @var{export rt-list}.
+The @var{export rt-list} will be attached to routes originated by
+NVEs in the NVE group when they are advertised via BGP. 
+If the NVE group definition does not specify an @var{export rt-list},
+then the default @var{export rt-list} is used.
+If neither a group nor a default @var{export rt-list} is configured,
+then no RT list will be sent; in turn, these routes will probably
+not be processed
+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 @w{SAFI} routes must have
+RT lists that have at least one route target in common with the
+group's @var{import rt-list}.
+
+If the NVE group definition does not specify an import filter,
+then the default @var{import rt-list} is used.
+If neither a group nor a default @var{import rt-list} is configured,
+there can be no RT intersections when receiving BGP routes and
+therefore no incoming BGP routes will be processed for the group.
+
+The third, @code{rt both}, is a shorthand way of specifying both
+lists simultaneously, and is equivalent to @code{rt export @var{rt-list}}
+followed by @code{rt import @var{rt-list}}.
+@end deffn
+
+@deffn {VNC} {export bgp|zebra route-map MAP-NAME}
+Specify that the named route-map should be applied to routes
+being exported to bgp or zebra. 
+This paramter is used in conjunction with 
+@ref{Configuring Export of Routes to Other Routing Protocols}.
+This item is optional.
+@end deffn
+
+@deffn {VNC} {export bgp|zebra no route-map}
+Specify that no route-map should be applied to routes
+being exported to bgp or zebra. 
+This paramter is used in conjunction with 
+@ref{Configuring Export of Routes to Other Routing Protocols}.
+This item is optional.
+@end deffn
+
+@deffn {VNC} {export bgp|zebra ipv4|ipv6 prefix-list LIST-NAME}
+Specify that the named prefix-list filter should be applied to
+routes being exported to bgp or zebra.
+Prefix-lists for ipv4 and ipv6 are independent of each other. 
+This paramter is used in conjunction with 
+@ref{Configuring Export of Routes to Other Routing Protocols}.
+This item is optional.
+@end deffn
+
+@deffn {VNC} {export bgp|zebra no ipv4|ipv6 prefix-list}
+Specify that no prefix-list filter should be applied to
+routes being exported to bgp or zebra. 
+This paramter is used in conjunction with 
+@ref{Configuring Export of Routes to Other Routing Protocols}.
+This item is optional.
+@end deffn
+
+@c The following example shows two @code{vnc nve-group} definitions.  The first one,
+@c ``group1'', applies to the IPV4 virtual-network route prefix 172.16/16.  It
+@c sets the response lifetime to 200 seconds.  It defines a route target
+@c import-export filter for the route targets 1000:1 and 1000:2
+@c 
+@c The second @code{vnc nve-group} definition, ``group2'', applies to the IPV6
+@c underlay-network route prefix 10.0.2/24.  It defines the same response
+@c lifetime and import-export filter as ``group1''.
+@c 
+@c @example
+@c vnc nve-group group1
+@c     prefix vn 172.16/16
+@c     response-lifetime 200
+@c     rt both 1000:1 1000:2
+@c exit-vnc
+@c 
+@c vnc nve-group group2
+@c     prefix un 10.0.2/24
+@c     response-lifetime 200
+@c     rt both 1000:1 1000:2
+@c exit-vnc
+@c @end example
+
+@node VNC L2 Group Configuration
+@subsection VNC L2 Group Configuration
+
+The route targets advertised with prefixes and addresses registered by
+an NVE are determined based on the NVE's associated VNC NVE Group
+Configuration, @pxref{VNC NVE Group Configuration}.  Layer 2 (L2) Groups
+are used to override the route targets for an NVE's Ethernet
+registrations based on the Logical Network Identifier and label value.
+A Logical Network Identifier is used to uniquely identify a logical
+Ethernet segment and is conceptually similar to the Ethernet Segment
+Identifier defined in @cite{RFC7432, BGP MPLS-Based Ethernet VPN}.  Both
+the Logical Network Identifier and Label are passed to VNC via RFP
+prefix and address registration.
+
+Note that a corresponding NVE group configuration must be present, and
+that other NVE associated configuration information, notably RD, is
+not impacted by L2 Group Configuration.
+
+@deffn {VNC} {vnc l2-group @var{name}} {}
+Enter VNC configuration mode for defining the L2 group @var{name}.  
+Use @code{exit} or @code{exit-vnc} to exit group configuration mode.
+
+@example
+vnc l2-group group1
+  ... configuration commands
+exit-vnc
+@end example
+@end deffn
+
+@deffn {VNC} {no vnc l2-group @var{name}} {}
+Delete the L2 group named @var{name}.
+@end deffn
+
+The following statements are valid in a L2 group definition:
+
+@deffn {VNC} {logical-network-id @var{VALUE}}
+Define the Logical Network Identifier with a value in the range of
+0-4294967295 that identifies the logical Ethernet segment. 
+@end deffn
+
+@deffn {VNC} {labels @var{label-list}}
+@deffnx {VNC} {no labels @var{label-list}}
+Add or remove labels associated with the group.  @var{label-list} is a
+space separated list of label values in the range of 0-1048575.
+@end deffn
+
+@deffn {VNC} {rt import @var{rt-target}} {}
+@deffnx {VNC} {rt export @var{rt-target}} {}
+@deffnx {VNC} {rt both @var{rt-target}} {}
+Specify the route target import and export value associated with the
+group. A complete definition of these parameters is given above,
+@pxref{VNC NVE Group Configuration}.
+@end deffn
+
+
+@node Configuring Redistribution of Routes from Other Routing Protocols
+@subsection Configuring Redistribution of Routes from Other Routing Protocols
+
+Routes from other protocols (including BGP) can be provided to VNC (both
+for RFP and for redistribution via BGP)
+from three sources: the zebra kernel routing process;
+directly from the main (default) unicast BGP RIB; or directly
+from a designated BGP unicast exterior routing RIB instance.
+
+The protocol named in the @code{vnc redistribute} command indicates
+the route source:
+@code{bgp-direct} routes come directly from the main (default)
+unicast BGP RIB and are available for RFP and are redistributed via BGP;
+@code{bgp-direct-to-nve-groups} routes come directly from a designated
+BGP unicast routing RIB and are made available only to RFP;
+and routes from other protocols come from the zebra kernel
+routing process.
+Note that the zebra process does not need to be active if
+only @code{bgp-direct} or @code{bgp-direct-to-nve-groups} routes are used.
+
+@subsubsection @code{zebra} routes
+
+Routes originating from protocols other than BGP must be obtained
+via the zebra routing process.
+Redistribution of these routes into VNC does not support policy mechanisms
+such as prefix-lists or route-maps.
+
+@subsubsection @code{bgp-direct} routes
+
+@code{bgp-direct} redistribution supports policy via
+prefix lists and route-maps. This policy is applied to incoming
+original unicast routes before the redistribution translations
+(described below) are performed.
+
+Redistribution of @code{bgp-direct} routes is performed in one of three
+possible modes: @code{plain}, @code{nve-group}, or @code{resolve-nve}.
+The default mode is @code{plain}.
+These modes indicate the kind of translations applied to routes before
+they are added to the VNC RIB.
+
+In @code{plain} mode, the route's next hop is unchanged and the RD is set
+based on the next hop.
+For @code{bgp-direct} redistribution, the following translations are performed:
+@itemize @bullet
+@item
+The VN address is set to the original unicast route's next hop address.
+@item
+The UN address is NOT set. (VN->UN mapping will occur via
+ENCAP route or attribute, based on @code{vnc advertise-un-method}
+setting, generated by the RFP registration of the actual NVE) 
+@item
+The RD is set to as if auto:vn:0 were specified (i.e.,
+@var{rd_type=IP=1}:@var{IPv4-address=VN-address}:@var{two-byte-integer=0})
+@item
+The RT list is included in the extended community list copied from the
+original unicast route (i.e., it must be set in the original unicast route).
+@end itemize
+
+
+
+In @code{nve-group} mode, routes are registered with VNC as
+if they came from an NVE in the nve-group designated in the
+@code{vnc redistribute nve-group} command. The following
+translations are performed:
+
+@itemize @bullet
+@item
+The next hop/VN address is set to the VN prefix configured for the
+redistribute nve-group.
+@item
+The UN address is set to the UN prefix configured for the
+redistribute nve-group.
+@item
+The RD is set to the RD configured for the redistribute nve-group.
+@item
+The RT list is set to the RT list configured for the redistribute nve-group.
+If @code{bgp-direct} routes are being redistributed, 
+any extended communities present in the original unicast route
+will also be included.
+@end itemize
+
+
+In @code{resolve-nve} mode, the next hop of the original BGP route is
+typically the address of an NVE connected router (CE) connected by one or
+more NVEs.
+Each of the connected NVEs will register, via RFP, a VNC host route
+to the CE.
+This mode may be though of as a mechanism to proxy RFP registrations
+of BGP unicast routes on behalf of registering NVEs.
+
+Multiple copies of the BGP route, one per matching NVE host route, will be
+added to VNC.
+In other words, for a given BGP unicast route, each instance of a
+RFP-registered host route to the unicast route's next hop will result
+in an instance of an imported VNC route.
+Each such imported VNC route will have a prefix equal to the original
+BGP unicast route's prefix, and a next hop equal to the next hop of the
+matching RFP-registered host route.
+If there is no RFP-registered host route to the next hop of the BGP unicast
+route, no corresponding VNC route will be imported.
+
+The following translations are applied:
+
+@itemize @bullet
+@item
+The Next Hop is set to the next hop of the NVE route (i.e., the
+VN address of the NVE).
+
+@item
+The extended community list in the new route is set to the 
+union of:
+@itemize @minus
+@item
+Any extended communities in the original BGP route
+@item
+Any extended communities in the NVE route
+@item
+An added route-origin extended community with the next hop of the
+original BGP route
+is added to the new route.
+The value of the local administrator field defaults 5226 but may
+be configured by the user via the @code{roo-ec-local-admin} parameter.
+@end itemize
+
+@item
+The Tunnel Encapsulation attribute is set to the value of the Tunnel
+Encapsulation attribute of the NVE route, if any.
+
+@end itemize
+
+@subsubsection @code{bgp-direct-to-nve-groups} routes
+
+Unicast routes from the main or a designated instance of BGP
+may be redistributed to VNC as bgp-direct-to-nve-groups routes. These
+routes are NOT announced via BGP,
+but they are made available for local RFP lookup in response to
+queries from NVEs.
+
+A non-main/default BGP instance is configured using the
+@code{bgp multiple-instance} and @code{router bgp AS view NAME}
+commands as described elsewhere in this document.
+
+In order for a route in the unicast BGP RIB to be made
+available to a querying NVE, there must already be, available to
+that NVE, an (interior) VNC route matching the next hop address
+of the unicast route.
+When the unicast route is provided to the NVE, its next hop 
+is replaced by the next hop of the corresponding
+NVE. If there are multiple longest-prefix-match VNC routes,
+the unicast route will be replicated for each.
+
+There is currently no policy (prefix-list or route-map) support
+for @code{bgp-direct-to-nve-groups} routes.
+
+@subsubsection Redistribution Command Syntax
+
+@deffn {VNC} {vnc redistribute ipv4|ipv6 bgp|bgp-direct|ipv6 bgp-direct-to-nve-groups|connected|kernel|ospf|rip|static} {}
+@deffnx {VNC} {vnc redistribute ipv4|ipv6 bgp-direct-to-nve-groups view @var{VIEWNAME}} {}
+@deffnx {VNC} {no vnc redistribute ipv4|ipv6 bgp|bgp-direct|bgp-direct-to-nve-groups|connected|kernel|ospf|rip|static} {}
+Import (or do not import) prefixes from another routing
+protocols. Specify both the address family to import (@code{ipv4} or
+@code{ipv6}) and the protocol (@code{bgp}, @code{bgp-direct},
+@code{bgp-direct-to-nve-groups}, @code{connected},
+@code{kernel}, @code{ospf}, @code{rip}, or @code{static}).  Repeat
+this statement as needed for each combination of address family and
+routing protocol.
+Prefixes from protocol @code{bgp-direct} are imported from unicast BGP
+in the same bgpd process.
+Prefixes from all other protocols (including @code{bgp}) are imported
+via the @code{zebra} kernel routing process.
+@end deffn
+
+@deffn {VNC} {vnc redistribute mode plain|nve-group|resolve-nve}
+Redistribute routes from other protocols into VNC using the
+specified mode.
+Not all combinations of modes and protocols are supported.
+@end deffn
+
+@deffn {VNC} {vnc redistribute nve-group @var{group-name}} {}
+@deffnx {VNC} {no vnc redistribute nve-group @var{group-name}} {}
+When using @code{nve-group} mode,
+assign (or do not assign) the NVE group @var{group-name} to routes
+redistributed from another routing protocol.  @var{group-name}
+must be configured using @code{vnc nve-group}.
+
+The VN and UN prefixes of the nve-group must both be configured,
+and each prefix must be specified as a full-length (/32 for IPv4,
+/128 for IPv6) prefix.
+@end deffn
+
+@deffn {VNC} {vnc redistribute lifetime @var{lifetime}|infinite} {}
+Assign a registration lifetime, either @var{lifetime} seconds or
+@code{infinite}, to prefixes redistributed from other routing
+protocols as if they had been received via RFP registration messages
+from an NVE.  @var{lifetime} can be any integer between 1 and
+4294967295, inclusive. 
+@end deffn
+
+@deffn {VNC} {vnc redistribute resolve-nve roo-ec-local-admin @var{0-65536}}
+Assign a value to the local-administrator subfield used in the
+Route Origin extended community that is assigned to routes exported 
+under the @code{resolve-nve} mode. The default value is @var{5226}.
+@end deffn
+
+The following four @code{prefix-list} and @code{route-map} commands
+may be specified in the context of an nve-group or not.
+If they are specified in the context of an nve-group, they
+apply only if the redistribution mode is @code{nve-group},
+and then only for routes being redistributed from
+@code{bgp-direct}.
+If they are specified outside the context of an nve-group, then
+they apply only for redistribution modes @code{plain} and @code{resolve-nve},
+and then only for routes being redistributed from @code{bgp-direct}.
+
+@deffn {VNC} {vnc redistribute bgp-direct (ipv4|ipv6) prefix-list @var{LIST-NAME}}
+When redistributing @code{bgp-direct} routes,
+specifies that the named prefix-list should be applied.
+@end deffn
+
+@deffn {VNC} {vnc redistribute bgp-direct no (ipv4|ipv6) prefix-list}
+When redistributing @code{bgp-direct} routes,
+specifies that no prefix-list should be applied.
+@end deffn
+
+@deffn {VNC} {vnc redistribute bgp-direct route-map  @var{MAP-NAME}}
+When redistributing @code{bgp-direct} routes,
+specifies that the named route-map should be applied.
+@end deffn
+
+@deffn {VNC} {vnc redistribute bgp-direct no route-map}
+When redistributing @code{bgp-direct} routes,
+specifies that no route-map should be applied.
+@end deffn
+
+@node Configuring Export of Routes to Other Routing Protocols
+@subsection Configuring Export of Routes to Other Routing Protocols
+
+Routes from VNC (both for RFP and for redistribution via BGP) can be
+provided to other protocols, either via zebra or directly to BGP.
+
+It is important to note that when exporting routes to other protocols,
+the downstream protocol must also be configured to import the routes.
+For example, when VNC routes are exported to unicast BGP, the BGP
+configuration must include a corresponding @code{redistribute vnc-direct}
+statement.
+
+@deffn {VNC} {export bgp|zebra mode none|group-nve|registering-nve|ce}
+Specify how routes should be exported to bgp or zebra.
+If the mode is @code{none}, routes are not exported.
+If the mode is @code{group-nve}, routes are exported according
+to nve-group or vrf-policy group configuration (@pxref{VNC NVE Group Configuration}): if a group is configured to
+allow export, then each prefix visible to the group is exported
+with next hops set to the currently-registered NVEs.
+If the mode is @code{registering-nve}, then all VNC routes are
+exported with their original next hops.
+If the mode is @code{ce}, only VNC routes that have an NVE connected CE Router
+encoded in a Route Origin Extended Community are exported.
+This extended community must have an administrative value that
+matches the configured @code{roo-ec-local-admin} value.
+The next hop of the exported route is set to the encoded
+NVE connected CE Router.
+
+The default for both bgp and zebra is mode @code{none}.
+@end deffn
+
+@deffn {VNC} {vnc export bgp|zebra group-nve group @var{group-name}}
+@deffnx {VNC} {vnc export bgp|zebra group-nve no group @var{group-name}}
+When export mode is @code{group-nve},
+export (or do not export) prefixes from the specified nve-group or
+vrf-policy group
+to unicast BGP or to zebra.
+Repeat this statement as needed for each nve-group to be exported.
+Each VNC prefix that is exported will result in N exported routes to the
+prefix, each with a next hop corresponding to one of the N NVEs currently
+associated with the nve-group.
+@end deffn
+
+@deffn {VNC} export bgp|zebra ipv4|ipv6 prefix-list LIST-NAME
+When export mode is @code{ce} or @code{registering-nve},
+specifies that the named prefix-list should be applied to routes
+being exported to bgp or zebra.
+Prefix-lists for ipv4 and ipv6 are independent of each other.
+@end deffn
+
+@deffn {VNC} export bgp|zebra no ipv4|ipv6 prefix-list
+When export mode is @code{ce} or @code{registering-nve},
+specifies that no prefix-list should be applied to routes
+being exported to bgp or zebra.
+@end deffn
+
+@deffn {VNC} export bgp|zebra route-map MAP-NAME
+When export mode is @code{ce} or @code{registering-nve},
+specifies that the named route-map should be applied to routes
+being exported to bgp or zebra.
+@end deffn
+
+@deffn {VNC} export bgp|zebra no route-map
+When export mode is @code{ce} or @code{registering-nve},
+specifies that no route-map should be applied to routes
+being exported to bgp or zebra.
+@end deffn
+
+When the export mode is @code{group-nve}, policy for exported
+routes is specified per-NVE-group or vrf-policy group inside a @code{nve-group} @var{RFG-NAME} block
+via the following commands(@pxref{VNC NVE Group Configuration}):
+
+@deffn {VNC} {export bgp|zebra route-map MAP-NAME}
+This command is valid inside a @code{nve-group} @var{RFG-NAME} block.
+It specifies that the named route-map should be applied to routes
+being exported to bgp or zebra.
+@end deffn
+
+@deffn {VNC} {export bgp|zebra no route-map}
+This command is valid inside a @code{nve-group} @var{RFG-NAME} block.
+It specifies that no route-map should be applied to routes
+being exported to bgp or zebra.
+@end deffn
+
+@deffn {VNC} {export bgp|zebra ipv4|ipv6 prefix-list LIST-NAME}
+This command is valid inside a @code{nve-group} @var{RFG-NAME} block.
+It specifies that the named prefix-list filter should be applied to
+routes being exported to bgp or zebra.
+Prefix-lists for ipv4 and ipv6 are independent of each other.
+@end deffn
+
+@deffn {VNC} {export bgp|zebra no ipv4|ipv6 prefix-list}
+This command is valid inside a @code{nve-group} @var{RFG-NAME} block.
+It specifies that no prefix-list filter should be applied to
+routes being exported to bgp or zebra.
+@end deffn
+
+@node Manual Address Control
+@section Manual Address Control
+
+The commands in this section can be used to augment normal dynamic VNC.
+The @code{add vnc} commands can be used to manually add IP prefix or
+Ethernet MAC address forwarding information.  The @code{clear vnc}
+commands can be used to remove manually and dynamically added
+information.
+
+@deffn {Command} {add vnc prefix (A.B.C.D/M|X:X::X:X/M) vn (A.B.C.D|X:X::X:X) un (A.B.C.D|X:X::X:X) [cost <0-255>] [lifetime (infinite|<1-4294967295>)] [local-next-hop (A.B.C.D|X:X::X:X) [local-cost <0-255>]]} {}
+Register an IP prefix on behalf of the NVE identified by the VN and UN
+addresses.  The @code{cost} parameter provides the administrative
+preference of the forwarding information for remote advertisement.  If
+omitted, it defaults to 255 (lowest preference).  The @code{lifetime}
+parameter identifies the period, in seconds, that the information
+remains valid.  If omitted, it defaults to @var{infinite}.  The optional
+@code{local-next-hop} parameter is used to configure a nexthop to be
+used by an NVE to reach the prefix via a locally connected CE router.
+This information remains local to the NVA, i.e., not passed to other
+NVAs, and is only passed to registered NVEs. When specified, it is also
+possible to provide a @code{local-cost} parameter to provide a
+forwarding preference.  If omitted, it defaults to 255 (lowest
+preference).
+@end deffn
+
+
+@deffn {Command} {add vnc mac xx:xx:xx:xx:xx:xx virtual-network-identifier <1-4294967295> vn (A.B.C.D|X:X::X:X) un (A.B.C.D|X:X::X:X) [prefix (A.B.C.D/M|X:X::X:X/M)] [cost <0-255>] [lifetime (infinite|<1-4294967295>)]} {}
+Register a MAC address for a logical Ethernet (L2VPN) on behalf of the
+NVE identified by the VN and UN addresses.
+The optional @code{prefix} parameter is to support enable IP address
+mediation for the given prefix.   The @code{cost} parameter provides the administrative
+preference of the forwarding information.  If omitted, it defaults to
+255.  The @code{lifetime} parameter identifies the period, in seconds,
+that the information remains valid.  If omitted, it defaults to
+@var{infinite}. 
+@end deffn
+
+@deffn {Command} {clear vnc prefix (*|A.B.C.D/M|X:X::X:X/M) (*|[(vn|un) (A.B.C.D|X:X::X:X|*) [(un|vn) (A.B.C.D|X:X::X:X|*)] [mac xx:xx:xx:xx:xx:xx] [local-next-hop (A.B.C.D|X:X::X:X)])} {}
+Delete the information identified by prefix, VN address, and UN address.
+Any or all of these parameters may be wilcarded to (potentially) match
+more than one registration.
+The optional @code{mac} parameter specifies a layer-2 MAC address
+that must match the registration(s) to be deleted.
+The optional @code{local-next-hop} parameter is used to
+delete specific local nexthop information.
+@end deffn
+
+@deffn {Command} {clear vnc mac (*|xx:xx:xx:xx:xx:xx) virtual-network-identifier (*|<1-4294967295>) (*|[(vn|un) (A.B.C.D|X:X::X:X|*) [(un|vn) (A.B.C.D|X:X::X:X|*)] [prefix (*|A.B.C.D/M|X:X::X:X/M)])} {}
+Delete mac forwarding information.
+Any or all of these parameters may be wilcarded to (potentially) match
+more than one registration.
+The default value for the @code{prefix} parameter is the wildcard value @var{*}.
+@end deffn
+
+@deffn {Command} {clear vnc nve (*|((vn|un) (A.B.C.D|X:X::X:X) [(un|vn) (A.B.C.D|X:X::X:X)])) } {}
+Delete prefixes associated with the NVE specified by the given VN and UN
+addresses.
+It is permissible to specify only one of VN or UN, in which case
+any matching registration will be deleted.
+It is also permissible to specify @code{*} in lieu of any VN or UN
+address, in which case all registrations will match.
+@end deffn
+
+@node Other VNC-Related Commands
+@section Other VNC-Related Commands
+
+Note: VNC-Related configuration can be obtained via the @code{show
+running-configuration} command when in @code{enable} mode.
+
+The following commands are used to clear and display 
+Virtual Network Control related information:
+
+@deffn {COMMAND} {clear vnc counters} {}
+Reset the counter values stored by the NVA. Counter
+values can be seen using the @code{show vnc} commands listed above. This
+command is only available in @code{enable} mode.
+@end deffn
+
+@deffn {Command} {show vnc summary} {}
+Print counter values and other general information 
+about the NVA. Counter values can be reset 
+using the @code{clear vnc counters} command listed below.
+@end deffn
+
+@deffn {Command} {show vnc nves} {}
+@deffnx {Command} {show vnc nves vn|un @var{address}} {}
+Display the NVA's current clients. Specifying @var{address}
+limits the output to the NVEs whose addresses match @var{address}.
+The time since the NVA last communicated with the NVE, per-NVE
+summary counters and each NVE's addresses will be displayed.
+@end deffn
+
+@deffn {Command} {show vnc queries} {}
+@deffnx {Command} {show vnc queries @var{prefix}} {}
+Display active Query information.  Queries remain valid for the default
+Response Lifetime (@pxref{VNC Defaults Configuration}) or NVE-group
+Response Lifetime (@pxref{VNC NVE Group Configuration}).  Specifying
+@var{prefix} limits the output to Query Targets that fall within
+@var{prefix}.
+
+Query information is provided for each querying NVE, and includes the
+Query Target and the time remaining before the information is removed.
+@end deffn
+
+@deffn {Command} {show vnc registrations [all|local|remote|holddown|imported]} {}
+@deffnx {Command} {show vnc registrations [all|local|remote|holddown|imported] @var{prefix}} {}
+Display local, remote, holddown, and/or imported registration information.
+Local registrations are routes received via RFP, which are present in the
+NVA Registrations Cache.
+Remote registrations are routes received via BGP (VPN SAFIs), which
+are present in the NVE-group import tables.
+Holddown registrations are local and remote routes that have been
+withdrawn but whose holddown timeouts have not yet elapsed.
+Imported information represents routes that are imported into NVA and
+are made available to querying NVEs.  Depending on configuration,
+imported routes may also be advertised via BGP.
+Specifying @var{prefix} limits the output to the registered prefixes that
+fall within @var{prefix}.
+
+Registration information includes the registered prefix, the registering
+NVE addresses, the registered administrative cost, the registration
+lifetime and the time since the information was registered or, in the
+case of Holddown registrations, the amount of time remaining before the
+information is removed.
+@end deffn
+
+@deffn {Command} {show vnc responses [active|removed]} {}
+@deffnx {Command} {show vnc responses [active|removed] @var{prefix}} {}
+Display all, active and/or removed response information which are
+present in the NVA Responses Cache. Responses remain valid for the
+default Response Lifetime (@pxref{VNC Defaults Configuration}) or
+NVE-group Response Lifetime (@pxref{VNC NVE Group Configuration}.)
+When Removal Responses are enabled (@pxref{General VNC Configuration}),
+such responses are listed for the Response Lifetime.  Specifying
+@var{prefix} limits the output to the addresses that fall within
+@var{prefix}.
+
+Response information is provided for each querying NVE, and includes
+the response prefix, the prefix-associated registering NVE addresses,
+the administrative cost, the provided response lifetime and the time
+remaining before the information is to be removed or will become inactive.
+@end deffn
+
+@deffn {Command} {show memory vnc} {}
+Print the number of memory items allocated by the NVA.
+@end deffn
+
+@node Example VNC and VNC-GW Configurations
+@section Example VNC and VNC-GW Configurations
+
+@menu
+* Mesh NVA Configuration::
+* Mesh NVA and VNC-GW Configuration::
+* VNC with Frr Route Reflector Configuration::
+* VNC with Commercial Route Reflector Configuration::
+* VNC with Redundant Route Reflectors Configuration::
+@c * Interfacing VNC to an IGP::
+@end menu
+
+@node  Mesh NVA Configuration
+@subsection  Mesh NVA Configuration
+
+This example includes three NVAs, nine NVEs, and two NVE groups. Note
+that while not shown, a single physical device may support multiple
+logical NVEs.  @ref{fig:fig-vnc-mesh} shows @code{NVA 1}
+(192.168.1.100), @code{NVA 2} (192.168.1.101), and @code{NVA 3}
+(192.168.1.102), which are connected in a full mesh.  Each is a
+member of the autonomous system 64512.  Each NVA provides VNC
+services to three NVE clients in the 172.16.0.0/16 virtual-network
+address range.  The 172.16.0.0/16 address range is partitioned into
+two NVE groups, @code{group1} (172.16.0.0/17) and @code{group2}
+(172.16.128.0/17).
+
+Each NVE belongs to either NVE group @code{group1} or NVE group
+@code{group2}.  The NVEs @code{NVE 1}, @code{NVE 2}, @code{NVE
+4}, @code{NVE 7}, and @code{NVE 8} are members of the NVE group
+@code{group1}.  The NVEs @code{NVE 3}, @code{NVE 5}, @code{NVE
+6}, and @code{NVE 9} are members of the NVE group @code{group2}.
+
+Each NVA advertises NVE underlay-network IP addresses using the
+Tunnel Encapsulation Attribute.
+
+@float Figure,fig:fig-vnc-mesh
+@center @image{fig-vnc-mesh,400pt,,Three-way Mesh}
+@caption{A three-way full mesh with three NVEs per NVA}
+@end float
+
+@file{bgpd.conf} for @code{NVA 1} (192.168.1.100)
+@verbatim
+router bgp 64512
+
+    bgp router-id 192.168.1.100
+
+    neighbor 192.168.1.101  remote-as 64512
+    neighbor 192.168.1.102  remote-as 64512
+
+    address-family ipv4 vpn
+        neighbor 192.168.1.101 activate
+        neighbor 192.168.1.102 activate
+    exit-address-family
+
+    vnc defaults
+        rd 64512:1
+        response-lifetime 200
+        rt both 1000:1 1000:2
+    exit-vnc
+
+    vnc nve-group group1
+        prefix vn 172.16.0.0/17
+        rt both 1000:1 
+    exit-vnc
+
+    vnc nve-group group2
+        prefix vn 172.16.128.0/17
+        rt both 1000:2
+    exit-vnc
+
+exit
+@end verbatim
+
+@file{bgpd.conf} for @code{NVA 2} (192.168.1.101):
+@verbatim
+router bgp 64512
+
+    bgp router-id 192.168.1.101
+
+    neighbor 192.168.1.100  remote-as 64512
+    neighbor 192.168.1.102  remote-as 64512
+
+    address-family ipv4 vpn
+        neighbor 192.168.1.100 activate
+        neighbor 192.168.1.102 activate
+    exit-address-family
+
+    vnc nve-group group1
+        prefix vn 172.16.0.0/17
+        rd 64512:1
+        response-lifetime 200
+        rt both 1000:1 1000:2
+    exit-vnc
+exit
+@end verbatim
+
+@file{bgpd.conf} for @code{NVA 3} (192.168.1.102):
+@verbatim
+router bgp 64512
+
+    bgp router-id 192.168.1.102
+
+    neighbor 192.168.1.101  remote-as 64512
+    neighbor 192.168.1.102  remote-as 64512
+
+    address-family ipv4 vpn
+        neighbor 192.168.1.100 activate
+        neighbor 192.168.1.101 activate
+    exit-address-family
+
+    vnc defaults
+        rd 64512:1
+        response-lifetime 200
+        rt both 1000:1 1000:2
+    exit-vnc
+
+    vnc nve-group group1
+        prefix vn 172.16.128.0/17
+    exit-vnc
+exit
+@end verbatim
+
+@node Mesh NVA and VNC-GW Configuration
+@subsection Mesh NVA and VNC-GW Configuration
+
+This example includes two NVAs, each with two associated NVEs, and two
+VNC-GWs, each supporting two CE routers physically attached to the four
+NVEs.  Note that this example is showing a more complex configuration
+where VNC-GW is separated from normal NVA functions; it is equally
+possible to simplify the configuration and combine NVA and VNC-GW
+functions in a single frr instance.
+
+@float Figure,fig:fig-vnc-gw
+@center @image{fig-vnc-gw,400pt,,Frr VNC Gateway}
+@caption{Meshed NVEs and VNC-GWs}
+@end float
+
+As shown in @ref{fig:fig-vnc-gw}, NVAs and VNC-GWs are connected in a
+full iBGP mesh.  The VNC-GWs each have two CEs configured as
+route-reflector clients.  Each client provides BGP updates with unicast
+routes that the VNC-GW reflects to the other client.  The VNC-GW also
+imports these unicast routes into VPN routes to be shared with the other
+VNC-GW and the two NVAs.  This route importation is controlled with the
+@code{vnc redistribute} statements shown in the configuration.
+Similarly, registrations sent by NVEs via RFP to the NVAs are exported
+by the VNC-GWs to the route-reflector clients as unicast routes.  RFP
+registrations exported this way have a next-hop address of the CE behind
+the connected (registering) NVE.  Exporting VNC routes as IPv4 unicast
+is enabled with the @code{vnc export} command below.
+
+The configuration for @code{VNC-GW 1} is shown below.
+@verbatim
+router bgp 64512
+ bgp router-id 192.168.1.101
+ bgp cluster-id 1.2.3.4
+ neighbor 192.168.1.102 remote-as 64512
+ neighbor 192.168.1.103 remote-as 64512
+ neighbor 192.168.1.104 remote-as 64512
+ neighbor 172.16.1.2 remote-as 64512
+ neighbor 172.16.2.2 remote-as 64512
+ !
+ address-family ipv4 unicast
+  redistribute vnc-direct
+  no neighbor 192.168.1.102 activate
+  no neighbor 192.168.1.103 activate
+  no neighbor 192.168.1.104 activate
+  neighbor 172.16.1.2 route-reflector-client
+  neighbor 172.16.2.2 route-reflector-client
+ exit-address-family
+ !
+ address-family ipv4 vpn
+   neighbor 192.168.1.102 activate
+   neighbor 192.168.1.103 activate
+   neighbor 192.168.1.104 activate
+ exit-address-family
+ vnc export bgp mode ce
+ vnc redistribute mode resolve-nve
+ vnc redistribute ipv4 bgp-direct
+ exit
+@end verbatim
+
+Note that in the VNC-GW configuration, the neighboring VNC-GW and
+NVAs each have a statement disabling the IPv4 unicast address family.
+IPv4 unicast is on by default and this prevents the other VNC-GW and
+NVAs from learning unicast routes advertised by the route-reflector clients.
+
+Configuration for @code{NVA 2}:
+@verbatim
+router bgp 64512
+ bgp router-id 192.168.1.104
+ neighbor 192.168.1.101 remote-as 64512
+ neighbor 192.168.1.102 remote-as 64512
+ neighbor 192.168.1.103 remote-as 64512
+ !
+ address-family ipv4 unicast
+  no neighbor 192.168.1.101 activate
+  no neighbor 192.168.1.102 activate
+  no neighbor 192.168.1.103 activate
+ exit-address-family
+ !
+ address-family ipv4 vpn
+   neighbor 192.168.1.101 activate
+   neighbor 192.168.1.102 activate
+   neighbor 192.168.1.103 activate
+ exit-address-family
+ !
+ vnc defaults
+  response-lifetime 3600
+  exit-vnc
+ vnc nve-group nve1
+  prefix vn 172.16.1.1/32
+  response-lifetime 3600
+  rt both 1000:1 1000:2
+  exit-vnc
+ vnc nve-group nve2
+  prefix vn 172.16.2.1/32
+  response-lifetime 3600
+  rt both 1000:1 1000:2
+  exit-vnc
+ exit
+@end verbatim
+
+@c TBD make this its own example:
+@c 
+@c @float Figure,fig:fig-vnc-gw-rr
+@c @center @image{fig-vnc-gw-rr,400pt,,Frr VNC Gateway with RR}
+@c @end float
+@c An NVA can also import unicast routes from BGP without advertising the
+@c imported routes as VPN routes.  Such imported routes, while not
+@c distributed to other NVAs or VNC-GWs, are are available to NVEs via
+@c RFP query messages sent to the NVA. @ref{fig:fig-vnc-gw-rr}
+@c shows an example topology where unicast routes are imported into NVAs
+@c from a Route Reflector.  (@pxref{Route Reflector} for route reflector
+@c configuration details.)  The following three lines can be added to the
+@c @code{NVA 1} and @code{NVA 2} configurations to import routes into VNC
+@c for local VNC use:
+@c 
+@c @verbatim
+@c  neighbor 192.168.1.105 remote-as 64512
+@c  vnc redistribute mode plain
+@c  vnc redistribute ipv4 bgp-direct-to-nve-groups
+@c @end verbatim
+
+@node VNC with Frr Route Reflector Configuration
+@subsection VNC with Frr Route Reflector Configuration
+A route reflector eliminates the need for a fully meshed NVA
+network by acting as the hub between NVAs.
+@ref{fig:fig-vnc-frr-route-reflector} shows BGP route reflector
+@code{BGP Route Reflector 1} (192.168.1.100) as a route reflector for
+NVAs @code{NVA 2}(192.168.1.101) and @code{NVA 3}
+(192.168.1.102).
+
+@float Figure,fig:fig-vnc-frr-route-reflector
+@center @image{fig-vnc-frr-route-reflector,400pt,,Frr Route Reflector}
+@caption{Two NVAs and a BGP Route Reflector} 
+@end float
+
+@code{NVA 2} and @code{NVA 3} 
+advertise NVE underlay-network IP addresses using the Tunnel Encapsulation Attribute.
+@code{BGP Route Reflector 1} ``reflects'' advertisements from
+@code{NVA 2} to @code{NVA 3} and vice versa.
+
+As in the example of @ref{Mesh NVA Configuration}, there are two NVE groups.
+The 172.16.0.0/16 address range is partitioned into two NVE groups,
+@code{group1} (172.16.0.0/17) and @code{group2} (172.16.128.0/17).
+The NVE @code{NVE 4}, @code{NVE 7}, and @code{NVE 8} are
+members of the NVE group @code{group1}.  The NVEs @code{NVE 5},
+@code{NVE 6}, and @code{NVE 9} are members of the NVE group
+@code{group2}.
+
+@file{bgpd.conf} for @code{BGP Route Reflector 1} on 192.168.1.100:
+@verbatim
+router bgp 64512
+
+    bgp router-id 192.168.1.100
+
+    neighbor 192.168.1.101 remote-as 64512
+    neighbor 192.168.1.101 port 7179
+    neighbor 192.168.1.101 description iBGP-client-192-168-1-101
+
+    neighbor 192.168.1.102 remote-as 64512
+    neighbor 192.168.1.102 port 7179
+    neighbor 192.168.1.102 description iBGP-client-192-168-1-102
+
+    address-family ipv4 unicast
+        neighbor 192.168.1.101 route-reflector-client
+        neighbor 192.168.1.102 route-reflector-client
+    exit-address-family
+
+    address-family ipv4 vpn
+        neighbor 192.168.1.101 activate
+        neighbor 192.168.1.102 activate
+
+        neighbor 192.168.1.101 route-reflector-client
+        neighbor 192.168.1.102 route-reflector-client
+    exit-address-family
+
+exit
+@end verbatim
+
+@file{bgpd.conf} for @code{NVA 2} on 192.168.1.101:
+@verbatim
+router bgp 64512
+
+    bgp router-id 192.168.1.101
+
+    neighbor 192.168.1.100  remote-as 64512
+
+    address-family ipv4 vpn
+        neighbor 192.168.1.100 activate
+    exit-address-family
+
+    vnc nve-group group1
+        prefix vn 172.16.0.0/17
+        rd 64512:1
+        response-lifetime 200
+        rt both 1000:1 1000:2
+    exit-vnc
+exit
+@end verbatim
+
+@file{bgpd.conf} for @code{NVA 2} on 192.168.1.102:
+@verbatim
+router bgp 64512
+
+    bgp router-id 192.168.1.102
+
+    neighbor 192.168.1.100  remote-as 64512
+
+    address-family ipv4 vpn
+        neighbor 192.168.1.100 activate
+    exit-address-family
+
+    vnc defaults
+        rd 64512:1
+        response-lifetime 200
+        rt both 1000:1 1000:2
+    exit-vnc
+
+    vnc nve-group group1
+        prefix vn 172.16.128.0/17
+    exit-vnc
+exit
+@end verbatim
+
+While not shown, an NVA can also be configured as a route reflector.
+
+@node VNC with Commercial Route Reflector Configuration
+@subsection VNC with Commercial Route Reflector Configuration
+This example is identical to @ref{VNC with Frr Route Reflector
+Configuration} with the exception that the route reflector is a
+commercial router.  Only the
+VNC-relevant configuration is provided. 
+
+@float Figure,fig:fig-vnc-commercial-route-reflector
+@center @image{fig-vnc-commercial-route-reflector,400pt,,Commercial Route Reflector}
+@caption{Two NVAs with a commercial route reflector}
+@end float
+
+@file{bgpd.conf} for BGP route reflector @code{Commercial Router} on 192.168.1.104:
+@verbatim
+version 8.5R1.13;
+routing-options {
+    rib inet.0 {
+        static {
+            route 172.16.0.0/16 next-hop 192.168.1.104;
+        }
+    }
+    autonomous-system 64512;
+    resolution {
+        rib inet.3 {
+            resolution-ribs inet.0;
+        }
+        rib bgp.l3vpn.0 {
+            resolution-ribs inet.0;
+        }
+    }
+}
+protocols {
+    bgp {
+        advertise-inactive;
+        family inet {
+            labeled-unicast;
+        }
+       group 1 {
+            type internal;
+            advertise-inactive;
+            advertise-peer-as;
+            import h;
+            family inet {
+                unicast;
+            }
+            family inet-vpn {
+                unicast;
+            }
+            cluster 192.168.1.104;
+            neighbor 192.168.1.101;
+            neighbor 192.168.1.102;
+        }
+    }
+}
+policy-options {
+    policy-statement h {
+        from protocol bgp;
+        then {
+            as-path-prepend 64512;
+            accept;
+        }
+    }
+}
+@end verbatim
+
+@file{bgpd.conf} for @code{NVA 2} on 192.168.1.101:
+@verbatim
+router bgp 64512
+
+    bgp router-id 192.168.1.101
+
+    neighbor 192.168.1.100  remote-as 64512
+
+    address-family ipv4 vpn
+        neighbor 192.168.1.100 activate
+    exit-address-family
+
+    vnc nve-group group1
+        prefix vn 172.16.0.0/17
+        rd 64512:1
+        response-lifetime 200
+        rt both 1000:1 1000:2
+    exit-vnc
+exit
+@end verbatim
+
+@file{bgpd.conf} for @code{NVA 3} on 192.168.1.102:
+@verbatim
+router bgp 64512
+
+    bgp router-id 192.168.1.102
+
+    neighbor 192.168.1.100  remote-as 64512
+
+    address-family ipv4 vpn
+        neighbor 192.168.1.100 activate
+    exit-address-family
+
+    vnc defaults
+        rd 64512:1
+        response-lifetime 200
+        rt both 1000:1 1000:2
+    exit-vnc
+
+    vnc nve-group group1
+        prefix vn 172.16.128.0/17
+    exit-vnc
+exit
+@end verbatim
+
+@node VNC with Redundant Route Reflectors Configuration
+@subsection VNC with Redundant Route Reflectors Configuration
+This example combines the previous two (@ref{VNC with Frr Route
+Reflector Configuration} and @ref{VNC with Commercial Route Reflector
+Configuration}) into a redundant route reflector configuration.  BGP
+route reflectors @code{BGP Route Reflector 1} and @code{Commercial Router}
+are the route reflectors for NVAs @code{NVA 2} and
+@code{NVA 3}.  The two NVAs have connections to both
+route reflectors.
+
+@float Figure,fig:fig-vnc-redundant-route-reflectors
+@center @image{fig-vnc-redundant-route-reflectors,400pt,,Redundant Route Reflectors}
+@caption{Frr-based NVA with redundant route reflectors}
+@end float
+
+@file{bgpd.conf} for @code{Bgpd Route Reflector 1} on 192.168.1.100:
+@verbatim
+router bgp 64512
+
+    bgp router-id 192.168.1.100
+    bgp cluster-id 192.168.1.100
+
+    neighbor 192.168.1.104 remote-as 64512
+
+    neighbor 192.168.1.101 remote-as 64512
+    neighbor 192.168.1.101 description iBGP-client-192-168-1-101
+    neighbor 192.168.1.101 route-reflector-client
+
+    neighbor 192.168.1.102 remote-as 64512
+    neighbor 192.168.1.102 description iBGP-client-192-168-1-102
+    neighbor 192.168.1.102 route-reflector-client
+
+    address-family ipv4 vpn
+       neighbor 192.168.1.101 activate
+       neighbor 192.168.1.102 activate
+       neighbor 192.168.1.104 activate
+
+       neighbor 192.168.1.101 route-reflector-client
+       neighbor 192.168.1.102 route-reflector-client
+    exit-address-family
+exit
+@end verbatim
+
+@file{bgpd.conf} for @code{NVA 2} on 192.168.1.101:
+@verbatim
+router bgp 64512
+
+    bgp router-id 192.168.1.101
+
+    neighbor 192.168.1.100  remote-as 64512
+    neighbor 192.168.1.104  remote-as 64512
+
+    address-family ipv4 vpn
+        neighbor 192.168.1.100 activate
+        neighbor 192.168.1.104 activate
+    exit-address-family
+
+    vnc nve-group group1
+        prefix vn 172.16.0.0/17
+        rd 64512:1
+        response-lifetime 200
+        rt both 1000:1 1000:2
+    exit-vnc
+exit
+@end verbatim
+
+@file{bgpd.conf} for @code{NVA 3} on 192.168.1.102:
+@verbatim
+router bgp 64512
+
+    bgp router-id 192.168.1.102
+
+    neighbor 192.168.1.100  remote-as 64512
+    neighbor 192.168.1.104  remote-as 64512
+
+    address-family ipv4 vpn
+        neighbor 192.168.1.100 activate
+        neighbor 192.168.1.104 activate
+    exit-address-family
+
+    vnc defaults
+        rd 64512:1
+        response-lifetime 200
+        rt both 1000:1 1000:2
+    exit-vnc
+
+    vnc nve-group group1
+        prefix vn 172.16.128.0/17
+    exit-vnc
+exit
+@end verbatim
+
+@file{bgpd.conf} for the Commercial Router route reflector on
+192.168.1.104:
+@verbatim
+routing-options {
+    rib inet.0 {
+        static {
+            route 172.16.0.0/16 next-hop 192.168.1.104;
+        }
+    }
+    autonomous-system 64512;
+    resolution {
+        rib inet.3 {
+            resolution-ribs inet.0;
+        }
+        rib bgp.l3vpn.0 {
+            resolution-ribs inet.0;
+        }
+    }
+}
+protocols {
+    bgp {
+        advertise-inactive;
+        family inet {
+            labeled-unicast;
+        }
+       group 1 {
+            type internal;
+            advertise-inactive;
+            advertise-peer-as;
+            import h;
+            family inet {
+                unicast;
+            }
+            family inet-vpn {
+                unicast;
+            }
+            cluster 192.168.1.104;
+            neighbor 192.168.1.101;
+            neighbor 192.168.1.102;
+        }
+
+       group 2 {
+            type internal;
+            advertise-inactive;
+            advertise-peer-as;
+            import h;
+            family inet {
+                unicast;
+            }
+            family inet-vpn {
+                unicast;
+            }
+            neighbor 192.168.1.100;
+        }
+
+    }
+}
+policy-options {
+    policy-statement h {
+        from protocol bgp;
+        then {
+            as-path-prepend 64512;
+            accept;
+        }
+    }
+}
+@end verbatim
+
+@node Release Notes
+@section Release Notes
+
+@c A paragraph that introduces our release notes.
+
+@c outer list, one item per VNC release, items preceded by bullet
+@itemize @bullet 
+@item
+
+@c @item
+@end itemize
+
+@evenheading @thispage@|@|@thistitle
+@oddheading @thischapter@|@|@thispage
+@everyfooting 
+
index 0ccffde72bf0e6f096f13cae025f3bdf5436df4e..84396f0878ac36c4859a4a163aa7ce69a420f3d0 100644 (file)
@@ -170,9 +170,11 @@ void eigrp_reply_receive(struct eigrp *eigrp, struct ip *iph,
                 */
                if (!dest) {
                        char buf[PREFIX_STRLEN];
+
                        zlog_err("%s: Received prefix %s which we do not know about",
                                 __PRETTY_FUNCTION__,
-                                prefix2str(&dest_addr, buf, strlen(buf)));
+                                prefix2str(&dest_addr, buf, sizeof(buf)));
+                       eigrp_IPv4_InternalTLV_free(tlv);
                        continue;
                }
 
index 00438f2f47c0c2f7d69e19b4ac84a2b9ce75d853..f18d39d575679d09e0ebe6e0ae56b9133bab94ab 100644 (file)
@@ -366,6 +366,7 @@ void eigrp_zebra_route_add(struct prefix *p, struct list *successors)
 
        memset(&api, 0, sizeof(api));
        api.vrf_id = VRF_DEFAULT;
+       api.nh_vrf_id = VRF_DEFAULT;
        api.type = ZEBRA_ROUTE_EIGRP;
        api.safi = SAFI_UNICAST;
        memcpy(&api.prefix, p, sizeof(*p));
@@ -407,6 +408,7 @@ void eigrp_zebra_route_delete(struct prefix *p)
 
        memset(&api, 0, sizeof(api));
        api.vrf_id = VRF_DEFAULT;
+       api.nh_vrf_id = VRF_DEFAULT;
        api.type = ZEBRA_ROUTE_EIGRP;
        api.safi = SAFI_UNICAST;
        memcpy(&api.prefix, p, sizeof(*p));
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 30679367c04df30af569d36be28161dd86b4fbc8..0b7dc86ad6c88f58294d58ec3a0562135d965ddc 100644 (file)
@@ -676,7 +676,8 @@ int isis_circuit_up(struct isis_circuit *circuit)
 
        circuit->lsp_queue = list_new();
        circuit->lsp_hash = isis_lsp_hash_new();
-       circuit->lsp_queue_last_push = monotime(NULL);
+       circuit->lsp_queue_last_push[0] = circuit->lsp_queue_last_push[1] =
+               monotime(NULL);
 
        return ISIS_OK;
 }
index ac1e15f6bf6f16035b52621df0933a789855bb54..ab181189a983186719b0b4d4ebce136540c12824 100644 (file)
@@ -84,7 +84,7 @@ struct isis_circuit {
        struct thread *t_send_lsp;
        struct list *lsp_queue; /* LSPs to be txed (both levels) */
        struct isis_lsp_hash *lsp_hash; /* Hashtable synchronized with lsp_queue */
-       time_t lsp_queue_last_push;    /* timestamp used to enforce transmit
+       time_t lsp_queue_last_push[2]; /* timestamp used to enforce transmit
                                        * interval;
                                        * for scalability, use one timestamp per
                                        * circuit, instead of one per lsp per
index ff9114c506a63131ba3d4c6c2467105eb0cefeeb..614f46c78bb6795dcd63be2b9e2f7963b6d7c284 100644 (file)
@@ -1873,12 +1873,12 @@ int lsp_tick(struct thread *thread)
                                        if (!circuit->lsp_queue)
                                                continue;
 
-                                       if (now - circuit->lsp_queue_last_push
+                                       if (now - circuit->lsp_queue_last_push[level]
                                            < MIN_LSP_RETRANS_INTERVAL) {
                                                continue;
                                        }
 
-                                       circuit->lsp_queue_last_push = now;
+                                       circuit->lsp_queue_last_push[level] = now;
 
                                        for (ALL_LIST_ELEMENTS_RO(
                                                     lsp_list, lspnode, lsp)) {
index 3008fb6a1eb1805c3b3e7317381f2080a6efd12e..a076bb555c2cf64994ad86fd44a65922a9e5d812 100644 (file)
@@ -1249,7 +1249,7 @@ static void init_spt(struct isis_spftree *spftree, int mtid, int level,
 }
 
 static int isis_run_spf(struct isis_area *area, int level, int family,
-                       u_char *sysid)
+                       u_char *sysid, struct timeval *nowtv)
 {
        int retval = ISIS_OK;
        struct isis_vertex *vertex;
@@ -1263,9 +1263,8 @@ static int isis_run_spf(struct isis_area *area, int level, int family,
        uint16_t mtid;
 
        /* Get time that can't roll backwards. */
-       monotime(&time_now);
-       start_time = time_now.tv_sec;
-       start_time = (start_time * 1000000) + time_now.tv_usec;
+       start_time = nowtv->tv_sec;
+       start_time = (start_time * 1000000) + nowtv->tv_usec;
 
        if (family == AF_INET)
                spftree = area->spftree[level - 1];
@@ -1372,9 +1371,11 @@ static int isis_run_spf_cb(struct thread *thread)
                           area->area_tag, level);
 
        if (area->ip_circuits)
-               retval = isis_run_spf(area, level, AF_INET, isis->sysid);
+               retval = isis_run_spf(area, level, AF_INET, isis->sysid,
+                       &thread->real);
        if (area->ipv6_circuits)
-               retval = isis_run_spf(area, level, AF_INET6, isis->sysid);
+               retval = isis_run_spf(area, level, AF_INET6, isis->sysid,
+                       &thread->real);
 
        return retval;
 }
@@ -1435,9 +1436,8 @@ int isis_spf_schedule(struct isis_area *area, int level)
                         timer, &area->spf_timer[level - 1]);
 
        if (isis->debugs & DEBUG_SPF_EVENTS)
-               zlog_debug("ISIS-Spf (%s) L%d SPF scheduled %d sec from now",
-                          area->area_tag, level,
-                          area->min_spf_interval[level - 1] - diff);
+               zlog_debug("ISIS-Spf (%s) L%d SPF scheduled %ld sec from now",
+                          area->area_tag, level, timer);
 
        return ISIS_OK;
 }
index 573b81591cf7f0122f26a25ed55bd3db8385fd8a..0512a18a2a4855ae8bf778455c0f58d7cee05ab5 100644 (file)
@@ -261,6 +261,7 @@ static void isis_zebra_route_add_route(struct prefix *prefix,
 
        memset(&api, 0, sizeof(api));
        api.vrf_id = VRF_DEFAULT;
+       api.nh_vrf_id = VRF_DEFAULT;
        api.type = ZEBRA_ROUTE_ISIS;
        api.safi = SAFI_UNICAST;
        api.prefix = *prefix;
@@ -329,6 +330,7 @@ static void isis_zebra_route_del_route(struct prefix *prefix,
 
        memset(&api, 0, sizeof(api));
        api.vrf_id = VRF_DEFAULT;
+       api.nh_vrf_id = VRF_DEFAULT;
        api.type = ZEBRA_ROUTE_ISIS;
        api.safi = SAFI_UNICAST;
        api.prefix = *prefix;
index ee4f0843b7d7079095720e4b8f870c3d08dc70ca..39e20ef7c84d467d2b2081af8823653be3a0df29 100644 (file)
@@ -47,58 +47,58 @@ ldp_vty_debug(struct vty *vty, const char *negate, const char *type_str,
 
                if (dir_str[0] == 'r') {
                        if (negate)
-                               DEBUG_OFF(hello, HELLO_RECV);
+                               DEBUG_OFF(hello, LDP_DEBUG_HELLO_RECV);
                        else
-                               DEBUG_ON(hello, HELLO_RECV);
+                               DEBUG_ON(hello, LDP_DEBUG_HELLO_RECV);
                } else {
                        if (negate)
-                               DEBUG_OFF(hello, HELLO_SEND);
+                               DEBUG_OFF(hello, LDP_DEBUG_HELLO_SEND);
                        else
-                               DEBUG_ON(hello, HELLO_SEND);
+                               DEBUG_ON(hello, LDP_DEBUG_HELLO_SEND);
                }
        } else if (strcmp(type_str, "errors") == 0) {
                if (negate)
-                       DEBUG_OFF(errors, ERRORS);
+                       DEBUG_OFF(errors, LDP_DEBUG_ERRORS);
                else
-                       DEBUG_ON(errors, ERRORS);
+                       DEBUG_ON(errors, LDP_DEBUG_ERRORS);
        } else if (strcmp(type_str, "event") == 0) {
                if (negate)
-                       DEBUG_OFF(event, EVENT);
+                       DEBUG_OFF(event, LDP_DEBUG_EVENT);
                else
-                       DEBUG_ON(event, EVENT);
+                       DEBUG_ON(event, LDP_DEBUG_EVENT);
        } else if (strcmp(type_str, "labels") == 0) {
                if (negate)
-                       DEBUG_OFF(labels, LABELS);
+                       DEBUG_OFF(labels, LDP_DEBUG_LABELS);
                else
-                       DEBUG_ON(labels, LABELS);
+                       DEBUG_ON(labels, LDP_DEBUG_LABELS);
        } else if (strcmp(type_str, "messages") == 0) {
                if (dir_str == NULL)
                        return (CMD_WARNING_CONFIG_FAILED);
 
                if (dir_str[0] == 'r') {
                        if (negate) {
-                               DEBUG_OFF(msg, MSG_RECV);
-                               DEBUG_OFF(msg, MSG_RECV_ALL);
+                               DEBUG_OFF(msg, LDP_DEBUG_MSG_RECV);
+                               DEBUG_OFF(msg, LDP_DEBUG_MSG_RECV_ALL);
                        } else {
-                               DEBUG_ON(msg, MSG_RECV);
+                               DEBUG_ON(msg, LDP_DEBUG_MSG_RECV);
                                if (all)
-                                       DEBUG_ON(msg, MSG_RECV_ALL);
+                                       DEBUG_ON(msg, LDP_DEBUG_MSG_RECV_ALL);
                        }
                } else {
                        if (negate) {
-                               DEBUG_OFF(msg, MSG_SEND);
-                               DEBUG_OFF(msg, MSG_SEND_ALL);
+                               DEBUG_OFF(msg, LDP_DEBUG_MSG_SEND);
+                               DEBUG_OFF(msg, LDP_DEBUG_MSG_SEND_ALL);
                        } else {
-                               DEBUG_ON(msg, MSG_SEND);
+                               DEBUG_ON(msg, LDP_DEBUG_MSG_SEND);
                                if (all)
-                                       DEBUG_ON(msg, MSG_SEND_ALL);
+                                       DEBUG_ON(msg, LDP_DEBUG_MSG_SEND_ALL);
                        }
                }
        } else if (strcmp(type_str, "zebra") == 0) {
                if (negate)
-                       DEBUG_OFF(zebra, ZEBRA);
+                       DEBUG_OFF(zebra, LDP_DEBUG_ZEBRA);
                else
-                       DEBUG_ON(zebra, ZEBRA);
+                       DEBUG_ON(zebra, LDP_DEBUG_ZEBRA);
        }
 
        main_imsg_compose_both(IMSG_DEBUG_UPDATE, &ldp_debug,
@@ -112,27 +112,27 @@ ldp_vty_show_debugging(struct vty *vty)
 {
        vty_out (vty, "LDP debugging status:\n");
 
-       if (LDP_DEBUG(hello, HELLO_RECV))
+       if (LDP_DEBUG(hello, LDP_DEBUG_HELLO_RECV))
                vty_out (vty,"  LDP discovery debugging is on (inbound)\n");
-       if (LDP_DEBUG(hello, HELLO_SEND))
+       if (LDP_DEBUG(hello, LDP_DEBUG_HELLO_SEND))
                vty_out (vty,"  LDP discovery debugging is on (outbound)\n");
-       if (LDP_DEBUG(errors, ERRORS))
+       if (LDP_DEBUG(errors, LDP_DEBUG_ERRORS))
                vty_out (vty, "  LDP errors debugging is on\n");
-       if (LDP_DEBUG(event, EVENT))
+       if (LDP_DEBUG(event, LDP_DEBUG_EVENT))
                vty_out (vty, "  LDP events debugging is on\n");
-       if (LDP_DEBUG(labels, LABELS))
+       if (LDP_DEBUG(labels, LDP_DEBUG_LABELS))
                vty_out (vty, "  LDP labels debugging is on\n");
-       if (LDP_DEBUG(msg, MSG_RECV_ALL))
+       if (LDP_DEBUG(msg, LDP_DEBUG_MSG_RECV_ALL))
                vty_out (vty,
                          "  LDP detailed messages debugging is on (inbound)\n");
-       else if (LDP_DEBUG(msg, MSG_RECV))
+       else if (LDP_DEBUG(msg, LDP_DEBUG_MSG_RECV))
                vty_out (vty,"  LDP messages debugging is on (inbound)\n");
-       if (LDP_DEBUG(msg, MSG_SEND_ALL))
+       if (LDP_DEBUG(msg, LDP_DEBUG_MSG_SEND_ALL))
                vty_out (vty,
                          "  LDP detailed messages debugging is on (outbound)\n");
-       else if (LDP_DEBUG(msg, MSG_SEND))
+       else if (LDP_DEBUG(msg, LDP_DEBUG_MSG_SEND))
                vty_out (vty,"  LDP messages debugging is on (outbound)\n");
-       if (LDP_DEBUG(zebra, ZEBRA))
+       if (LDP_DEBUG(zebra, LDP_DEBUG_ZEBRA))
                vty_out (vty, "  LDP zebra debugging is on\n");
        vty_out (vty, "\n");
 
@@ -144,48 +144,48 @@ ldp_debug_config_write(struct vty *vty)
 {
        int write = 0;
 
-       if (CONF_LDP_DEBUG(hello, HELLO_RECV)) {
+       if (CONF_LDP_DEBUG(hello, LDP_DEBUG_HELLO_RECV)) {
                vty_out (vty,"debug mpls ldp discovery hello recv\n");
                write = 1;
        }
 
-       if (CONF_LDP_DEBUG(hello, HELLO_SEND)) {
+       if (CONF_LDP_DEBUG(hello, LDP_DEBUG_HELLO_SEND)) {
                vty_out (vty,"debug mpls ldp discovery hello sent\n");
                write = 1;
        }
 
-       if (CONF_LDP_DEBUG(errors, ERRORS)) {
+       if (CONF_LDP_DEBUG(errors, LDP_DEBUG_ERRORS)) {
                vty_out (vty, "debug mpls ldp errors\n");
                write = 1;
        }
 
-       if (CONF_LDP_DEBUG(event, EVENT)) {
+       if (CONF_LDP_DEBUG(event, LDP_DEBUG_EVENT)) {
                vty_out (vty, "debug mpls ldp event\n");
                write = 1;
        }
 
-       if (CONF_LDP_DEBUG(labels, LABELS)) {
+       if (CONF_LDP_DEBUG(labels, LDP_DEBUG_LABELS)) {
                vty_out (vty, "debug mpls ldp labels\n");
                write = 1;
        }
 
-       if (CONF_LDP_DEBUG(msg, MSG_RECV_ALL)) {
+       if (CONF_LDP_DEBUG(msg, LDP_DEBUG_MSG_RECV_ALL)) {
                vty_out (vty, "debug mpls ldp messages recv all\n");
                write = 1;
-       } else if (CONF_LDP_DEBUG(msg, MSG_RECV)) {
+       } else if (CONF_LDP_DEBUG(msg, LDP_DEBUG_MSG_RECV)) {
                vty_out (vty, "debug mpls ldp messages recv\n");
                write = 1;
        }
 
-       if (CONF_LDP_DEBUG(msg, MSG_SEND_ALL)) {
+       if (CONF_LDP_DEBUG(msg, LDP_DEBUG_MSG_SEND_ALL)) {
                vty_out (vty, "debug mpls ldp messages sent all\n");
                write = 1;
-       } else if (CONF_LDP_DEBUG(msg, MSG_SEND)) {
+       } else if (CONF_LDP_DEBUG(msg, LDP_DEBUG_MSG_SEND)) {
                vty_out (vty, "debug mpls ldp messages sent\n");
                write = 1;
        }
 
-       if (CONF_LDP_DEBUG(zebra, ZEBRA)) {
+       if (CONF_LDP_DEBUG(zebra, LDP_DEBUG_ZEBRA)) {
                vty_out (vty, "debug mpls ldp zebra\n");
                write = 1;
        }
index a0972cea8e663b04cdc93b087dc8e0f928f52420..8ae144d93a3d6c9cac298c9220471bc16cd47bf3 100644 (file)
@@ -46,11 +46,11 @@ struct ldp_debug {
 extern struct ldp_debug         conf_ldp_debug;
 extern struct ldp_debug         ldp_debug;
 
-#define CONF_DEBUG_ON(a, b)    (conf_ldp_debug.a |= (LDP_DEBUG_ ## b))
-#define CONF_DEBUG_OFF(a, b)   (conf_ldp_debug.a &= ~(LDP_DEBUG_ ## b))
+#define CONF_DEBUG_ON(a, b)    (conf_ldp_debug.a |= (b))
+#define CONF_DEBUG_OFF(a, b)   (conf_ldp_debug.a &= ~(b))
 
-#define TERM_DEBUG_ON(a, b)    (ldp_debug.a |= (LDP_DEBUG_ ## b))
-#define TERM_DEBUG_OFF(a, b)   (ldp_debug.a &= ~(LDP_DEBUG_ ## b))
+#define TERM_DEBUG_ON(a, b)    (ldp_debug.a |= (b))
+#define TERM_DEBUG_OFF(a, b)   (ldp_debug.a &= ~(b))
 
 #define DEBUG_ON(a, b)                 \
     do {                               \
@@ -66,48 +66,48 @@ extern struct ldp_debug      ldp_debug;
        TERM_DEBUG_OFF(a, b);           \
     } while (0)
 
-#define LDP_DEBUG(a, b)                (ldp_debug.a & LDP_DEBUG_ ## b)
-#define CONF_LDP_DEBUG(a, b)    (conf_ldp_debug.a & LDP_DEBUG_ ## b)
+#define LDP_DEBUG(a, b)                (ldp_debug.a & b)
+#define CONF_LDP_DEBUG(a, b)    (conf_ldp_debug.a & b)
 
 #define                 debug_hello_recv(emsg, ...)                            \
 do {                                                                   \
-       if (LDP_DEBUG(hello, HELLO_RECV))                               \
+       if (LDP_DEBUG(hello, LDP_DEBUG_HELLO_RECV))                     \
                log_debug("discovery[recv]: " emsg, __VA_ARGS__);       \
 } while (0)
 
 #define                 debug_hello_send(emsg, ...)                            \
 do {                                                                   \
-       if (LDP_DEBUG(hello, HELLO_SEND))                               \
+       if (LDP_DEBUG(hello, LDP_DEBUG_HELLO_SEND))                     \
                log_debug("discovery[send]: " emsg, __VA_ARGS__);       \
 } while (0)
 
 #define                 debug_err(emsg, ...)                                   \
 do {                                                                   \
-       if (LDP_DEBUG(errors, ERRORS))                                  \
+       if (LDP_DEBUG(errors, LDP_DEBUG_ERRORS))                        \
                log_debug("error: " emsg, __VA_ARGS__);                 \
 } while (0)
 
 #define                 debug_evt(emsg, ...)                                   \
 do {                                                                   \
-       if (LDP_DEBUG(event, EVENT))                                    \
+       if (LDP_DEBUG(event, LDP_DEBUG_EVENT))                          \
                log_debug("event: " emsg, __VA_ARGS__);                 \
 } while (0)
 
 #define                 debug_labels(emsg, ...)                                \
 do {                                                                   \
-       if (LDP_DEBUG(labels, LABELS))                                  \
+       if (LDP_DEBUG(labels, LDP_DEBUG_LABELS))                        \
                log_debug("labels: " emsg, __VA_ARGS__);                \
 } while (0)
 
 #define                 debug_msg_recv(emsg, ...)                              \
 do {                                                                   \
-       if (LDP_DEBUG(msg, MSG_RECV))                                   \
+       if (LDP_DEBUG(msg, LDP_DEBUG_MSG_RECV))                         \
                log_debug("msg[in]: " emsg, __VA_ARGS__);               \
 } while (0)
 
 #define                 debug_msg_send(emsg, ...)                              \
 do {                                                                   \
-       if (LDP_DEBUG(msg, MSG_SEND))                                   \
+       if (LDP_DEBUG(msg, LDP_DEBUG_MSG_SEND))                         \
                log_debug("msg[out]: " emsg, __VA_ARGS__);              \
 } while (0)
 
@@ -121,25 +121,25 @@ do {                                                                      \
 
 #define                 debug_kalive_recv(emsg, ...)                           \
 do {                                                                   \
-       if (LDP_DEBUG(msg, MSG_RECV_ALL))                               \
+       if (LDP_DEBUG(msg, LDP_DEBUG_MSG_RECV_ALL))                     \
                log_debug("kalive[in]: " emsg, __VA_ARGS__);            \
 } while (0)
 
 #define                 debug_kalive_send(emsg, ...)                           \
 do {                                                                   \
-       if (LDP_DEBUG(msg, MSG_SEND_ALL))                               \
+       if (LDP_DEBUG(msg, LDP_DEBUG_MSG_SEND_ALL))                     \
                log_debug("kalive[out]: " emsg, __VA_ARGS__);           \
 } while (0)
 
 #define                 debug_zebra_in(emsg, ...)                              \
 do {                                                                   \
-       if (LDP_DEBUG(zebra, ZEBRA))                                    \
+       if (LDP_DEBUG(zebra, LDP_DEBUG_ZEBRA))                          \
                log_debug("zebra[in]: " emsg, __VA_ARGS__);             \
 } while (0)
 
 #define                 debug_zebra_out(emsg, ...)                             \
 do {                                                                   \
-       if (LDP_DEBUG(zebra, ZEBRA))                                    \
+       if (LDP_DEBUG(zebra, LDP_DEBUG_ZEBRA))                          \
                log_debug("zebra[out]: " emsg, __VA_ARGS__);            \
 } while (0)
 
index 42dd1c5325d9e517bb19e0421de9f228b0668290..fa8323bf2ddb5a49d8e0d8847589bd41c385849f 100644 (file)
@@ -190,7 +190,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
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 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 861f7a5f0c2ea8659752e2b750cf4e895022fe1f..d4df5130e7e33e40d04da993e9f4fec731896cb6 100644 (file)
@@ -47,46 +47,43 @@ void frrzmq_finish(void)
        }
 }
 
-/* read callback integration */
-struct frrzmq_cb {
-       struct thread *thread;
-       void *zmqsock;
-       void *arg;
-       int fd;
-
-       bool cancelled;
-
-       void (*cb_msg)(void *arg, void *zmqsock);
-       void (*cb_part)(void *arg, void *zmqsock,
-                       zmq_msg_t *msg, unsigned partnum);
-};
-
-
 static int frrzmq_read_msg(struct thread *t)
 {
-       struct frrzmq_cb *cb = THREAD_ARG(t);
+       struct frrzmq_cb **cbp = THREAD_ARG(t);
+       struct frrzmq_cb *cb;
        zmq_msg_t msg;
        unsigned partno;
+       unsigned char read = 0;
        int ret, more;
        size_t moresz;
 
+       if (!cbp)
+               return 1;
+       cb = (*cbp);
+       if (!cb || !cb->zmqsock)
+               return 1;
+
        while (1) {
-               zmq_pollitem_t polli = {
-                       .socket = cb->zmqsock,
-                       .events = ZMQ_POLLIN
-               };
+               zmq_pollitem_t polli = {.socket = cb->zmqsock,
+                                       .events = ZMQ_POLLIN};
                ret = zmq_poll(&polli, 1, 0);
 
                if (ret < 0)
                        goto out_err;
+
                if (!(polli.revents & ZMQ_POLLIN))
                        break;
 
-               if (cb->cb_msg) {
-                       cb->cb_msg(cb->arg, cb->zmqsock);
+               if (cb->read.cb_msg) {
+                       cb->read.cb_msg(cb->read.arg, cb->zmqsock);
+                       read = 1;
 
-                       if (cb->cancelled) {
-                               XFREE(MTYPE_ZEROMQ_CB, cb);
+                       if (cb->read.cancelled) {
+                               frrzmq_check_events(cbp, &cb->write,
+                                                   ZMQ_POLLOUT);
+                               cb->read.thread = NULL;
+                               if (cb->write.cancelled && !cb->write.thread)
+                                       XFREE(MTYPE_ZEROMQ_CB, cb);
                                return 0;
                        }
                        continue;
@@ -104,11 +101,17 @@ static int frrzmq_read_msg(struct thread *t)
                                zmq_msg_close(&msg);
                                goto out_err;
                        }
+                       read = 1;
 
-                       cb->cb_part(cb->arg, cb->zmqsock, &msg, partno);
-                       if (cb->cancelled) {
+                       cb->read.cb_part(cb->read.arg, cb->zmqsock, &msg,
+                                        partno);
+                       if (cb->read.cancelled) {
                                zmq_msg_close(&msg);
-                               XFREE(MTYPE_ZEROMQ_CB, cb);
+                               frrzmq_check_events(cbp, &cb->write,
+                                                   ZMQ_POLLOUT);
+                               cb->read.thread = NULL;
+                               if (cb->write.cancelled && !cb->write.thread)
+                                       XFREE(MTYPE_ZEROMQ_CB, cb);
                                return 0;
                        }
 
@@ -116,8 +119,8 @@ static int frrzmq_read_msg(struct thread *t)
                         * message; don't use zmq_msg_more here */
                        moresz = sizeof(more);
                        more = 0;
-                       ret = zmq_getsockopt(cb->zmqsock, ZMQ_RCVMORE,
-                                            &more, &moresz);
+                       ret = zmq_getsockopt(cb->zmqsock, ZMQ_RCVMORE, &more,
+                                            &moresz);
                        if (ret < 0) {
                                zmq_msg_close(&msg);
                                goto out_err;
@@ -128,64 +131,221 @@ static int frrzmq_read_msg(struct thread *t)
                zmq_msg_close(&msg);
        }
 
-       funcname_thread_add_read_write(THREAD_READ, t->master, frrzmq_read_msg,
-                       cb, cb->fd, &cb->thread, t->funcname, t->schedfrom,
-                       t->schedfrom_line);
+       if (read)
+               frrzmq_check_events(cbp, &cb->write, ZMQ_POLLOUT);
+
+       funcname_thread_add_read_write(
+               THREAD_READ, t->master, frrzmq_read_msg, cbp, cb->fd,
+               &cb->read.thread, t->funcname, t->schedfrom, t->schedfrom_line);
        return 0;
 
 out_err:
-       zlog_err("ZeroMQ error: %s(%d)", strerror (errno), errno);
-       return 0;
+       zlog_err("ZeroMQ read error: %s(%d)", strerror(errno), errno);
+       if (cb->read.cb_error)
+               cb->read.cb_error(cb->read.arg, cb->zmqsock);
+       return 1;
 }
 
-struct frrzmq_cb *funcname_frrzmq_thread_add_read(
-               struct thread_master *master,
-               void (*msgfunc)(void *arg, void *zmqsock),
-               void (*partfunc)(void *arg, void *zmqsock,
-                                zmq_msg_t *msg, unsigned partnum),
-               void *arg, void *zmqsock, debugargdef)
+int funcname_frrzmq_thread_add_read(struct thread_master *master,
+                                   void (*msgfunc)(void *arg, void *zmqsock),
+                                   void (*partfunc)(void *arg, void *zmqsock,
+                                                    zmq_msg_t *msg,
+                                                    unsigned partnum),
+                                   void (*errfunc)(void *arg, void *zmqsock),
+                                   void *arg, void *zmqsock,
+                                   struct frrzmq_cb **cbp, debugargdef)
 {
        int fd, events;
        size_t len;
        struct frrzmq_cb *cb;
 
+       if (!cbp)
+               return -1;
        if (!(msgfunc || partfunc) || (msgfunc && partfunc))
-               return NULL;
+               return -1;
+       len = sizeof(fd);
+       if (zmq_getsockopt(zmqsock, ZMQ_FD, &fd, &len))
+               return -1;
+       len = sizeof(events);
+       if (zmq_getsockopt(zmqsock, ZMQ_EVENTS, &events, &len))
+               return -1;
+
+       if (*cbp)
+               cb = *cbp;
+       else {
+               cb = XCALLOC(MTYPE_ZEROMQ_CB, sizeof(struct frrzmq_cb));
+               cb->write.cancelled = 1;
+               if (!cb)
+                       return -1;
+               *cbp = cb;
+       }
+
+       cb->zmqsock = zmqsock;
+       cb->fd = fd;
+       cb->read.arg = arg;
+       cb->read.cb_msg = msgfunc;
+       cb->read.cb_part = partfunc;
+       cb->read.cb_error = errfunc;
+       cb->read.cancelled = 0;
+
+       if (events & ZMQ_POLLIN) {
+               if (cb->read.thread) {
+                       thread_cancel(cb->read.thread);
+                       cb->read.thread = NULL;
+               }
+               funcname_thread_add_event(master, frrzmq_read_msg, cbp, fd,
+                                         &cb->read.thread, funcname, schedfrom,
+                                         fromln);
+       } else
+               funcname_thread_add_read_write(
+                       THREAD_READ, master, frrzmq_read_msg, cbp, fd,
+                       &cb->read.thread, funcname, schedfrom, fromln);
+       return 0;
+}
+
+static int frrzmq_write_msg(struct thread *t)
+{
+       struct frrzmq_cb **cbp = THREAD_ARG(t);
+       struct frrzmq_cb *cb;
+       unsigned char written = 0;
+       int ret;
+
+       if (!cbp)
+               return 1;
+       cb = (*cbp);
+       if (!cb || !cb->zmqsock)
+               return 1;
+
+       while (1) {
+               zmq_pollitem_t polli = {.socket = cb->zmqsock,
+                                       .events = ZMQ_POLLOUT};
+               ret = zmq_poll(&polli, 1, 0);
+
+               if (ret < 0)
+                       goto out_err;
+
+               if (!(polli.revents & ZMQ_POLLOUT))
+                       break;
+
+               if (cb->write.cb_msg) {
+                       cb->write.cb_msg(cb->write.arg, cb->zmqsock);
+                       written = 1;
+
+                       if (cb->write.cancelled) {
+                               frrzmq_check_events(cbp, &cb->read, ZMQ_POLLIN);
+                               cb->write.thread = NULL;
+                               if (cb->read.cancelled && !cb->read.thread)
+                                       XFREE(MTYPE_ZEROMQ_CB, cb);
+                               return 0;
+                       }
+                       continue;
+               }
+       }
+
+       if (written)
+               frrzmq_check_events(cbp, &cb->read, ZMQ_POLLIN);
+
+       funcname_thread_add_read_write(THREAD_WRITE, t->master,
+                                      frrzmq_write_msg, cbp, cb->fd,
+                                      &cb->write.thread, t->funcname,
+                                      t->schedfrom, t->schedfrom_line);
+       return 0;
+
+out_err:
+       zlog_err("ZeroMQ write error: %s(%d)", strerror(errno), errno);
+       if (cb->write.cb_error)
+               cb->write.cb_error(cb->write.arg, cb->zmqsock);
+       return 1;
+}
+int funcname_frrzmq_thread_add_write(struct thread_master *master,
+                                    void (*msgfunc)(void *arg, void *zmqsock),
+                                    void (*errfunc)(void *arg, void *zmqsock),
+                                    void *arg, void *zmqsock,
+                                    struct frrzmq_cb **cbp, debugargdef)
+{
+       int fd, events;
+       size_t len;
+       struct frrzmq_cb *cb;
+
+       if (!cbp)
+               return -1;
+       if (!msgfunc)
+               return -1;
        len = sizeof(fd);
        if (zmq_getsockopt(zmqsock, ZMQ_FD, &fd, &len))
-               return NULL;
+               return -1;
        len = sizeof(events);
        if (zmq_getsockopt(zmqsock, ZMQ_EVENTS, &events, &len))
-               return NULL;
+               return -1;
 
-       cb = XCALLOC(MTYPE_ZEROMQ_CB, sizeof(struct frrzmq_cb));
-       if (!cb)
-               return NULL;
+       if (*cbp)
+               cb = *cbp;
+       else {
+               cb = XCALLOC(MTYPE_ZEROMQ_CB, sizeof(struct frrzmq_cb));
+               cb->read.cancelled = 1;
+               if (!cb)
+                       return -1;
+               *cbp = cb;
+       }
 
-       cb->arg = arg;
        cb->zmqsock = zmqsock;
-       cb->cb_msg = msgfunc;
-       cb->cb_part = partfunc;
        cb->fd = fd;
+       cb->write.arg = arg;
+       cb->write.cb_msg = msgfunc;
+       cb->write.cb_part = NULL;
+       cb->write.cb_error = errfunc;
+       cb->write.cancelled = 0;
+
+       if (events & ZMQ_POLLOUT) {
+               if (cb->write.thread) {
+                       thread_cancel(cb->write.thread);
+                       cb->write.thread = NULL;
+               }
+               funcname_thread_add_event(master, frrzmq_write_msg, cbp, fd,
+                                         &cb->write.thread, funcname,
+                                         schedfrom, fromln);
+       } else
+               funcname_thread_add_read_write(
+                       THREAD_WRITE, master, frrzmq_write_msg, cbp, fd,
+                       &cb->write.thread, funcname, schedfrom, fromln);
+       return 0;
+}
 
-       if (events & ZMQ_POLLIN)
-               funcname_thread_add_event(master,
-                               frrzmq_read_msg, cb, fd, &cb->thread,
-                               funcname, schedfrom, fromln);
-       else
-               funcname_thread_add_read_write(THREAD_READ, master,
-                               frrzmq_read_msg, cb, fd, &cb->thread,
-                               funcname, schedfrom, fromln);
-       return cb;
+void frrzmq_thread_cancel(struct frrzmq_cb **cb, struct cb_core *core)
+{
+       if (!cb || !*cb)
+               return;
+       core->cancelled = 1;
+       if (core->thread) {
+               thread_cancel(core->thread);
+               core->thread = NULL;
+       }
+       if ((*cb)->read.cancelled && !(*cb)->read.thread
+           && (*cb)->write.cancelled && (*cb)->write.thread)
+               XFREE(MTYPE_ZEROMQ_CB, *cb);
 }
 
-void frrzmq_thread_cancel(struct frrzmq_cb *cb)
+void frrzmq_check_events(struct frrzmq_cb **cbp, struct cb_core *core,
+                        int event)
 {
-       if (!cb->thread) {
-               /* canceling from within callback */
-               cb->cancelled = 1;
+       struct frrzmq_cb *cb;
+       int events;
+       size_t len;
+
+       if (!cbp)
+               return;
+       cb = (*cbp);
+       if (!cb || !cb->zmqsock)
+               return;
+
+       if (zmq_getsockopt(cb->zmqsock, ZMQ_EVENTS, &events, &len))
                return;
+       if (events & event && core->thread && !core->cancelled) {
+               struct thread_master *tm = core->thread->master;
+               thread_cancel(core->thread);
+               core->thread = NULL;
+               thread_add_event(tm, (event == ZMQ_POLLIN ? frrzmq_read_msg
+                                                         : frrzmq_write_msg),
+                                cbp, cb->fd, &core->thread);
        }
-       thread_cancel(cb->thread);
-       XFREE(MTYPE_ZEROMQ_CB, cb);
 }
index 69c6f8580dbb6bb68adc69a8af191d8a295ac6dd..1146b879640c87ba66e17c3b7b01c2919a1108b2 100644 (file)
  *   foo_LDFLAGS = libfrrzmq.la libfrr.la $(ZEROMQ_LIBS)
  */
 
+/* callback integration */
+struct cb_core {
+       struct thread *thread;
+       void *arg;
+
+       bool cancelled;
+
+       void (*cb_msg)(void *arg, void *zmqsock);
+       void (*cb_part)(void *arg, void *zmqsock, zmq_msg_t *msg,
+                       unsigned partnum);
+       void (*cb_error)(void *arg, void *zmqsock);
+};
+struct frrzmq_cb {
+       void *zmqsock;
+       int fd;
+
+       struct cb_core read;
+       struct cb_core write;
+};
+
 /* libzmq's context
  *
  * this is mostly here as a convenience, it has IPv6 enabled but nothing
  */
 extern void *frrzmq_context;
 
-extern void frrzmq_init (void);
-extern void frrzmq_finish (void);
+extern void frrzmq_init(void);
+extern void frrzmq_finish(void);
 
 #define debugargdef const char *funcname, const char *schedfrom, int fromln
 
 /* core event registration, one of these 2 macros should be used */
-#define frrzmq_thread_add_read_msg(m,f,a,z) funcname_frrzmq_thread_add_read( \
-                               m,f,NULL,a,z,#f,__FILE__,__LINE__)
-#define frrzmq_thread_add_read_part(m,f,a,z) funcname_frrzmq_thread_add_read( \
-                               m,NULL,f,a,z,#f,__FILE__,__LINE__)
+#define frrzmq_thread_add_read_msg(m, f, e, a, z, d)                           \
+       funcname_frrzmq_thread_add_read(m, f, NULL, e, a, z, d, #f, __FILE__,  \
+                                       __LINE__)
+#define frrzmq_thread_add_read_part(m, f, e, a, z, d)                          \
+       funcname_frrzmq_thread_add_read(m, NULL, f, e, a, z, d, #f, __FILE__,  \
+                                       __LINE__)
+#define frrzmq_thread_add_write_msg(m, f, e, a, z, d)                          \
+       funcname_frrzmq_thread_add_write(m, f, e, a, z, d, #f, __FILE__,       \
+                                        __LINE__)
 
+struct cb_core;
 struct frrzmq_cb;
 
-/* Set up a POLLIN notification to be called from the libfrr main loop.
- * This has the following properties:
+/* Set up a POLLIN or POLLOUT notification to be called from the libfrr main
+ * loop. This has the following properties:
  *
  * - since ZeroMQ works with edge triggered notifications, it will loop and
  *   dispatch as many events as ZeroMQ has pending at the time libfrr calls
@@ -67,22 +93,35 @@ struct frrzmq_cb;
  *   - if partfunc is specified, the message is read and partfunc is called
  *     for each ZeroMQ multi-part subpart.  Note that you can't send replies
  *     before all parts have been read because that violates the ZeroMQ FSM.
+ * - write version doesn't allow for partial callback, you must handle the
+ *   whole message (all parts) in msgfunc callback
  * - you can safely cancel the callback from within itself
  * - installing a callback will check for pending events (ZMQ_EVENTS) and
  *   may schedule the event to run as soon as libfrr is back in its main
  *   loop.
+ */
+extern int funcname_frrzmq_thread_add_read(
+       struct thread_master *master, void (*msgfunc)(void *arg, void *zmqsock),
+       void (*partfunc)(void *arg, void *zmqsock, zmq_msg_t *msg,
+                        unsigned partnum),
+       void (*errfunc)(void *arg, void *zmqsock), void *arg, void *zmqsock,
+       struct frrzmq_cb **cb, debugargdef);
+extern int funcname_frrzmq_thread_add_write(
+       struct thread_master *master, void (*msgfunc)(void *arg, void *zmqsock),
+       void (*errfunc)(void *arg, void *zmqsock), void *arg, void *zmqsock,
+       struct frrzmq_cb **cb, debugargdef);
+
+extern void frrzmq_thread_cancel(struct frrzmq_cb **cb, struct cb_core *core);
+
+/*
+ * http://api.zeromq.org/4-2:zmq-getsockopt#toc10
  *
- * TODO #1: add ZMQ_POLLERR / error callback
- * TODO #2: add frrzmq_check_events() function to check for edge triggered
- *          things that may have happened after a zmq_send() call or so
+ * As the descriptor is edge triggered, applications must update the state of
+ * ZMQ_EVENTS after each invocation of zmq_send or zmq_recv.To be more explicit:
+ * after calling zmq_send the socket may become readable (and vice versa)
+ * without triggering a read event on the file descriptor.
  */
-extern struct frrzmq_cb *funcname_frrzmq_thread_add_read(
-               struct thread_master *master,
-               void (*msgfunc)(void *arg, void *zmqsock),
-               void (*partfunc)(void *arg, void *zmqsock,
-                                zmq_msg_t *msg, unsigned partnum),
-               void *arg, void *zmqsock, debugargdef);
-
-extern void frrzmq_thread_cancel(struct frrzmq_cb *cb);
+extern void frrzmq_check_events(struct frrzmq_cb **cbp, struct cb_core *core,
+                               int event);
 
 #endif /* _FRRZMQ_H */
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 7589934b69420e031a91b729adea64d06b3f0e92..bf65ac7c7da4dbd7bc04b02dfe47b9c0457d15a5 100644 (file)
--- a/lib/log.c
+++ b/lib/log.c
@@ -945,6 +945,8 @@ static const struct zebra_desc_table command_types[] = {
        DESC_ENTRY(ZEBRA_ADVERTISE_DEFAULT_GW),
        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),
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..6ef00375e8acc479426657c1a720b3962e4605f3 100644 (file)
@@ -81,6 +81,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
index f6b2c9788d50a4757649f76d12b593ad821cbcbb..f531f27302d772599f4b9919b6a367105eb12b39 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;
@@ -210,12 +210,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..753e66643d14cd34cef6f8d0a27414af9391599e 100644 (file)
@@ -55,13 +55,6 @@ 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;
@@ -80,6 +73,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 +100,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
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..7e947ea48abc01b05a5a426b7b33ec257677b4e6 100644 (file)
@@ -348,6 +348,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 +399,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 e881d49225e48a8f8beeb1513ef6cfb3d079080e..28d26149e5d39afc6f3107c67d8a49d0d4333266 100644 (file)
@@ -223,6 +223,25 @@ int ptm_lib_init_msg(ptm_lib_handle_t *hdl, int cmd_id, int type, void *in_ctxt,
        return 0;
 }
 
+int ptm_lib_cleanup_msg(ptm_lib_handle_t *hdl, void *ctxt)
+{
+       ptm_lib_msg_ctxt_t *p_ctxt = ctxt;
+       csv_t *csv;
+
+       if (!p_ctxt) {
+               ERRLOG("%s: no context \n", __FUNCTION__);
+               return -1;
+       }
+
+       csv = p_ctxt->csv;
+
+       csv_clean(csv);
+       csv_free(csv);
+       free(p_ctxt);
+
+       return 0;
+}
+
 int ptm_lib_complete_msg(ptm_lib_handle_t *hdl, void *ctxt, char *buf, int *len)
 {
        ptm_lib_msg_ctxt_t *p_ctxt = ctxt;
index bc8fe4ac54d3f1ad7c52130d7673c0f7e8aaefa4..fc4d520dcb41b4c188d9340c7ee5a5edf96cc67b 100644 (file)
@@ -63,5 +63,6 @@ int ptm_lib_find_key_in_msg(void *, const char *, char *);
 int ptm_lib_init_msg(ptm_lib_handle_t *, int, int, void *, void **);
 int ptm_lib_append_msg(ptm_lib_handle_t *, void *, const char *, const char *);
 int ptm_lib_complete_msg(ptm_lib_handle_t *, void *, char *, int *);
+int ptm_lib_cleanup_msg(ptm_lib_handle_t *, void *);
 
 #endif
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 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..2fa3a9c0ef512eb67496f20c28172031c6f48584 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)
@@ -225,6 +225,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 +267,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 +355,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));
        }
 }
index e93e9937769437f47c9c97241dca8a4f9a48b8f1..7e625769e7f332c447b6e84387ec7c3c42a3ffd7 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
@@ -103,6 +102,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)                                                    \
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..d3717d0cdd2022a5ab22c35e74edca34a3970658 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) {
@@ -389,25 +389,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 +450,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 +614,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 +945,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);
@@ -940,6 +975,8 @@ int zapi_route_encode(u_char cmd, struct stream *s, struct zapi_route *api)
                }
 
                stream_putw(s, api->nexthop_num);
+               if (api->nexthop_num)
+                       stream_putw(s, api->nh_vrf_id);
 
                for (i = 0; i < api->nexthop_num; i++) {
                        api_nh = &api->nexthops[i];
@@ -1032,6 +1069,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);
@@ -1087,6 +1126,9 @@ int zapi_route_decode(struct stream *s, struct zapi_route *api)
                        return -1;
                }
 
+               if (api->nexthop_num)
+                       STREAM_GETW(s, api->nh_vrf_id);
+
                for (i = 0; i < api->nexthop_num; i++) {
                        api_nh = &api->nexthops[i];
 
@@ -1673,7 +1715,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);
@@ -2039,7 +2081,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 +2247,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,
@@ -2332,9 +2384,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..df9e5f438d001db6630f5c1af6e3d9a3d023b7a0 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
@@ -112,6 +112,8 @@ typedef enum {
        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,
@@ -200,6 +202,8 @@ 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);
        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,7 +227,7 @@ 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;
 };
@@ -277,6 +281,9 @@ struct zapi_route {
        u_int32_t mtu;
 
        vrf_id_t vrf_id;
+       vrf_id_t nh_vrf_id;
+
+       struct ethaddr rmac;
 };
 
 /* Zebra IPv4 route message API. */
@@ -414,6 +421,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,6 +484,9 @@ 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,
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..2f084f8422f3e7268ad998afa78000eb58c5e60e 100644 (file)
@@ -95,6 +95,8 @@ 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.nh_vrf_id = VRF_DEFAULT;
        api.prefix = *p;
 
        switch (type) {
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..b7cd9b4b09af703a939abb1284110c5841636286 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;
index c65578c11e34988c457d5283e23002bbb153661c..745b87b890ed13f527557a19b37dd31a99e09f7d 100644 (file)
@@ -173,11 +173,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 +370,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 +438,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);
        }
@@ -369,10 +626,21 @@ 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_zebra_no_redistribute(type);
+                               ospf6_zebra_redistribute(type);
+                       }
+               } else
                        ospf6->rmap[type].map = NULL;
        }
 }
index 73053452e6a22ac0e838d3dbd604af7e071875a1..7f4665ac2b501645831f610dbbdd2bbb1efba7d2 100644 (file)
@@ -93,5 +93,7 @@ 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);
 
 #endif /* OSPF6_ASBR_H */
index 98f93b06e67431fc0b6e1865088324aa93b479df..fc6c46c7e75d417f87dc199198fcc734acd77d45 100644 (file)
@@ -1008,6 +1008,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 +1938,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..b67d9a9f2e6f55167f56159e3d577e3702db3118 100644 (file)
@@ -117,6 +117,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 82f75b153eb204882b30faace2bd1d3bd501f8a0..cca4616c163323b6385d967e5d93d2639c7770e9 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;
 
index 3536d33d19ab74b1fc57027a38bf1a9f32a57506..db446a328734f4ec95aec29afbbea974f01252bb 100644 (file)
@@ -252,5 +252,6 @@ 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);
 
 #endif /* OSPF6_LSA_H */
index 56c232d6da98bbb90c07f2cef085e5fec8e56ca6..1c3523b43d327fa76a4a21d0cded83a6b13967bd 100644 (file)
@@ -41,4 +41,5 @@ 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_OTHER, "OSPF6 other")
index fe72ee3669763e89cdd4fe490bdb446dc90864e8..548af5e321e7767ae7c60187b0ff977454cf9a8e 100644 (file)
@@ -40,6 +40,7 @@ DECLARE_MTYPE(OSPF6_VERTEX)
 DECLARE_MTYPE(OSPF6_SPFTREE)
 DECLARE_MTYPE(OSPF6_NEXTHOP)
 DECLARE_MTYPE(OSPF6_EXTERNAL_INFO)
+DECLARE_MTYPE(OSPF6_PATH)
 DECLARE_MTYPE(OSPF6_OTHER)
 
 #endif /* _QUAGGA_OSPF6_MEMORY_H */
index 1307b374a511c9d1c7c3bb65ca99b8b40449af1d..d76438ea5033aae81e6c89259946a5bbfdc7bd09 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)) {
@@ -2185,8 +2206,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 +2287,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 +2314,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 3c77c483ea07ea18fb26b930da75db9faf2923fa..735b28a69330ce37c635b0770266d44af28210ab 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);
                        }
                }
        }
@@ -241,18 +241,25 @@ int ospf6_route_cmp_nexthops(struct ospf6_route *a, struct ospf6_route *b)
 {
        struct listnode *anode, *bnode;
        struct ospf6_nexthop *anh, *bnh;
+       bool identical = false;
 
        if (a && b) {
                if (listcount(a->nh_list) == listcount(b->nh_list)) {
                        for (ALL_LIST_ELEMENTS_RO(a->nh_list, anode, anh)) {
+                               identical = false;
                                for (ALL_LIST_ELEMENTS_RO(b->nh_list, bnode,
-                                                         bnh))
-                                       if (!ospf6_nexthop_is_same(anh, bnh))
-                                               return (1);
+                                                         bnh)) {
+                                       if (ospf6_nexthop_is_same(anh, bnh))
+                                               identical = true;
+                               }
+                               /* Currnet List A element not found List B
+                                * Non-Identical lists return */
+                               if (identical == false)
+                                       return 1;
                        }
-                       return (0);
+                       return 0;
                } else
-                       return (1);
+                       return 1;
        }
        /* One of the routes doesn't exist ? */
        return (1);
@@ -331,14 +338,49 @@ 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 &&
-           IN6_ARE_ADDR_EQUAL(&(a)->address, &(b)->address))
+       if (a->ifindex < b->ifindex)
+               return -1;
+       else if (a->ifindex > b->ifindex)
                return 1;
+       else
+               return memcmp(&a->address, &b->address,
+                             sizeof(struct in6_addr));
+
        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;
@@ -346,6 +388,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;
 }
 
@@ -354,6 +399,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);
        }
 }
@@ -452,7 +499,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;
@@ -1071,6 +1124,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 c148107449a6f2f3375b8bcbe2cfa26bdee000ba..a4486459600574938c291689923d09792398d8b6 100644 (file)
@@ -914,7 +914,7 @@ static u_char *ospfv3WwLsdbEntry(struct variable *v, oid *name, size_t *length,
        if (len)
                id = htonl(*offset);
        offset += len;
-       offsetlen -= len;
+       //offsetlen -= len;  // Add back in if we need it again
 
        if (exact) {
                if (v->magic & OSPFv3WWASTABLE) {
@@ -1080,8 +1080,8 @@ static u_char *ospfv3IfEntry(struct variable *v, oid *name, size_t *length,
        len = (offsetlen < 1 ? 0 : 1);
        if (len)
                instid = *offset;
-       offset += len;
-       offsetlen -= len;
+       //offset += len; // Add back in if we ever start using again
+       //offsetlen -= len;
 
        if (exact) {
                oi = ospf6_interface_lookup_by_ifindex(ifindex);
@@ -1241,8 +1241,8 @@ static u_char *ospfv3NbrEntry(struct variable *v, oid *name, size_t *length,
        len = (offsetlen < 1 ? 0 : 1);
        if (len)
                rtrid = htonl(*offset);
-       offset += len;
-       offsetlen -= len;
+       //offset += len; // Add back in if we ever start looking at data
+       //offsetlen -= len;
 
        if (exact) {
                oi = ospf6_interface_lookup_by_ifindex(ifindex);
index 340d90159ff8d2d539a0d154d507c1b3ae5aba85..17ce1771e2a76a3d4b23049ebc5c8e26c46f907b 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,153 @@ 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);
+       if (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..5d1144335be4c27b55d1f6a4bdf96f0017e59167 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);
index cc87c499ee50af6e502bf382aa7907365adae65e..2a419ddfc616ff927d406d9a79083e81c3330434 100644 (file)
@@ -337,6 +337,7 @@ static void ospf6_zebra_route_update(int type, struct ospf6_route *request)
 
        memset(&api, 0, sizeof(api));
        api.vrf_id = VRF_DEFAULT;
+       api.nh_vrf_id = VRF_DEFAULT;
        api.type = ZEBRA_ROUTE_OSPF6;
        api.safi = SAFI_UNICAST;
        api.prefix = *dest;
@@ -387,6 +388,7 @@ void ospf6_zebra_add_discard(struct ospf6_route *request)
        if (!CHECK_FLAG(request->flag, OSPF6_ROUTE_BLACKHOLE_ADDED)) {
                memset(&api, 0, sizeof(api));
                api.vrf_id = VRF_DEFAULT;
+               api.nh_vrf_id = VRF_DEFAULT;
                api.type = ZEBRA_ROUTE_OSPF6;
                api.safi = SAFI_UNICAST;
                api.prefix = *dest;
@@ -420,6 +422,7 @@ void ospf6_zebra_delete_discard(struct ospf6_route *request)
        if (CHECK_FLAG(request->flag, OSPF6_ROUTE_BLACKHOLE_ADDED)) {
                memset(&api, 0, sizeof(api));
                api.vrf_id = VRF_DEFAULT;
+               api.nh_vrf_id = VRF_DEFAULT;
                api.type = ZEBRA_ROUTE_OSPF6;
                api.safi = SAFI_UNICAST;
                api.prefix = *dest;
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 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 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..1bd6bf8d4c656b2690cfbe2fb29c4461481ed762 100644 (file)
@@ -589,30 +589,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);
index 65e9cac8371154fe27b3cc31f0958ddadfa78645..86703596102111d31a6a6c58ed874db8f5a22069 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;
                        }
                }
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..22fff1b53d50b0d603986de89a1ccf51c0e78081 100644 (file)
@@ -1463,9 +1463,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,
index c4289fb3ce4a576f2a6d463506e7e75d0ea4ab93..c923a6f35e8a9f9c5709be462f53b7e900e80d19 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);
@@ -449,7 +449,7 @@ DEFUN (ospf_passive_interface,
 {
        VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
        int idx_ipv4 = 2;
-       struct interface *ifp;
+       struct interface *ifp = NULL;
        struct in_addr addr = {.s_addr = INADDR_ANY};
        int ret;
        struct ospf_if_params *params;
@@ -459,12 +459,13 @@ DEFUN (ospf_passive_interface,
                ospf_passive_interface_default(ospf, OSPF_IF_PASSIVE);
                return CMD_SUCCESS;
        }
+       if (ospf->vrf_id != VRF_UNKNOWN)
+               ifp = if_get_by_name(argv[1]->arg, ospf->vrf_id, 0);
 
-       ifp = if_get_by_name(argv[1]->arg, ospf->vrf_id, 0);
        if (ifp == NULL) {
                vty_out(vty, "interface %s not found.\n",
                        (char *)argv[1]->arg);
-               return CMD_WARNING;
+               return CMD_WARNING_CONFIG_FAILED;
        }
 
        params = IF_DEF_PARAMS(ifp);
@@ -521,7 +522,7 @@ DEFUN (no_ospf_passive_interface,
 {
        VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
        int idx_ipv4 = 3;
-       struct interface *ifp;
+       struct interface *ifp = NULL;
        struct in_addr addr = {.s_addr = INADDR_ANY};
        struct ospf_if_params *params;
        int ret;
@@ -532,11 +533,13 @@ DEFUN (no_ospf_passive_interface,
                return CMD_SUCCESS;
        }
 
-       ifp = if_get_by_name(argv[2]->arg, ospf->vrf_id, 0);
+       if (ospf->vrf_id != VRF_UNKNOWN)
+               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);
-               return CMD_WARNING;
+                       (char *)argv[2]->arg);
+               return CMD_WARNING_CONFIG_FAILED;
        }
 
        params = IF_DEF_PARAMS(ifp);
@@ -616,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;
@@ -1971,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);
@@ -3689,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) {
@@ -3710,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 {
@@ -3737,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);
+                       }
                }
        }
 
@@ -4279,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) {
@@ -4299,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) {
@@ -4677,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)
@@ -6163,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");
                        }
@@ -6185,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");
                }
@@ -8095,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"
@@ -8128,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);
@@ -8144,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
@@ -8334,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"
@@ -8357,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);
@@ -8379,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"
@@ -9492,9 +9529,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);
                        }
 
@@ -9518,9 +9555,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)
@@ -9579,7 +9616,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++;
 
@@ -9593,7 +9630,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);
@@ -10198,8 +10236,12 @@ 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");
+                               else if (red->dmetric.type ==
+                                               EXTERNAL_METRIC_TYPE_2)
+                                       vty_out(vty, " metric-type 2");
 
                                if (ROUTEMAP_NAME(red))
                                        vty_out(vty, " route-map %s",
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..58e8a921d51f8f8d46862214b68de065024881d6 100644 (file)
@@ -389,6 +389,7 @@ void ospf_zebra_add(struct ospf *ospf, struct prefix_ipv4 *p,
 
        memset(&api, 0, sizeof(api));
        api.vrf_id = ospf->vrf_id;
+       api.nh_vrf_id = ospf->vrf_id;
        api.type = ZEBRA_ROUTE_OSPF;
        api.instance = ospf->instance;
        api.safi = SAFI_UNICAST;
@@ -466,6 +467,7 @@ void ospf_zebra_delete(struct ospf *ospf, struct prefix_ipv4 *p,
 
        memset(&api, 0, sizeof(api));
        api.vrf_id = ospf->vrf_id;
+       api.nh_vrf_id = ospf->vrf_id;
        api.type = ZEBRA_ROUTE_OSPF;
        api.instance = ospf->instance;
        api.safi = SAFI_UNICAST;
@@ -487,6 +489,7 @@ void ospf_zebra_add_discard(struct ospf *ospf, struct prefix_ipv4 *p)
 
        memset(&api, 0, sizeof(api));
        api.vrf_id = ospf->vrf_id;
+       api.nh_vrf_id = ospf->vrf_id;
        api.type = ZEBRA_ROUTE_OSPF;
        api.instance = ospf->instance;
        api.safi = SAFI_UNICAST;
@@ -506,6 +509,7 @@ void ospf_zebra_delete_discard(struct ospf *ospf, struct prefix_ipv4 *p)
 
        memset(&api, 0, sizeof(api));
        api.vrf_id = ospf->vrf_id;
+       api.nh_vrf_id = ospf->vrf_id;
        api.type = ZEBRA_ROUTE_OSPF;
        api.instance = ospf->instance;
        api.safi = SAFI_UNICAST;
index ceb8440eebd9707d07e0bda90ae598abeca3f2c8..e6f19369ef5b87f450a2bee27bd4e34fa8a78a05 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
@@ -693,9 +707,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 +844,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 +1044,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 +2027,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 +2037,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 +2050,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 +2059,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 10b68ab73594f5242e44539b61b5ce235c1136ea..76ba505ad4c15b85d0be965a14334a3d7f30f18c 100644 (file)
@@ -7333,6 +7333,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 +7348,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 +7489,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 +7511,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 +7590,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 +7604,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,
index b2a8a6ff8f14867bb8386eb4833000242aae2c4c..f02cf7ed31c4555688646f64cb570e68268841cf 100644 (file)
@@ -205,6 +205,7 @@ struct pim_interface *pim_if_new(struct interface *ifp, int igmp, int pim)
        if (!pim_ifp->sec_addr_list) {
                zlog_err("%s: failure: secondary addresslist",
                         __PRETTY_FUNCTION__);
+               return if_list_clean(pim_ifp);
        }
        pim_ifp->sec_addr_list->del = (void (*)(void *))pim_sec_addr_free;
        pim_ifp->sec_addr_list->cmp =
index 5f597b17b1b0f009138644a3fb8ae2f31da7d93a..7d3b783adf63569ce3e6119edfa7dbfece5a7c38 100644 (file)
@@ -640,6 +640,13 @@ static int on_ifjoin_prune_pending_timer(struct thread *t)
 
        ch = THREAD_ARG(t);
 
+       if (PIM_DEBUG_TRACE)
+               zlog_debug("%s: IFCHANNEL%s %s Prune Pending Timer Popped",
+                          __PRETTY_FUNCTION__,
+                          pim_str_sg_dump(&ch->sg),
+                          pim_ifchannel_ifjoin_name(ch->ifjoin_state,
+                                                    ch->flags));
+
        if (ch->ifjoin_state == PIM_IFJOIN_PRUNE_PENDING) {
                ifp = ch->interface;
                pim_ifp = ifp->info;
@@ -665,16 +672,19 @@ static int on_ifjoin_prune_pending_timer(struct thread *t)
                         *  message on RP path upon prune timer expiry.
                         */
                        ch->ifjoin_state = PIM_IFJOIN_PRUNE;
-                       if (ch->upstream)
+                       if (ch->upstream) {
+                               struct pim_upstream *parent =
+                                       ch->upstream->parent;
+
                                pim_upstream_update_join_desired(pim_ifp->pim,
                                                                 ch->upstream);
+
+                               pim_jp_agg_single_upstream_send(&parent->rpf,
+                                                               parent,
+                                                               true);
+                       }
                }
                /* from here ch may have been deleted */
-       } else {
-               zlog_warn(
-                       "%s: IFCHANNEL%s Prune Pending Timer Popped while in %s state",
-                       __PRETTY_FUNCTION__, pim_str_sg_dump(&ch->sg),
-                       pim_ifchannel_ifjoin_name(ch->ifjoin_state, ch->flags));
        }
 
        return 0;
index 1fccbaeafa3be332a308d95837ae03eb9bcf2e09..8da610a3a6d54e0650603e9a3e45fa05352fd5d6 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);
index e2984e1d131233292657c09d6b521065de395699..ccef796724a3a159088cc02cdb5926a1f327bf46 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));
@@ -811,7 +785,7 @@ int pim_parse_nexthop_update(int command, struct zclient *zclient,
                char buf[PREFIX2STR_BUFFER];
                prefix2str(&p, buf, sizeof(buf));
                zlog_debug(
-                       "%s: NHT Update for %s(%s) num_nh %d num_pim_nh %d vrf:%d up %ld rp %d",
+                       "%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, nexthop_num,
                        pnc->nexthop_num, vrf_id, pnc->upstream_hash->count,
                        listcount(pnc->rp_list));
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 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..52a5d93c4ff4189c093f8b49de11a06a758f8665 100644 (file)
@@ -48,6 +48,7 @@ static void rip_zebra_ipv4_send(struct route_node *rp, u_char cmd)
 
        memset(&api, 0, sizeof(api));
        api.vrf_id = VRF_DEFAULT;
+       api.nh_vrf_id = VRF_DEFAULT;
        api.type = ZEBRA_ROUTE_RIP;
        api.safi = SAFI_UNICAST;
 
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..ea069d877fe251d38cfea13d3f297426fece2e61 100644 (file)
@@ -48,6 +48,7 @@ static void ripng_zebra_ipv6_send(struct route_node *rp, u_char cmd)
 
        memset(&api, 0, sizeof(api));
        api.vrf_id = VRF_DEFAULT;
+       api.nh_vrf_id = VRF_DEFAULT;
        api.type = ZEBRA_ROUTE_RIPNG;
        api.safi = SAFI_UNICAST;
        api.prefix = rp->p;
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 4a5ae13c43415326eb761902f31956ca0c1187fe..25bb512a8b6c0704546eb3278abdbcfbf3c6b00a 100644 (file)
@@ -159,6 +159,7 @@ void route_add(struct prefix *p, struct nexthop *nh)
 
        memset(&api, 0, sizeof(api));
        api.vrf_id = VRF_DEFAULT;
+       api.nh_vrf_id = VRF_DEFAULT;
        api.type = ZEBRA_ROUTE_SHARP;
        api.safi = SAFI_UNICAST;
        memcpy(&api.prefix, p, sizeof(*p));
@@ -180,6 +181,7 @@ void route_delete(struct prefix *p)
 
        memset(&api, 0, sizeof(api));
        api.vrf_id = VRF_DEFAULT;
+       api.nh_vrf_id = VRF_DEFAULT;
        api.type = ZEBRA_ROUTE_SHARP;
        api.safi = SAFI_UNICAST;
        memcpy(&api.prefix, p, sizeof(*p));
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..3d5518f3b7b618b0cce5560eb62b8574c58d513c 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"
@@ -915,6 +916,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 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 c270ec3d18f8faa240f90c070d29c128d932f6b2..b6624915e874f47009dc32e212e825930eb1a318 100644 (file)
@@ -23,6 +23,7 @@
 #include "frr_zmq.h"
 
 DEFINE_MTYPE_STATIC(LIB, TESTBUF, "zmq test buffer")
+DEFINE_MTYPE_STATIC(LIB, ZMQMSG, "zmq message")
 
 static struct thread_master *master;
 
@@ -31,6 +32,25 @@ static void msg_buf_free(void *data, void *hint)
        XFREE(MTYPE_TESTBUF, data);
 }
 
+static int recv_delim(void *zmqsock)
+{
+       /* receive delim */
+       zmq_msg_t zdelim;
+       int more;
+       zmq_msg_init(&zdelim);
+       zmq_msg_recv(&zdelim, zmqsock, 0);
+       more = zmq_msg_more(&zdelim);
+       zmq_msg_close(&zdelim);
+       return more;
+}
+static void send_delim(void *zmqsock)
+{
+       /* Send delim */
+       zmq_msg_t zdelim;
+       zmq_msg_init(&zdelim);
+       zmq_msg_send(&zdelim, zmqsock, ZMQ_SNDMORE);
+       zmq_msg_close(&zdelim);
+}
 static void run_client(int syncfd)
 {
        int i, j;
@@ -38,13 +58,14 @@ static void run_client(int syncfd)
        char dummy;
        void *zmqctx = NULL;
        void *zmqsock;
+       int more;
 
        read(syncfd, &dummy, 1);
 
        zmqctx = zmq_ctx_new();
        zmq_ctx_set(zmqctx, ZMQ_IPV6, 1);
 
-       zmqsock = zmq_socket(zmqctx, ZMQ_REQ);
+       zmqsock = zmq_socket(zmqctx, ZMQ_DEALER);
        if (zmq_connect(zmqsock, "tcp://127.0.0.1:17171")) {
                perror("zmq_connect");
                exit(1);
@@ -52,22 +73,28 @@ static void run_client(int syncfd)
 
        /* single-part */
        for (i = 0; i < 8; i++) {
-               snprintf(buf, sizeof(buf), "msg #%d %c%c%c",
-                        i, 'a' + i, 'b' + i, 'c' + i);
+               snprintf(buf, sizeof(buf), "msg #%d %c%c%c", i, 'a' + i,
+                        'b' + i, 'c' + i);
                printf("client send: %s\n", buf);
                fflush(stdout);
-               zmq_send(zmqsock, buf, strlen(buf) + 1, 0);
-               zmq_recv(zmqsock, buf, sizeof(buf), 0);
-               printf("client recv: %s\n", buf);
+               send_delim(zmqsock);
+               zmq_send(zmqsock, buf, strlen(buf) + 1, 0);
+               more = recv_delim(zmqsock);
+               while (more) {
+                       zmq_recv(zmqsock, buf, sizeof(buf), 0);
+                       printf("client recv: %s\n", buf);
+                       size_t len = sizeof(more);
+                       if (zmq_getsockopt(zmqsock, ZMQ_RCVMORE, &more, &len))
+                               break;
+               }
        }
 
        /* multipart */
        for (i = 2; i < 5; i++) {
-               int more;
-
                printf("---\n");
+               send_delim(zmqsock);
+               zmq_msg_t part;
                for (j = 1; j <= i; j++) {
-                       zmq_msg_t part;
                        char *dyn = XMALLOC(MTYPE_TESTBUF, 32);
 
                        snprintf(dyn, 32, "part %d/%d", j, i);
@@ -79,7 +106,7 @@ static void run_client(int syncfd)
                        zmq_msg_send(&part, zmqsock, j < i ? ZMQ_SNDMORE : 0);
                }
 
-               zmq_msg_t part;
+               recv_delim(zmqsock);
                do {
                        char *data;
 
@@ -90,26 +117,85 @@ static void run_client(int syncfd)
                } while (more);
                zmq_msg_close(&part);
        }
+
+       /* write callback */
+       printf("---\n");
+       snprintf(buf, 32, "Done receiving");
+       printf("client send: %s\n", buf);
+       fflush(stdout);
+       send_delim(zmqsock);
+       zmq_send(zmqsock, buf, strlen(buf) + 1, 0);
+       /* wait for message from server */
+       more = recv_delim(zmqsock);
+       while (more) {
+               zmq_recv(zmqsock, buf, sizeof(buf), 0);
+               printf("client recv: %s\n", buf);
+               size_t len = sizeof(more);
+               if (zmq_getsockopt(zmqsock, ZMQ_RCVMORE, &more, &len))
+                       break;
+       }
+
        zmq_close(zmqsock);
        zmq_ctx_term(zmqctx);
 }
 
 static struct frrzmq_cb *cb;
 
+static void recv_id_and_delim(void *zmqsock, zmq_msg_t *msg_id)
+{
+       /* receive id */
+       zmq_msg_init(msg_id);
+       zmq_msg_recv(msg_id, zmqsock, 0);
+       /* receive delim */
+       recv_delim(zmqsock);
+}
+static void send_id_and_delim(void *zmqsock, zmq_msg_t *msg_id)
+{
+       /* Send Id */
+       zmq_msg_send(msg_id, zmqsock, ZMQ_SNDMORE);
+       send_delim(zmqsock);
+}
+static void serverwritefn(void *arg, void *zmqsock)
+{
+       zmq_msg_t *msg_id = (zmq_msg_t *)arg;
+       char buf[32] = "Test write callback";
+       size_t i;
+
+       for (i = 0; i < strlen(buf); i++)
+               buf[i] = toupper(buf[i]);
+       printf("server send: %s\n", buf);
+       fflush(stdout);
+       send_id_and_delim(zmqsock, msg_id);
+       zmq_send(zmqsock, buf, strlen(buf) + 1, 0);
+
+       /* send just once */
+       frrzmq_thread_cancel(&cb, &cb->write);
+
+       zmq_msg_close(msg_id);
+       XFREE(MTYPE_ZMQMSG, msg_id);
+}
 static void serverpartfn(void *arg, void *zmqsock, zmq_msg_t *msg,
-                       unsigned partnum)
+                        unsigned partnum)
 {
+       static int num = 0;
        int more = zmq_msg_more(msg);
        char *in = zmq_msg_data(msg);
        size_t i;
        zmq_msg_t reply;
        char *out;
 
+       /* Id */
+       if (partnum == 0) {
+               send_id_and_delim(zmqsock, msg);
+               return;
+       }
+       /* Delim */
+       if (partnum == 1)
+               return;
+
+
        printf("server recv part %u (more: %d): %s\n", partnum, more, in);
        fflush(stdout);
-       /* REQ-REP doesn't allow sending a reply here */
-       if (more)
-               return;
 
        out = XMALLOC(MTYPE_TESTBUF, strlen(in) + 1);
        for (i = 0; i < strlen(in); i++)
@@ -118,39 +204,66 @@ static void serverpartfn(void *arg, void *zmqsock, zmq_msg_t *msg,
        zmq_msg_init_data(&reply, out, strlen(out) + 1, msg_buf_free, NULL);
        zmq_msg_send(&reply, zmqsock, ZMQ_SNDMORE);
 
+       if (more)
+               return;
+
        out = XMALLOC(MTYPE_TESTBUF, 32);
        snprintf(out, 32, "msg# was %u", partnum);
        zmq_msg_init_data(&reply, out, strlen(out) + 1, msg_buf_free, NULL);
        zmq_msg_send(&reply, zmqsock, 0);
+
+       zmq_msg_close(&reply);
+
+       if (++num < 7)
+               return;
+
+       /* write callback test */
+       char buf[32];
+       zmq_msg_t *msg_id = XMALLOC(MTYPE_ZMQMSG, sizeof(zmq_msg_t));
+       recv_id_and_delim(zmqsock, msg_id);
+       zmq_recv(zmqsock, buf, sizeof(buf), 0);
+       printf("server recv: %s\n", buf);
+       fflush(stdout);
+
+       frrzmq_thread_add_write_msg(master, serverwritefn, NULL, msg_id,
+                                   zmqsock, &cb);
 }
 
 static void serverfn(void *arg, void *zmqsock)
 {
        static int num = 0;
 
+       zmq_msg_t msg_id;
        char buf[32];
        size_t i;
+
+       recv_id_and_delim(zmqsock, &msg_id);
        zmq_recv(zmqsock, buf, sizeof(buf), 0);
 
        printf("server recv: %s\n", buf);
        fflush(stdout);
        for (i = 0; i < strlen(buf); i++)
                buf[i] = toupper(buf[i]);
+       send_id_and_delim(zmqsock, &msg_id);
+       zmq_msg_close(&msg_id);
        zmq_send(zmqsock, buf, strlen(buf) + 1, 0);
 
        if (++num < 4)
                return;
 
        /* change to multipart callback */
-       frrzmq_thread_cancel(cb);
+       frrzmq_thread_cancel(&cb, &cb->read);
+       frrzmq_thread_cancel(&cb, &cb->write);
 
-       cb = frrzmq_thread_add_read_part(master, serverpartfn, NULL, zmqsock);
+       frrzmq_thread_add_read_part(master, serverpartfn, NULL, NULL, zmqsock,
+                                   &cb);
 }
 
 static void sigchld(void)
 {
        printf("child exited.\n");
-       frrzmq_thread_cancel(cb);
+       frrzmq_thread_cancel(&cb, &cb->read);
+       frrzmq_thread_cancel(&cb, &cb->write);
 }
 
 static struct quagga_signal_t sigs[] = {
@@ -170,13 +283,13 @@ static void run_server(int syncfd)
        signal_init(master, array_size(sigs), sigs);
        frrzmq_init();
 
-       zmqsock = zmq_socket(frrzmq_context, ZMQ_REP);
+       zmqsock = zmq_socket(frrzmq_context, ZMQ_ROUTER);
        if (zmq_bind(zmqsock, "tcp://*:17171")) {
                perror("zmq_bind");
                exit(1);
        }
 
-       cb = frrzmq_thread_add_read_msg(master, serverfn, NULL, zmqsock);
+       frrzmq_thread_add_read_msg(master, serverfn, NULL, NULL, zmqsock, &cb);
 
        write(syncfd, &dummy, sizeof(dummy));
        while (thread_fetch(master, &t))
index 61f45f02b137241d7ca17c804c8d37e9de2f26ef..acac50553d15ec01f04eac697ac9d3fbdd5bf6bb 100644 (file)
@@ -11,40 +11,57 @@ client send: msg #3 def
 server recv: msg #3 def
 client recv: MSG #3 DEF
 client send: msg #4 efg
-server recv part 0 (more: 0): msg #4 efg
+server recv part 2 (more: 0): msg #4 efg
 client recv: MSG #4 EFG
+client recv: msg# was 2
 client send: msg #5 fgh
-client recv: msg# was 0
+server recv part 2 (more: 0): msg #5 fgh
+client recv: MSG #5 FGH
+client recv: msg# was 2
 client send: msg #6 ghi
-server recv part 0 (more: 0): msg #6 ghi
+server recv part 2 (more: 0): msg #6 ghi
 client recv: MSG #6 GHI
+client recv: msg# was 2
 client send: msg #7 hij
-client recv: msg# was 0
+server recv part 2 (more: 0): msg #7 hij
+client recv: MSG #7 HIJ
+client recv: msg# was 2
 ---
 client send: part 1/2
 client send: part 2/2
-server recv part 0 (more: 1): part 1/2
-server recv part 1 (more: 0): part 2/2
+server recv part 2 (more: 1): part 1/2
+server recv part 3 (more: 0): part 2/2
+client recv (more: 1): PART 1/2
 client recv (more: 1): PART 2/2
-client recv (more: 0): msg# was 1
+client recv (more: 0): msg# was 3
 ---
 client send: part 1/3
 client send: part 2/3
 client send: part 3/3
-server recv part 0 (more: 1): part 1/3
-server recv part 1 (more: 1): part 2/3
-server recv part 2 (more: 0): part 3/3
+server recv part 2 (more: 1): part 1/3
+server recv part 3 (more: 1): part 2/3
+server recv part 4 (more: 0): part 3/3
+client recv (more: 1): PART 1/3
+client recv (more: 1): PART 2/3
 client recv (more: 1): PART 3/3
-client recv (more: 0): msg# was 2
+client recv (more: 0): msg# was 4
 ---
 client send: part 1/4
 client send: part 2/4
 client send: part 3/4
 client send: part 4/4
-server recv part 0 (more: 1): part 1/4
-server recv part 1 (more: 1): part 2/4
-server recv part 2 (more: 1): part 3/4
-server recv part 3 (more: 0): part 4/4
+server recv part 2 (more: 1): part 1/4
+server recv part 3 (more: 1): part 2/4
+server recv part 4 (more: 1): part 3/4
+server recv part 5 (more: 0): part 4/4
+client recv (more: 1): PART 1/4
+client recv (more: 1): PART 2/4
+client recv (more: 1): PART 3/4
 client recv (more: 1): PART 4/4
-client recv (more: 0): msg# was 3
+client recv (more: 0): msg# was 5
+---
+client send: Done receiving
+server recv: Done receiving
+server send: TEST WRITE CALLBACK
+client recv: TEST WRITE CALLBACK
 child exited.
index 3f40836c90bda4857aad02024c7c90c2c02a9357..783d16731873d0ed75c8752481925509bbf85239 100644 (file)
@@ -20,7 +20,7 @@ sharpd_options="  --daemon -A 127.0.0.1"
 
 # The list of daemons to watch is automatically generated by the init script.
 watchfrr_enable=yes
-watchfrr_options=(-d -r /usr/sbin/servicebBfrrbBrestartbB%s -s /usr/sbin/servicebBfrrbBstartbB%s -k /usr/sbin/servicebBfrrbBstopbB%s -b bB -t 30)
+watchfrr_options=(-d -r /usr/sbin/servicebBfrrbBrestartbB%s -s /usr/sbin/servicebBfrrbBstartbB%s -k /usr/sbin/servicebBfrrbBstopbB%s -b bB)
 
 # If valgrind_enable is 'yes' the frr daemons will be started via valgrind.
 # The use case for doing so is tracking down memory leaks, etc in frr.
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 76343ded602cc0e6f053ddfa1642b75eee732316..097f39fcf0370ae7458f8721736422ade92ba56f 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");
                }
@@ -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;
 }
@@ -2703,6 +2721,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 +2786,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 +3016,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 +3029,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);
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 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 c9f721eacb65212931f7f069ed4c57f681f8bbc6..dc3dcbf1e94096b58bf7433ff2279684bdde0b8b 100644 (file)
@@ -45,7 +45,7 @@
 #define FUZZY(X) ((X)+JITTER((X)/20))
 
 #define DEFAULT_PERIOD         5
-#define DEFAULT_TIMEOUT                10
+#define DEFAULT_TIMEOUT                90
 #define DEFAULT_RESTART_TIMEOUT        20
 #define DEFAULT_LOGLEVEL       LOG_INFO
 #define DEFAULT_MIN_RESTART    60
@@ -596,7 +596,8 @@ static void daemon_send_ready(void)
                FILE *fp;
 
                fp = fopen(DAEMON_VTY_DIR "/watchfrr.started", "w");
-               fclose(fp);
+               if (fp)
+                       fclose(fp);
 #if defined HAVE_SYSTEMD
                zlog_notice(
                        "Watchfrr: Notifying Systemd we are up and running");
index 18dc6a970b5427d7374cc6a79665fdc500cce680..d34fd9021a3e96eb48a264ae2083e7d68c438a39 100644 (file)
@@ -238,11 +238,13 @@ 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, 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, 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];
@@ -396,10 +398,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 af17e49231fa5b6278d1c5656fb1f9c7ce93104c..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)
 {
@@ -838,6 +843,16 @@ int kernel_address_delete_ipv4(struct interface *ifp, struct connected *ifc)
        return netlink_address(RTM_DELADDR, AF_INET, ifp, ifc);
 }
 
+int kernel_address_add_ipv6 (struct interface *ifp, struct connected *ifc)
+{
+  return netlink_address (RTM_NEWADDR, AF_INET6, ifp, ifc);
+}
+
+int kernel_address_delete_ipv6 (struct interface *ifp, struct connected *ifc)
+{
+  return netlink_address (RTM_DELADDR, AF_INET6, ifp, ifc);
+}
+
 int netlink_interface_addr(struct sockaddr_nl *snl, struct nlmsghdr *h,
                           ns_id_t ns_id, int startup)
 {
index dd1050ee7f066659b91e5ee2d52bada7ad6698af..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);
        }
 
@@ -561,33 +594,35 @@ static void if_delete_connected(struct interface *ifp)
        struct prefix cp;
        struct route_node *rn;
        struct zebra_if *zebra_if;
+       struct listnode *node;
+       struct listnode *last = NULL;
 
        zebra_if = ifp->info;
 
-       if (ifp->connected) {
-               struct listnode *node;
-               struct listnode *last = NULL;
+       if (!ifp->connected)
+               return;
 
-               while ((node = (last ? last->next
-                                    : listhead(ifp->connected)))) {
-                       ifc = listgetdata(node);
+       while ((node = (last ? last->next
+                       : listhead(ifp->connected)))) {
+               ifc = listgetdata(node);
 
-                       cp = *CONNECTED_PREFIX(ifc);
-                       apply_mask(&cp);
+               cp = *CONNECTED_PREFIX(ifc);
+               apply_mask(&cp);
 
-                       if (cp.family == AF_INET
-                           && (rn = route_node_lookup(zebra_if->ipv4_subnets,
-                                                      &cp))) {
-                               struct listnode *anode;
-                               struct listnode *next;
-                               struct listnode *first;
-                               struct list *addr_list;
+               if (cp.family == AF_INET
+                   && (rn = route_node_lookup(zebra_if->ipv4_subnets,
+                                              &cp))) {
+                       struct listnode *anode;
+                       struct listnode *next;
+                       struct listnode *first;
+                       struct list *addr_list;
 
-                               route_unlock_node(rn);
-                               addr_list = (struct list *)rn->info;
+                       route_unlock_node(rn);
+                       addr_list = (struct list *)rn->info;
 
-                               /* Remove addresses, secondaries first. */
-                               first = listhead(addr_list);
+                       /* Remove addresses, secondaries first. */
+                       first = listhead(addr_list);
+                       if (first)
                                for (anode = first->next; anode || first;
                                     anode = next) {
                                        if (!anode) {
@@ -626,27 +661,26 @@ static void if_delete_connected(struct interface *ifp)
                                                last = node;
                                }
 
-                               /* Free chain list and respective route node. */
-                               list_delete_and_null(&addr_list);
-                               rn->info = NULL;
-                               route_unlock_node(rn);
-                       } else if (cp.family == AF_INET6) {
-                               connected_down(ifp, ifc);
+                       /* Free chain list and respective route node. */
+                       list_delete_and_null(&addr_list);
+                       rn->info = NULL;
+                       route_unlock_node(rn);
+               } else if (cp.family == AF_INET6) {
+                       connected_down(ifp, ifc);
 
-                               zebra_interface_address_delete_update(ifp, ifc);
+                       zebra_interface_address_delete_update(ifp, ifc);
 
-                               UNSET_FLAG(ifc->conf, ZEBRA_IFC_REAL);
-                               UNSET_FLAG(ifc->conf, ZEBRA_IFC_QUEUED);
+                       UNSET_FLAG(ifc->conf, ZEBRA_IFC_REAL);
+                       UNSET_FLAG(ifc->conf, ZEBRA_IFC_QUEUED);
 
-                               if (CHECK_FLAG(ifc->conf, ZEBRA_IFC_CONFIGURED))
-                                       last = node;
-                               else {
-                                       listnode_delete(ifp->connected, ifc);
-                                       connected_free(ifc);
-                               }
-                       } else {
+                       if (CHECK_FLAG(ifc->conf, ZEBRA_IFC_CONFIGURED))
                                last = node;
+                       else {
+                               listnode_delete(ifp->connected, ifc);
+                               connected_free(ifc);
                        }
+               } else {
+                       last = node;
                }
        }
 }
@@ -734,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 6bc05e21c5d08c9da870416cada92a11c7f03273..e13721448c680f446960cec8332c6e18a788fd05 100644 (file)
@@ -170,7 +170,12 @@ struct rtadvconf {
 #define RTADV_PREF_MEDIUM 0x0 /* Per RFC4191. */
 
        u_char inFastRexmit; /* True if we're rexmits faster than usual */
-       u_char configured;   /* Has operator configured RA? */
+
+       /* Track if RA was configured by BGP or by the Operator or both */
+       u_char ra_configured;     /* Was RA configured? */
+#define BGP_RA_CONFIGURED (1<<0)  /* BGP configured RA? */
+#define VTY_RA_CONFIGURED (1<<1)  /* Operator configured RA? */
+#define VTY_RA_INTERVAL_CONFIGURED (1<<2)  /* Operator configured RA interval */
        int
                NumFastReXmitsRemain; /* Loaded first with number of fast
                                         rexmits to do */
@@ -268,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),
@@ -308,6 +315,8 @@ static inline void zebra_if_set_ziftype(struct interface *ifp,
 #define IS_ZEBRA_IF_VRF_SLAVE(ifp)                                             \
        (((struct zebra_if *)(ifp->info))->zif_slave_type == ZEBRA_IF_SLAVE_VRF)
 
+extern void zebra_if_init(void);
+
 extern struct interface *if_lookup_by_index_per_ns(struct zebra_ns *,
                                                   u_int32_t);
 extern struct interface *if_lookup_by_name_per_ns(struct zebra_ns *,
index 58118ce006f014c9306b82e16816450e0c6abf96..8e3a1d1a036307ea1d024dda8124579556a8dc42 100644 (file)
@@ -78,6 +78,7 @@ int if_ioctl(u_long request, caddr_t buffer)
        return 0;
 }
 
+#ifndef HAVE_NETLINK
 static int if_ioctl_ipv6(u_long request, caddr_t buffer)
 {
        int sock;
@@ -108,6 +109,7 @@ static int if_ioctl_ipv6(u_long request, caddr_t buffer)
        }
        return 0;
 }
+#endif /* ! HAVE_NETLINK */
 
 /*
  * get interface metric
@@ -460,44 +462,19 @@ struct in6_ifreq {
        int ifr6_ifindex;
 };
 #endif /* _LINUX_IN6_H */
-
 /* Interface's address add/delete functions. */
 int if_prefix_add_ipv6(struct interface *ifp, struct connected *ifc)
 {
-       int ret;
-       struct prefix_ipv6 *p;
-       struct in6_ifreq ifreq;
-
-       p = (struct prefix_ipv6 *)ifc->address;
-
-       memset(&ifreq, 0, sizeof(struct in6_ifreq));
-
-       memcpy(&ifreq.ifr6_addr, &p->prefix, sizeof(struct in6_addr));
-       ifreq.ifr6_ifindex = ifp->ifindex;
-       ifreq.ifr6_prefixlen = p->prefixlen;
-
-       ret = if_ioctl_ipv6(SIOCSIFADDR, (caddr_t)&ifreq);
-
-       return ret;
+#ifdef HAVE_NETLINK
+       return kernel_address_add_ipv6 (ifp, ifc);
+#endif /* HAVE_NETLINK */
 }
 
 int if_prefix_delete_ipv6(struct interface *ifp, struct connected *ifc)
 {
-       int ret;
-       struct prefix_ipv6 *p;
-       struct in6_ifreq ifreq;
-
-       p = (struct prefix_ipv6 *)ifc->address;
-
-       memset(&ifreq, 0, sizeof(struct in6_ifreq));
-
-       memcpy(&ifreq.ifr6_addr, &p->prefix, sizeof(struct in6_addr));
-       ifreq.ifr6_ifindex = ifp->ifindex;
-       ifreq.ifr6_prefixlen = p->prefixlen;
-
-       ret = if_ioctl_ipv6(SIOCDIFADDR, (caddr_t)&ifreq);
-
-       return ret;
+#ifdef HAVE_NETLINK
+       return kernel_address_delete_ipv6 (ifp, ifc);
+#endif /* HAVE_NETLINK */
 }
 #else /* LINUX_IPV6 */
 #ifdef HAVE_STRUCT_IN6_ALIASREQ
index 2834eeeb9cc51f62921c9f95796f21030a56b481..f823ec4384c9eedea0efa81b1029a41b33eaca1d 100644 (file)
@@ -42,6 +42,7 @@ static void dropline(FILE *fp)
 
 int ipforward(void)
 {
+       int ret = 0;
        FILE *fp;
        int ipforwarding = 0;
        char buf[10];
@@ -58,11 +59,11 @@ int ipforward(void)
           1 => ip forwarding enabled
           2 => ip forwarding off. */
        if (fgets(buf, 6, fp))
-               sscanf(buf, "Ip: %d", &ipforwarding);
+               ret = sscanf(buf, "Ip: %d", &ipforwarding);
 
        fclose(fp);
 
-       if (ipforwarding == 1)
+       if (ret == 1 && ipforwarding == 1)
                return 1;
 
        return 0;
@@ -127,6 +128,7 @@ char proc_ipv6_forwarding[] = "/proc/sys/net/ipv6/conf/all/forwarding";
 
 int ipforward_ipv6(void)
 {
+       int ret = 0;
        FILE *fp;
        char buf[5];
        int ipforwarding = 0;
@@ -137,9 +139,13 @@ int ipforward_ipv6(void)
                return -1;
 
        if (fgets(buf, 2, fp))
-               sscanf(buf, "%d", &ipforwarding);
+               ret = sscanf(buf, "%d", &ipforwarding);
 
        fclose(fp);
+
+       if (ret != 1)
+               return 0;
+
        return ipforwarding;
 }
 
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 a5c36b0daedc7ab0024e5b0876781c7377cb5f5a..1be2cbcaf54ea27b974cacfee3a58f9cb9a2bd5b 100644 (file)
@@ -40,6 +40,7 @@
 #include "zebra/zserv.h"
 #include "zebra/zebra_ns.h"
 #include "zebra/zebra_vrf.h"
+#include "zebra/rt.h"
 #include "zebra/debug.h"
 #include "zebra/kernel_netlink.h"
 #include "zebra/rt_netlink.h"
index 89c933f90ff53f8d40e953bccfda264b81eb2d63..ba028ed09cf64f47cd1112506583faddc893cff5 100644 (file)
@@ -1039,7 +1039,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;
@@ -1048,13 +1048,13 @@ void rtm_read(struct rt_msghdr *rtm)
 
                if (rtm->rtm_type == RTM_GET || rtm->rtm_type == RTM_ADD
                    || rtm->rtm_type == RTM_CHANGE)
-                       rib_add(AFI_IP, SAFI_UNICAST, VRF_DEFAULT,
+                       rib_add(AFI_IP, SAFI_UNICAST, VRF_DEFAULT, 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 +1085,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
@@ -1096,13 +1096,13 @@ void rtm_read(struct rt_msghdr *rtm)
 
                if (rtm->rtm_type == RTM_GET || rtm->rtm_type == RTM_ADD
                    || rtm->rtm_type == RTM_CHANGE)
-                       rib_add(AFI_IP6, SAFI_UNICAST, VRF_DEFAULT,
+                       rib_add(AFI_IP6, SAFI_UNICAST, VRF_DEFAULT, 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);
        }
 }
 
index bf4522b70f52dcf2354866ec97921b9a7fd73b77..ace13eda7140d006e547dcefe2e80bbe4b34a65c 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);
index 36c931c4ee9b6ded7afbf86be069d0aa2cd43227..19b16936d9e08900f00351249b8f5dc2eac4f568 100644 (file)
@@ -295,11 +295,17 @@ int main(int argc, char **argv)
        zebrad.master = frr_init();
 
        /* Zebra related initialize. */
-       zebra_init();
+       zserv_init();
        rib_init();
        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 818844cb6d55e345a1f686eb7d3f2cad455dba8c..664afd01b84bd038f9e18b5511eca58fe851fbbd 100644 (file)
@@ -59,6 +59,7 @@ struct route_entry {
 
        /* VRF identifier. */
        vrf_id_t vrf_id;
+       vrf_id_t nh_vrf_id;
 
        /* Which routing table */
        uint32_t table;
@@ -85,8 +86,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 +122,8 @@ typedef struct rib_dest_t_ {
         */
        struct route_entry *routes;
 
+       struct route_entry *selected_fib;
+
        /*
         * Flags, see below.
         */
@@ -292,11 +294,11 @@ extern void rib_uninstall_kernel(struct route_node *rn, struct route_entry *re);
 /* NOTE:
  * All rib_add function will not just add prefix into RIB, but
  * also implicitly withdraw equal prefix of same type. */
-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,
+extern int rib_add(afi_t afi, safi_t safi, vrf_id_t vrf_id, vrf_id_t nh_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 +306,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 *,
@@ -435,4 +438,10 @@ static inline void rib_tables_iter_cleanup(rib_tables_iter_t *iter)
 DECLARE_HOOK(rib_update, (struct route_node * rn, const char *reason),
             (rn, 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 6bbe69e983390ae25f17e01e99bedd00dc87f73b..54d45b889a303a9f4c9b014340bb7257b8c869a1 100644 (file)
@@ -60,20 +60,24 @@ 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);
 
 extern int kernel_address_add_ipv4(struct interface *, struct connected *);
 extern int kernel_address_delete_ipv4(struct interface *, struct connected *);
+extern int kernel_address_add_ipv6 (struct interface *, struct connected *);
+extern int kernel_address_delete_ipv6 (struct interface *, struct connected *);
 extern int kernel_neigh_update(int, int, uint32_t, char *, int);
 extern int kernel_interface_set_master(struct interface *master,
                                       struct interface *slave);
@@ -96,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);
@@ -112,4 +117,18 @@ extern int kernel_add_neigh(struct interface *ifp, struct ipaddr *ip,
                            struct ethaddr *mac);
 extern int kernel_del_neigh(struct interface *ifp, struct ipaddr *ip);
 
+/*
+ * Southbound Initialization routines to get initial starting
+ * state.
+ */
+extern void interface_list(struct zebra_ns *zns);
+extern void kernel_init(struct zebra_ns *zns);
+extern void kernel_terminate(struct zebra_ns *zns);
+extern void macfdb_read(struct zebra_ns *zns);
+extern void macfdb_read_for_bridge(struct zebra_ns *zns, struct interface *ifp,
+                                  struct interface *br_if);
+extern void neigh_read(struct zebra_ns *zns);
+extern void neigh_read_for_vlan(struct zebra_ns *zns, struct interface *ifp);
+extern void route_read(struct zebra_ns *zns);
+
 #endif /* _ZEBRA_RT_H */
index cbe736e00cc1c06bd3ce98b9c01c5603d8bd18b8..20cc292e111cffc35a9e979bfe4cffce4bade81a 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;
+                       }
+
+                       rib_add(afi, SAFI_UNICAST, vrf_id, nh_vrf_id, proto,
+                               0, flags, &p, NULL, &nh, table, metric,
+                               mtu, distance, tag);
                } else {
                        /* This is a multipath route */
 
@@ -446,9 +463,11 @@ static int netlink_route_change_read_unicast(struct sockaddr_nl *snl,
                        re->metric = metric;
                        re->mtu = mtu;
                        re->vrf_id = vrf_id;
+                       re->nh_vrf_id = vrf_id;
                        re->table = table;
                        re->nexthop_num = 0;
                        re->uptime = time(NULL);
+                       re->tag = tag;
 
                        for (;;) {
                                if (len < (int)sizeof(*rtnh)
@@ -456,6 +475,18 @@ static int netlink_route_change_read_unicast(struct sockaddr_nl *snl,
                                        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)
+                                               re->nh_vrf_id = ifp->vrf_id;
+                               }
                                gate = 0;
                                if (rtnh->rtnh_len > sizeof(*rtnh)) {
                                        memset(tb, 0, sizeof(tb));
@@ -535,13 +566,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,7 +826,7 @@ 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];
        char label_buf[256];
 
@@ -932,10 +963,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 +991,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,7 +1031,7 @@ 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];
        char label_buf[256];
 
@@ -1133,11 +1169,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 +1192,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 +1351,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 +1642,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 +1673,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 +1683,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 40219599ddac9903e6e912c642ce66b480ccd276..32418eb82fb45498d90d16505209135e1929bc39 100644 (file)
@@ -838,16 +838,21 @@ void zebra_interface_radv_set(struct zserv *client, u_short length,
 
        zif = ifp->info;
        if (enable) {
+               SET_FLAG(zif->rtadv.ra_configured, BGP_RA_CONFIGURED);
                ipv6_nd_suppress_ra_set(ifp, RA_ENABLE);
                if (ra_interval
-                   && (ra_interval * 1000) < zif->rtadv.MaxRtrAdvInterval)
+                       && (ra_interval * 1000) < zif->rtadv.MaxRtrAdvInterval
+                       && !CHECK_FLAG(zif->rtadv.ra_configured,
+                               VTY_RA_INTERVAL_CONFIGURED))
                        zif->rtadv.MaxRtrAdvInterval = ra_interval * 1000;
        } else {
-               if (!zif->rtadv.configured) {
+               UNSET_FLAG(zif->rtadv.ra_configured, BGP_RA_CONFIGURED);
+               if (!CHECK_FLAG(zif->rtadv.ra_configured,
+                               VTY_RA_INTERVAL_CONFIGURED))
                        zif->rtadv.MaxRtrAdvInterval =
                                RTADV_MAX_RTR_ADV_INTERVAL;
+               if (!CHECK_FLAG(zif->rtadv.ra_configured, VTY_RA_CONFIGURED))
                        ipv6_nd_suppress_ra_set(ifp, RA_SUPPRESS);
-               }
        }
 stream_failure:
        return;
@@ -870,8 +875,10 @@ DEFUN (ipv6_nd_suppress_ra,
                return CMD_WARNING_CONFIG_FAILED;
        }
 
-       ipv6_nd_suppress_ra_set(ifp, RA_SUPPRESS);
-       zif->rtadv.configured = 0;
+       if (!CHECK_FLAG(zif->rtadv.ra_configured, BGP_RA_CONFIGURED))
+               ipv6_nd_suppress_ra_set(ifp, RA_SUPPRESS);
+
+       UNSET_FLAG(zif->rtadv.ra_configured, VTY_RA_CONFIGURED);
        return CMD_SUCCESS;
 }
 
@@ -894,7 +901,7 @@ DEFUN (no_ipv6_nd_suppress_ra,
        }
 
        ipv6_nd_suppress_ra_set(ifp, RA_ENABLE);
-       zif->rtadv.configured = 1;
+       SET_FLAG(zif->rtadv.ra_configured, VTY_RA_CONFIGURED);
        return CMD_SUCCESS;
 }
 
@@ -929,6 +936,7 @@ DEFUN (ipv6_nd_ra_interval_msec,
        if (interval % 1000)
                zns->rtadv.adv_msec_if_count++;
 
+       SET_FLAG(zif->rtadv.ra_configured, VTY_RA_INTERVAL_CONFIGURED);
        zif->rtadv.MaxRtrAdvInterval = interval;
        zif->rtadv.MinRtrAdvInterval = 0.33 * interval;
        zif->rtadv.AdvIntervalTimer = 0;
@@ -966,6 +974,7 @@ DEFUN (ipv6_nd_ra_interval,
        /* convert to milliseconds */
        interval = interval * 1000;
 
+       SET_FLAG(zif->rtadv.ra_configured, VTY_RA_INTERVAL_CONFIGURED);
        zif->rtadv.MaxRtrAdvInterval = interval;
        zif->rtadv.MinRtrAdvInterval = 0.33 * interval;
        zif->rtadv.AdvIntervalTimer = 0;
@@ -995,9 +1004,15 @@ DEFUN (no_ipv6_nd_ra_interval,
        if (zif->rtadv.MaxRtrAdvInterval % 1000)
                zns->rtadv.adv_msec_if_count--;
 
-       zif->rtadv.MaxRtrAdvInterval = RTADV_MAX_RTR_ADV_INTERVAL;
-       zif->rtadv.MinRtrAdvInterval = RTADV_MIN_RTR_ADV_INTERVAL;
+       UNSET_FLAG(zif->rtadv.ra_configured, VTY_RA_INTERVAL_CONFIGURED);
+
+       if (CHECK_FLAG(zif->rtadv.ra_configured, BGP_RA_CONFIGURED))
+               zif->rtadv.MaxRtrAdvInterval = 10000;
+       else
+               zif->rtadv.MaxRtrAdvInterval = RTADV_MAX_RTR_ADV_INTERVAL;
+
        zif->rtadv.AdvIntervalTimer = zif->rtadv.MaxRtrAdvInterval;
+       zif->rtadv.MinRtrAdvInterval = RTADV_MIN_RTR_ADV_INTERVAL;
 
        return CMD_SUCCESS;
 }
@@ -1552,15 +1567,20 @@ static int rtadv_config_write(struct vty *vty, struct interface *ifp)
 
        if (!(if_is_loopback(ifp)
              || CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_VRF_LOOPBACK))) {
-               if (zif->rtadv.AdvSendAdvertisements)
+               if (zif->rtadv.AdvSendAdvertisements
+                   && CHECK_FLAG(zif->rtadv.ra_configured, VTY_RA_CONFIGURED))
                        vty_out(vty, " no ipv6 nd suppress-ra\n");
        }
 
        interval = zif->rtadv.MaxRtrAdvInterval;
-       if (interval % 1000)
-               vty_out(vty, " ipv6 nd ra-interval msec %d\n", interval);
-       else if (interval != RTADV_MAX_RTR_ADV_INTERVAL)
-               vty_out(vty, " ipv6 nd ra-interval %d\n", interval / 1000);
+       if (CHECK_FLAG(zif->rtadv.ra_configured, VTY_RA_INTERVAL_CONFIGURED)) {
+               if (interval % 1000)
+                       vty_out(vty, " ipv6 nd ra-interval msec %d\n",
+                               interval);
+               else if (interval != RTADV_MAX_RTR_ADV_INTERVAL)
+                       vty_out(vty, " ipv6 nd ra-interval %d\n",
+                               interval / 1000);
+       }
 
        if (zif->rtadv.AdvIntervalOption)
                vty_out(vty, " ipv6 nd adv-interval-option\n");
index 62f3224b6e874db7c120b91dbb352dcb9b6a0b99..ba45f54ad2d6b4a0d20926b653a98eeb91a84025 100644 (file)
@@ -30,7 +30,7 @@
 #include "vty.h"
 
 #include "zebra/rib.h"
-#include "zebra/zserv.h"
+#include "zebra/rt.h"
 
 /* Thank you, Solaris, for polluting application symbol namespace. */
 #undef hook_register
@@ -97,8 +97,9 @@ static void handle_route_entry(mib2_ipRouteEntry_t *routeEntry)
        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);
+       rib_add(AFI_IP, SAFI_UNICAST, VRF_DEFAULT, VRF_DEFAULT,
+               ZEBRA_ROUTE_KERNEL, 0, zebra_flags, &prefix, NULL,
+               &nh, 0, 0, 0, 0, 0);
 }
 
 void route_read(struct zebra_ns *zns)
index f38cba65e737199c7880295c3b92c617fb2bdd8d..ec29d1820ece9d5680cbc41af3be2f6af8aff88d 100644 (file)
@@ -24,7 +24,7 @@
 #ifdef GNU_LINUX
 
 #include "vty.h"
-#include "zebra/zserv.h"
+#include "zebra/rt.h"
 #include "zebra/rt_netlink.h"
 
 void route_read(struct zebra_ns *zns)
index 53ed0e7906be83d7915be2d19535024689bae939..4f5a80612ee6977c4c3b4c0a320ffe7f99f3ca33 100644 (file)
@@ -28,7 +28,6 @@
 #include "log.h"
 #include "vrf.h"
 
-#include "zebra/zserv.h"
 #include "zebra/rt.h"
 #include "zebra/kernel_socket.h"
 
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..61051ba87e966148983c57c4b4305c299bd9f361 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,
@@ -457,7 +457,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);
@@ -1217,7 +1217,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];
 }
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 78072f43bb9eb57e32b97507559c4ef6eb22acc5..b3b9c6d18a4c9f1144d2c75ad86127def4129f22 100644 (file)
@@ -29,6 +29,8 @@
 #include "zebra_ns.h"
 #include "zebra_vrf.h"
 #include "zebra_memory.h"
+#include "rt.h"
+#include "zebra_vxlan.h"
 
 DEFINE_MTYPE(ZEBRA, ZEBRA_NS, "Zebra Name Space")
 
@@ -48,6 +50,7 @@ int zebra_ns_enable(ns_id_t ns_id, void **info)
 #endif
 
        zns->if_table = route_table_init();
+       zebra_vxlan_ns_init(zns);
        kernel_init(zns);
        interface_list(zns);
        route_read(zns);
@@ -60,6 +63,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
@@ -77,7 +81,7 @@ int zebra_ns_init(void)
 
        zebra_vrf_init();
 
-       zebra_ns_enable(0, (void **)&dzns);
+       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 dcd4fb02398ac647d7a4357bf78d22fbc1df5a9f..7f5fd472f1f96d5ae839ca3bf25c659a36143cbe 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,7 +816,10 @@ 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;
 }
 
@@ -945,7 +948,10 @@ 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;
 }
 
@@ -955,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;
 
@@ -997,7 +1003,12 @@ 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 (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..c200e2dbb3727de5e65e2fb63e249072156208cd 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))
@@ -255,11 +256,12 @@ struct nexthop *route_entry_nexthop_ipv4_ifindex_add(struct route_entry *re,
        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, re->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);
                }
 
@@ -370,6 +372,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 +391,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 +403,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(re->nh_vrf_id,
                                                     nexthop->resolved, top);
                nexthops_free(nexthop->resolved);
                nexthop->resolved = NULL;
@@ -413,7 +422,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, re->nh_vrf_id);
                if (ifp && connected_is_unnumbered(ifp)) {
                        if (if_is_operative(ifp))
                                return 1;
@@ -441,7 +450,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, re->nh_vrf_id);
        if (!table)
                return 0;
 
@@ -466,17 +475,12 @@ static int nexthop_active(afi_t afi, struct route_entry *re,
                    && !nh_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 +557,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 +578,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 +692,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 +709,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 +745,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 +764,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 +838,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, re->nh_vrf_id);
                if (ifp && if_is_operative(ifp))
                        SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
                else
@@ -846,7 +847,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 +866,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,
+                                                re->nh_vrf_id);
                        if (ifp && if_is_operative(ifp))
                                SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
                        else
@@ -906,7 +910,7 @@ 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,
+       ret = zebra_route_map_check(family, re->type, p, nexthop, re->nh_vrf_id,
                                    re->tag);
        if (ret == RMAP_DENYMATCH) {
                if (IS_ZEBRA_DEBUG_RIB) {
@@ -914,7 +918,8 @@ static unsigned nexthop_active_check(struct route_node *rn,
                        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,
+                                              re->nh_vrf_id));
                }
                UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
        }
@@ -993,14 +998,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 +1024,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 +1109,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 +1136,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 +1146,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 +1158,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 +1231,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 +1242,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 +1255,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 +1264,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 +1281,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 +1305,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 +1354,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 +1381,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 +1388,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 +1415,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 +1429,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 +1444,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 +1525,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 +1549,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))
@@ -2183,8 +2237,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 +2252,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 +2261,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 +2368,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 +2378,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 +2411,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 +2481,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 +2527,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);
        }
 
@@ -2477,10 +2551,11 @@ 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)
+int rib_add(afi_t afi, safi_t safi, vrf_id_t vrf_id, vrf_id_t nh_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, route_tag_t tag)
 {
        struct route_entry *re;
        struct nexthop *nexthop;
@@ -2495,8 +2570,10 @@ int rib_add(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, u_short instance,
        re->mtu = mtu;
        re->table = table_id;
        re->vrf_id = vrf_id;
+       re->nh_vrf_id = nh_vrf_id;
        re->nexthop_num = 0;
        re->uptime = time(NULL);
+       re->tag = tag;
 
        /* Add nexthop. */
        nexthop = nexthop_new();
@@ -2740,24 +2817,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..8983bdee09e2ab22a75ed325fc316559ba334d4c 100644 (file)
@@ -951,6 +951,8 @@ 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;
+       state->nh_vrf_id = re->vrf_id;
 
        route_entry_copy_nexthops(state, re->nexthop);
        rnh->state = state;
@@ -1000,7 +1002,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) {
index 61af60b5da1e3ccd1d4dc16fc24d23a8799c246d..4c619e5782743a227121d8b45e9f6a06b809d9c9 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 = re->nh_vrf_id;
        nh_obj.source_protocol = re->type;
        nh_obj.metric = re->metric;
        nh_obj.tag = re->tag;
index 1f95c7f83c7b78a8074c43fb51415196485f95ab..60bf7c3f59412a3f7876a7b088cc4b6cf762aa11 100644 (file)
@@ -22,6 +22,7 @@
 #ifndef __ZEBRA_ROUTEMAP_H__
 #define __ZEBRA_ROUTEMAP_H__
 
+extern void zebra_route_map_init(void);
 extern void zebra_routemap_config_write_protocol(struct vty *vty);
 extern char *zebra_get_import_table_route_map(afi_t afi, uint32_t table);
 extern void zebra_add_import_table_route_map(afi_t afi, const char *rmap_name,
index 5927ba9d750e5146eec12125b3f308f55dc4b40d..2e8ab11b040a7621a6a73a8a48332bb8fb8be756 100644 (file)
@@ -91,7 +91,7 @@ void static_install_route(afi_t afi, safi_t safi, struct prefix *p,
                        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(
@@ -111,7 +111,7 @@ void static_install_route(afi_t afi, safi_t safi, struct prefix *p,
                        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(
@@ -141,7 +141,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);
@@ -155,8 +155,9 @@ void static_install_route(afi_t afi, safi_t safi, struct prefix *p,
                re->metric = 0;
                re->mtu = 0;
                re->vrf_id = si->vrf_id;
+               re->nh_vrf_id = si->nh_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;
@@ -169,7 +170,7 @@ void static_install_route(afi_t afi, safi_t safi, struct prefix *p,
                        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(
@@ -189,7 +190,7 @@ void static_install_route(afi_t afi, safi_t safi, struct prefix *p,
                        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(
@@ -221,7 +222,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 +332,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 +352,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 +379,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 +441,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 +497,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..246a7e7e4c597ce5ab315e102ae3c13da39d1a8b 100644 (file)
@@ -250,6 +250,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);
@@ -452,6 +456,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 +477,18 @@ static int vrf_config_write(struct vty *vty)
                if (!zvrf)
                        continue;
 
-               if (strcmp(zvrf_name(zvrf), VRF_DEFAULT_NAME)) {
+               if (vrf->vrf_id != VRF_DEFAULT)
                        vty_out(vty, "vrf %s\n", zvrf_name(zvrf));
+
+               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 && zvrf->l3vni)
+                       vty_out(vty, " vni %u\n", zvrf->l3vni);
+
+               if (vrf->vrf_id != VRF_DEFAULT)
                        vty_out(vty, "!\n");
-               }
        }
        return 0;
 }
index 1dfc0b3eb8b11f941209e6cb8a372ef49a377d93..c7a0717ee8291bc655f3bfff7e1f23d3ade2e00c 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_ {
@@ -114,6 +115,9 @@ struct zebra_vrf {
         */
        int advertise_gw_macip;
 
+       /* l3-vni info */
+       vni_t l3vni;
+
        /* Route Installs */
        uint64_t installs;
        uint64_t removals;
index c2c7075671cca1b8c3e9c01242a1389d3a6ac48a..f0be862221de01cfed28d8da9073c4d4b5311dd8 100644 (file)
@@ -47,6 +47,9 @@
 #include "zebra/zebra_vty_clippy.c"
 #endif
 #include "zebra/zserv.h"
+#include "zebra/router-id.h"
+#include "zebra/ipforward.h"
+#include "zebra/zebra_vxlan_private.h"
 
 extern int allow_delete;
 
@@ -63,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;
@@ -84,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;
 
@@ -134,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) {
@@ -228,7 +233,8 @@ static int zebra_static_route(struct vty *vty, afi_t afi, safi_t safi,
 
        if (!negate)
                static_add_route(afi, safi, type, &p, src_p, gatep, ifname,
-                                bh_type, tag, distance, zvrf, &snh_label);
+                                bh_type, tag, distance, zvrf, nh_zvrf,
+                                &snh_label);
        else
                static_delete_route(afi, safi, type, &p, src_p, gatep, ifname,
                                    tag, distance, zvrf, &snh_label);
@@ -236,6 +242,31 @@ static int zebra_static_route(struct vty *vty, afi_t afi, safi_t safi,
        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_id_str,
+                             const char *label_str)
+{
+       struct zebra_vrf *zvrf;
+
+       /* 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;
+       }
+
+       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,
@@ -376,6 +407,37 @@ 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;
+
+       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\
@@ -387,6 +449,7 @@ DEFPY(ip_route_address_interface,
          |(1-255)$distance                            \
          |vrf NAME                                    \
          |label WORD                                  \
+         |nexthop-vrf NAME                            \
           }]",
       NO_STR IP_STR
       "Establish static routes\n"
@@ -400,16 +463,89 @@ 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;
+       }
+
+       nh_zvrf = zebra_vrf_lookup_by_name(nexthop_vrf);
+       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,
@@ -422,6 +558,7 @@ DEFPY(ip_route,
          |(1-255)$distance                            \
          |vrf NAME                                    \
          |label WORD                                  \
+         |nexthop-vrf NAME                            \
           }]",
       NO_STR IP_STR
       "Establish static routes\n"
@@ -434,16 +571,88 @@ 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;
+       }
+
+       nh_zvrf = zebra_vrf_lookup_by_name(nexthop_vrf);
+       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. */
@@ -472,8 +681,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) {
@@ -523,7 +737,7 @@ static void vty_show_ip_route_detail(struct vty *vty, struct route_node *rn,
                                if (nexthop->ifindex)
                                        vty_out(vty, ", via %s",
                                                ifindex2ifname(nexthop->ifindex,
-                                                              re->vrf_id));
+                                                              re->nh_vrf_id));
                                break;
                        case NEXTHOP_TYPE_IPV6:
                        case NEXTHOP_TYPE_IPV6_IFINDEX:
@@ -533,12 +747,12 @@ static void vty_show_ip_route_detail(struct vty *vty, struct route_node *rn,
                                if (nexthop->ifindex)
                                        vty_out(vty, ", via %s",
                                                ifindex2ifname(nexthop->ifindex,
-                                                              re->vrf_id));
+                                                              re->nh_vrf_id));
                                break;
                        case NEXTHOP_TYPE_IFINDEX:
                                vty_out(vty, " directly connected, %s",
                                        ifindex2ifname(nexthop->ifindex,
-                                                      re->vrf_id));
+                                                      re->nh_vrf_id));
                                break;
                        case NEXTHOP_TYPE_BLACKHOLE:
                                vty_out(vty, " unreachable");
@@ -560,6 +774,14 @@ static void vty_show_ip_route_detail(struct vty *vty, struct route_node *rn,
                        default:
                                break;
                        }
+
+                       if (re->vrf_id != re->nh_vrf_id) {
+                               struct vrf *vrf =
+                                       vrf_lookup_by_id(re->nh_vrf_id);
+
+                               vty_out(vty, "(vrf %s)", vrf->name);
+                       }
+
                        if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_DUPLICATE))
                                vty_out(vty, " (duplicate nexthop removed)");
 
@@ -699,7 +921,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));
+                                                              re->nh_vrf_id));
                                }
                                break;
                        case NEXTHOP_TYPE_IPV6:
@@ -718,7 +940,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));
+                                                              re->nh_vrf_id));
                                }
                                break;
 
@@ -731,7 +953,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));
+                                                      re->nh_vrf_id));
                                break;
                        case NEXTHOP_TYPE_BLACKHOLE:
                                json_object_boolean_true_add(json_nexthop,
@@ -758,6 +980,14 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn,
                                break;
                        }
 
+                       if (re->nh_vrf_id != re->vrf_id) {
+                               struct vrf *vrf =
+                                       vrf_lookup_by_id(re->nh_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");
@@ -865,7 +1095,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));
+                                                      re->nh_vrf_id));
                        break;
                case NEXTHOP_TYPE_IPV6:
                case NEXTHOP_TYPE_IPV6_IFINDEX:
@@ -875,12 +1105,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));
+                                                      re->nh_vrf_id));
                        break;
 
                case NEXTHOP_TYPE_IFINDEX:
                        vty_out(vty, " is directly connected, %s",
-                               ifindex2ifname(nexthop->ifindex, re->vrf_id));
+                               ifindex2ifname(nexthop->ifindex,
+                                              re->nh_vrf_id));
                        break;
                case NEXTHOP_TYPE_BLACKHOLE:
                        vty_out(vty, " unreachable");
@@ -901,6 +1132,14 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn,
                default:
                        break;
                }
+
+               if (re->nh_vrf_id != re->vrf_id) {
+                       struct vrf *vrf =
+                               vrf_lookup_by_id(re->nh_vrf_id);
+
+                       vty_out(vty, "(vrf %s)", vrf->name);
+               }
+
                if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE))
                        vty_out(vty, " inactive");
 
@@ -961,6 +1200,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;
@@ -998,10 +1238,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)
@@ -1163,7 +1404,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;
 }
 
@@ -1179,7 +1420,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;
 }
 
@@ -1194,7 +1435,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;
 }
 
@@ -1210,7 +1451,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;
 }
 
@@ -1585,97 +1826,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;
 }
 
@@ -1709,6 +1951,38 @@ 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;
+
+       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] \
@@ -1719,6 +1993,7 @@ DEFPY(ipv6_route_address_interface,
             |(1-255)$distance                              \
             |vrf NAME                                      \
             |label WORD                                    \
+            |nexthop-vrf NAME                              \
           }]",
       NO_STR
       IPV6_STR
@@ -1732,11 +2007,72 @@ 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;
+
+       nh_zvrf = zebra_vrf_lookup_by_name(nexthop_vrf);
+       if (!nh_zvrf) {
+               vty_out(vty, "%% nexthop vrf %s is not defined\n",
+                       nexthop_vrf);
+               return CMD_WARNING_CONFIG_FAILED;
+       }
+
+       zvrf = zebra_vrf_lookup_by_name(vrf);
+       if (!nh_zvrf) {
+               vty_out(vty, "%% nexthop vrf %s is not defined\n",
+                       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;
+
+       nh_zvrf = zebra_vrf_lookup_by_name(nexthop_vrf);
+       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,
@@ -1748,6 +2084,7 @@ DEFPY(ipv6_route,
             |(1-255)$distance                              \
             |vrf NAME                                      \
             |label WORD                                    \
+            |nexthop-vrf NAME                              \
           }]",
       NO_STR
       IPV6_STR
@@ -1761,18 +2098,78 @@ 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;
 
-/*
- * Show IPv6 mroute command.Used to dump
- * the Multicast routing table.
- */
-DEFUN (show_ipv6_mroute,
+       nh_zvrf = zebra_vrf_lookup_by_name(nexthop_vrf);
+       if (!nh_zvrf) {
+               vty_out(vty, "%% nexthop vrf %s is not defined\n",
+                       nexthop_vrf);
+               return CMD_WARNING_CONFIG_FAILED;
+       }
+
+       zvrf = zebra_vrf_lookup_by_name(vrf);
+       if (!nh_zvrf) {
+               vty_out(vty, "%% nexthop vrf %s is not defined\n",
+                       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;
+
+       nh_zvrf = zebra_vrf_lookup_by_name(nexthop_vrf);
+       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);
+}
+
+/*
+ * Show IPv6 mroute command.Used to dump
+ * the Multicast routing table.
+ */
+DEFUN (show_ipv6_mroute,
        show_ipv6_mroute_cmd,
        "show ipv6 mroute [vrf NAME]",
        SHOW_STR
@@ -1872,7 +2269,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));
@@ -1887,6 +2284,110 @@ DEFUN (show_vrf,
        return CMD_SUCCESS;
 }
 
+DEFUN (vrf_vni_mapping,
+       vrf_vni_mapping_cmd,
+       "vni " CMD_VNI_RANGE,
+       "VNI\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);
+
+       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\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;
+       }
+
+       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();
+       }
+
+       RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name) {
+               zvrf = vrf->info;
+               if (!zvrf)
+                       continue;
+
+               if (!zvrf->l3vni)
+                       continue;
+
+               if (!uj) {
+                       vty_out(vty, "vrf: %s VNI: %u",
+                               zvrf_name(zvrf),
+                               zvrf->l3vni);
+                       vty_out(vty, "\n");
+               } 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, "l3vni",
+                                           zvrf->l3vni);
+                       json_object_array_add(json_vrfs, json_vrf);
+               }
+       }
+
+       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_vni,
        show_evpn_vni_cmd,
        "show evpn vni [json]",
@@ -1922,6 +2423,161 @@ DEFUN (show_evpn_vni_vni,
        return CMD_SUCCESS;
 }
 
+DEFUN (show_evpn_l3vni,
+       show_evpn_l3vni_cmd,
+       "show evpn l3vni [json]",
+       SHOW_STR
+       "EVPN\n"
+       "L3 VNI\n"
+       JSON_STR)
+{
+       u_char uj = use_json(argc, argv);
+
+       zebra_vxlan_print_l3vnis(vty, uj);
+       return CMD_SUCCESS;
+}
+
+DEFUN (show_evpn_l3vni_vni,
+       show_evpn_l3vni_vni_cmd,
+       "show evpn l3vni " CMD_VNI_RANGE "[json]",
+       SHOW_STR
+       "EVPN\n"
+       "L3 VxLAN Network Identifier\n"
+       "VNI number\n"
+       JSON_STR)
+{
+       vni_t vni;
+       u_char uj = use_json(argc, argv);
+
+       vni = strtoul(argv[3]->arg, NULL, 10);
+       zebra_vxlan_print_l3vni(vty, vni, uj);
+       return CMD_SUCCESS;
+}
+
+DEFUN (show_evpn_rmac_l3vni_mac,
+       show_evpn_rmac_l3vni_mac_cmd,
+       "show evpn rmac l3vni " 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_l3vni,
+       show_evpn_rmac_l3vni_cmd,
+       "show evpn rmac l3vni " 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_l3vni_all,
+       show_evpn_rmac_l3vni_all_cmd,
+       "show evpn rmac l3vni 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_l3vni_ip,
+       show_evpn_nh_l3vni_ip_cmd,
+       "show evpn next-hops l3vni " 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_l3vni,
+       show_evpn_nh_l3vni_cmd,
+       "show evpn next-hops l3vni " 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_l3vni_all,
+       show_evpn_nh_l3vni_all_cmd,
+       "show evpn next-hops l3vni 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]",
@@ -2142,11 +2798,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;
 }
 
@@ -2325,13 +2978,254 @@ static int config_write_protocol(struct vty *vty)
        return 1;
 }
 
+#ifdef HAVE_NETLINK
+/* Display default rtm_table for all clients. */
+DEFUN (show_table,
+       show_table_cmd,
+       "show table",
+       SHOW_STR
+       "default routing table to use for all clients\n")
+{
+       vty_out(vty, "table %d\n", zebrad.rtm_table_default);
+       return CMD_SUCCESS;
+}
+
+DEFUN (config_table,
+       config_table_cmd,
+       "table TABLENO",
+       "Configure target kernel routing table\n"
+       "TABLE integer\n")
+{
+       zebrad.rtm_table_default = strtol(argv[1]->arg, (char **)0, 10);
+       return CMD_SUCCESS;
+}
+
+DEFUN (no_config_table,
+       no_config_table_cmd,
+       "no table [TABLENO]",
+       NO_STR
+       "Configure target kernel routing table\n"
+       "TABLE integer\n")
+{
+       zebrad.rtm_table_default = 0;
+       return CMD_SUCCESS;
+}
+#endif
+
+DEFUN (show_zebra,
+       show_zebra_cmd,
+       "show zebra",
+       SHOW_STR
+       ZEBRA_STR)
+{
+       struct vrf *vrf;
+
+       vty_out(vty,
+               "                            Route      Route      Neighbor   LSP        LSP\n");
+       vty_out(vty,
+               "VRF                         Installs   Removals    Updates   Installs   Removals\n");
+
+       RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name) {
+               struct zebra_vrf *zvrf = vrf->info;
+
+               vty_out(vty, "%-25s %10" PRIu64 " %10" PRIu64 " %10" PRIu64
+                            " %10" PRIu64 " %10" PRIu64 "\n",
+                       vrf->name, zvrf->installs, zvrf->removals,
+                       zvrf->neigh_updates, zvrf->lsp_installs,
+                       zvrf->lsp_removals);
+       }
+
+       return CMD_SUCCESS;
+}
+
+DEFUN (ip_forwarding,
+       ip_forwarding_cmd,
+       "ip forwarding",
+       IP_STR
+       "Turn on IP forwarding\n")
+{
+       int ret;
+
+       ret = ipforward();
+       if (ret == 0)
+               ret = ipforward_on();
+
+       if (ret == 0) {
+               vty_out(vty, "Can't turn on IP forwarding\n");
+               return CMD_WARNING_CONFIG_FAILED;
+       }
+
+       return CMD_SUCCESS;
+}
+
+DEFUN (no_ip_forwarding,
+       no_ip_forwarding_cmd,
+       "no ip forwarding",
+       NO_STR
+       IP_STR
+       "Turn off IP forwarding\n")
+{
+       int ret;
+
+       ret = ipforward();
+       if (ret != 0)
+               ret = ipforward_off();
+
+       if (ret != 0) {
+               vty_out(vty, "Can't turn off IP forwarding\n");
+               return CMD_WARNING_CONFIG_FAILED;
+       }
+
+       return CMD_SUCCESS;
+}
+
+/* Only display ip forwarding is enabled or not. */
+DEFUN (show_ip_forwarding,
+       show_ip_forwarding_cmd,
+       "show ip forwarding",
+       SHOW_STR
+       IP_STR
+       "IP forwarding status\n")
+{
+       int ret;
+
+       ret = ipforward();
+
+       if (ret == 0)
+               vty_out(vty, "IP forwarding is off\n");
+       else
+               vty_out(vty, "IP forwarding is on\n");
+       return CMD_SUCCESS;
+}
+
+/* Only display ipv6 forwarding is enabled or not. */
+DEFUN (show_ipv6_forwarding,
+       show_ipv6_forwarding_cmd,
+       "show ipv6 forwarding",
+       SHOW_STR
+       "IPv6 information\n"
+       "Forwarding status\n")
+{
+       int ret;
+
+       ret = ipforward_ipv6();
+
+       switch (ret) {
+       case -1:
+               vty_out(vty, "ipv6 forwarding is unknown\n");
+               break;
+       case 0:
+               vty_out(vty, "ipv6 forwarding is %s\n", "off");
+               break;
+       case 1:
+               vty_out(vty, "ipv6 forwarding is %s\n", "on");
+               break;
+       default:
+               vty_out(vty, "ipv6 forwarding is %s\n", "off");
+               break;
+       }
+       return CMD_SUCCESS;
+}
+
+DEFUN (ipv6_forwarding,
+       ipv6_forwarding_cmd,
+       "ipv6 forwarding",
+       IPV6_STR
+       "Turn on IPv6 forwarding\n")
+{
+       int ret;
+
+       ret = ipforward_ipv6();
+       if (ret == 0)
+               ret = ipforward_ipv6_on();
+
+       if (ret == 0) {
+               vty_out(vty, "Can't turn on IPv6 forwarding\n");
+               return CMD_WARNING_CONFIG_FAILED;
+       }
+
+       return CMD_SUCCESS;
+}
+
+DEFUN (no_ipv6_forwarding,
+       no_ipv6_forwarding_cmd,
+       "no ipv6 forwarding",
+       NO_STR
+       IPV6_STR
+       "Turn off IPv6 forwarding\n")
+{
+       int ret;
+
+       ret = ipforward_ipv6();
+       if (ret != 0)
+               ret = ipforward_ipv6_off();
+
+       if (ret != 0) {
+               vty_out(vty, "Can't turn off IPv6 forwarding\n");
+               return CMD_WARNING_CONFIG_FAILED;
+       }
+
+       return CMD_SUCCESS;
+}
+
+/* Table configuration write function. */
+static int config_write_table(struct vty *vty)
+{
+       if (zebrad.rtm_table_default)
+               vty_out(vty, "table %d\n", zebrad.rtm_table_default);
+       return 0;
+}
+
+/* IPForwarding configuration write function. */
+static int config_write_forwarding(struct vty *vty)
+{
+       /* FIXME: Find better place for that. */
+       router_id_write(vty);
+
+       if (!ipforward())
+               vty_out(vty, "no ip forwarding\n");
+       if (!ipforward_ipv6())
+               vty_out(vty, "no ipv6 forwarding\n");
+       vty_out(vty, "!\n");
+       return 0;
+}
+
 /* IP node for static routes. */
 static struct cmd_node ip_node = {IP_NODE, "", 1};
 static struct cmd_node protocol_node = {PROTOCOL_NODE, "", 1};
+/* table node for routing tables. */
+static struct cmd_node table_node = {TABLE_NODE,
+                                    "", /* This node has no interface. */
+                                    1};
+static struct cmd_node forwarding_node = {FORWARDING_NODE,
+                                         "", /* This node has no interface. */
+                                         1};
 
 /* Route VTY.  */
 void zebra_vty_init(void)
 {
+       /* Install configuration write function. */
+       install_node(&table_node, config_write_table);
+       install_node(&forwarding_node, config_write_forwarding);
+
+       install_element(VIEW_NODE, &show_ip_forwarding_cmd);
+       install_element(CONFIG_NODE, &ip_forwarding_cmd);
+       install_element(CONFIG_NODE, &no_ip_forwarding_cmd);
+       install_element(ENABLE_NODE, &show_zebra_cmd);
+
+#ifdef HAVE_NETLINK
+       install_element(VIEW_NODE, &show_table_cmd);
+       install_element(CONFIG_NODE, &config_table_cmd);
+       install_element(CONFIG_NODE, &no_config_table_cmd);
+#endif /* HAVE_NETLINK */
+
+       install_element(VIEW_NODE, &show_ipv6_forwarding_cmd);
+       install_element(CONFIG_NODE, &ipv6_forwarding_cmd);
+       install_element(CONFIG_NODE, &no_ipv6_forwarding_cmd);
+
+       /* Route-map */
+       zebra_route_map_init();
+
        install_node(&ip_node, zebra_ip_config);
        install_node(&protocol_node, config_write_protocol);
 
@@ -2341,8 +3235,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);
@@ -2351,6 +3248,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);
@@ -2363,8 +3261,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);
@@ -2376,6 +3277,14 @@ void zebra_vty_init(void)
 
        install_element(VIEW_NODE, &show_evpn_vni_cmd);
        install_element(VIEW_NODE, &show_evpn_vni_vni_cmd);
+       install_element(VIEW_NODE, &show_evpn_l3vni_cmd);
+       install_element(VIEW_NODE, &show_evpn_l3vni_vni_cmd);
+       install_element(VIEW_NODE, &show_evpn_rmac_l3vni_mac_cmd);
+       install_element(VIEW_NODE, &show_evpn_rmac_l3vni_cmd);
+       install_element(VIEW_NODE, &show_evpn_rmac_l3vni_all_cmd);
+       install_element(VIEW_NODE, &show_evpn_nh_l3vni_ip_cmd);
+       install_element(VIEW_NODE, &show_evpn_nh_l3vni_cmd);
+       install_element(VIEW_NODE, &show_evpn_nh_l3vni_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);
@@ -2385,4 +3294,9 @@ 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, &no_vrf_vni_mapping_cmd);
+       install_element(VRF_NODE, &vrf_vni_mapping_cmd);
+       install_element(VRF_NODE, &no_vrf_vni_mapping_cmd);
+
 }
index 9c70b55a1a4e4cb4a4d82567efa2620ccbc0d50b..1690079f68f76c7d0e7f67167f34976d58459d43 100644 (file)
@@ -48,7 +48,9 @@
 #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");
@@ -61,6 +63,10 @@ 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 +97,46 @@ 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 int is_vni_l3(vni_t);
+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);
@@ -385,6 +426,80 @@ 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, "  Host-List:\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, "rmac",
+                                      prefix_mac2str(&n->emac, buf2,
+                                                     sizeof(buf2)));
+               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, "hosts", 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, "  Host-List:\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, "Rmac",
+                                      prefix_mac2str(&zrmac->macaddr,
+                                                     buf1,
+                                                     sizeof(buf1)));
+               json_object_string_add(json, "vtep-ip",
+                                      inet_ntoa(zrmac->fwd_info.r_vtep_ip));
+               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, "hosts", json_hosts);
+       }
+}
+
 /*
  * Print a specific MAC entry.
  */
@@ -603,6 +718,234 @@ 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 %6d\n",
+                       ipaddr2str(&(n->ip), buf2, sizeof(buf2)),
+                       prefix_mac2str(&n->emac, buf1, sizeof(buf1)),
+                       listcount(n->host_list));
+       } else {
+               json_object_string_add(json_nh, "nexthop-ip",
+                                      ipaddr2str(&n->ip, buf2, sizeof(buf2)));
+               json_object_string_add(json_nh, "rmac",
+                                      prefix_mac2str(&n->emac, buf1,
+                                                     sizeof(buf1)));
+               json_object_int_add(json_nh, "refCnt", listcount(n->host_list));
+               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 %6s\n", "IP",
+                       "RMAC", "Refcnt");
+       } else
+               json_object_int_add(json_vni, "numNh", 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 #MACs %u\n\n",
+                       zl3vni->vni, num_rmacs);
+               vty_out(vty, "%-17s %-21s %-6s\n", "MAC",
+                       "Remote VTEP", "Refcnt");
+       } 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 %-6d\n",
+                       prefix_mac2str(&zrmac->macaddr, buf, sizeof(buf)),
+                                       inet_ntoa(zrmac->fwd_info.r_vtep_ip),
+                                       listcount(zrmac->host_list));
+       } else {
+               json_object_string_add(json_rmac, "rmac",
+                                      prefix_mac2str(&zrmac->macaddr, buf,
+                                                     sizeof(buf)));
+               json_object_string_add(json_rmac, "vtep-ip",
+                                      inet_ntoa(zrmac->fwd_info.r_vtep_ip));
+               json_object_int_add(json_rmac, "refcnt",
+                                   listcount(zrmac->host_list));
+               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, "  Local Vtep Ip: %s",
+                       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, "  Vrf: %s\n",
+                       zl3vni_vrf_name(zl3vni));
+               vty_out(vty, "  Rmac: %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, "local-vtep-ip",
+                                      inet_ntoa(zl3vni->local_vtep_ip));
+               json_object_string_add(json, "vxlan-intf",
+                                      zl3vni_vxlan_if_name(zl3vni));
+               json_object_string_add(json, "svi-if",
+                                      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, "rmac",
+                                      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, "l2-vnis", json_vni_list);
+       }
+}
+
 /*
  * Print a specific VNI entry.
  */
@@ -619,10 +962,14 @@ 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, " VRF: %s\n", vrf_id_to_name(zvni->vrf_id));
+       } else {
                json_object_int_add(json, "vni", zvni->vni);
+               json_object_string_add(json, "vrf",
+                                      vrf_id_to_name(zvni->vrf_id));
+       }
 
        if (!zvni->vxlan_if) { // unexpected
                if (json == NULL)
@@ -682,6 +1029,56 @@ 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[])
+{
+       char buf[ETHER_ADDR_STRLEN];
+       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 %-15s %-20s %-20s %-5s %-37s %-18s\n",
+                       zl3vni->vni,
+                       inet_ntoa(zl3vni->local_vtep_ip),
+                       zl3vni_vxlan_if_name(zl3vni),
+                       zl3vni_svi_if_name(zl3vni),
+                       zl3vni_state2str(zl3vni),
+                       zl3vni_vrf_name(zl3vni),
+                       zl3vni_rmac2str(zl3vni, buf, sizeof(buf)));
+       } 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, "local-ip",
+                                      inet_ntoa(zl3vni->local_vtep_ip));
+               json_object_string_add(json_vni, "vxlan-if",
+                                      zl3vni_vxlan_if_name(zl3vni));
+               json_object_string_add(json_vni, "svi-if",
+                                      zl3vni_svi_if_name(zl3vni));
+               json_object_string_add(json_vni, "state",
+                                      zl3vni_state2str(zl3vni));
+               json_object_string_add(json_vni, "vrf",
+                                      zl3vni_vrf_name(zl3vni));
+               json_object_string_add(json_vni, "rmac",
+                                      zl3vni_rmac2str(zl3vni, buf,
+                                                      sizeof(buf)));
+               json_object_object_add(json, vni_str, json_vni);
+       }
+
+}
+
 /*
  * Print a VNI hash entry - called for display of all VNIs.
  */
@@ -714,10 +1111,12 @@ 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 %-21s %-15s %-8u %-8u %-15u %-37s\n",
+                       zvni->vni,
                        zvni->vxlan_if ? zvni->vxlan_if->name : "unknown",
                        inet_ntoa(zvni->local_vtep_ip), num_macs, num_neigh,
-                       num_vteps);
+                       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);
@@ -753,11 +1152,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 +1166,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 +1184,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 +1400,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,
@@ -1040,7 +1440,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 +1477,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,
@@ -1302,12 +1702,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)
@@ -1353,7 +1753,7 @@ static int zvni_gw_macip_add(struct interface *ifp, zebra_vni_t *zvni,
 
        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)));
@@ -1370,10 +1770,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);
@@ -1395,7 +1795,7 @@ static int zvni_gw_macip_del(struct interface *ifp, zebra_vni_t *zvni,
 
        if (IS_ZEBRA_DEBUG_VXLAN)
                zlog_debug(
-                       "SVI %s(%u) VNI %u, sending GW MAC %s IP %s del to BGP",
+                       "SVI %s(%u) L2-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)));
@@ -1747,7 +2147,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;
@@ -2130,16 +2531,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 +2565,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 +2592,9 @@ 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;
                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 +2602,83 @@ 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));
+               if (is_vni_l3(vni)) {
+                       zebra_l3vni_t *zl3vni = NULL;
 
-               /* 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;
-               }
+                       zl3vni = zl3vni_lookup(vni);
+                       if (!zl3vni) {
+                               zlog_err(
+                                       "Failed to locate L3-VNI hash at UP, IF %s(%u) VNI %u",
+                                       ifp->name, ifp->ifindex, vni);
+                               return;
+                       }
 
-               zvni->local_vtep_ip = vxl->vtep_ip;
-               zvni->vxlan_if = ifp;
+                       /* associate with vxlan_if */
+                       zl3vni->local_vtep_ip = vxl->vtep_ip;
+                       zl3vni->vxlan_if = ifp;
 
-               /* 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);
+                       /*
+                        * 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);
+
+                       if (is_l3vni_oper_up(zl3vni))
+                               zebra_vxlan_process_l3vni_oper_up(zl3vni);
+
+               } else {
+                       zebra_vni_t *zvni = NULL;
+                       zebra_l3vni_t *zl3vni = NULL;
+                       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);
+               }
        }
 }
 
@@ -2351,12 +2797,18 @@ static int zvni_vtep_uninstall(zebra_vni_t *zvni, struct in_addr *vtep_ip)
  */
 static void zvni_cleanup_all(struct hash_backet *backet, void *zvrf)
 {
-       zebra_vni_t *zvni;
+       zebra_vni_t *zvni = NULL;
+       zebra_l3vni_t *zl3vni = NULL;
 
        zvni = (zebra_vni_t *)backet->data;
        if (!zvni)
                return;
 
+       /* remove from l3-vni list */
+       zl3vni = zl3vni_from_vrf(zvni->vrf_id);
+       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);
@@ -2368,63 +2820,1342 @@ static void zvni_cleanup_all(struct hash_backet *backet, void *zvrf)
        zvni_del(zvni);
 }
 
+/* cleanup L3VNI */
+static void zl3vni_cleanup_all(struct hash_backet *backet,
+                              void *args)
+{
+       zebra_l3vni_t *zl3vni = NULL;
 
-/* Public functions */
+       zl3vni = (zebra_l3vni_t *)backet->data;
+       if (!zl3vni)
+               return;
 
-/*
- * Display Neighbors for a VNI (VTY command handler).
- */
-void zebra_vxlan_print_neigh_vni(struct vty *vty, struct zebra_vrf *zvrf,
-                                vni_t vni, u_char use_json)
+       zebra_vxlan_process_l3vni_oper_down(zl3vni);
+}
+
+static int is_host_present_in_host_list(struct list *list,
+                                       struct prefix *host)
 {
-       zebra_vni_t *zvni;
-       u_int32_t num_neigh;
-       struct neigh_walk_ctx wctx;
-       json_object *json = NULL;
+       struct listnode *node = NULL;
+       struct prefix *p = 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;
+       for (ALL_LIST_ELEMENTS_RO(list, node, p)) {
+               if (prefix_same(p, host))
+                       return 1;
        }
-       num_neigh = hashcount(zvni->neigh_table);
-       if (!num_neigh)
-               return;
-
-       if (use_json)
-               json = json_object_new_object();
+       return 0;
+}
 
-       /* Since we have IPv6 addresses to deal with which can vary widely in
-        * size, we try to be a bit more elegant in display by first computing
-        * the maximum width.
-        */
-       memset(&wctx, 0, sizeof(struct neigh_walk_ctx));
-       wctx.zvni = zvni;
-       wctx.vty = vty;
-       wctx.addr_width = 15;
-       wctx.json = json;
-       hash_iterate(zvni->neigh_table, zvni_find_neigh_addr_width, &wctx);
+static void host_list_add_host(struct list *list,
+                              struct prefix *host)
+{
+       struct prefix *p = NULL;
 
-       if (!use_json) {
-               vty_out(vty,
-                       "Number of ARPs (local and remote) known for this VNI: %u\n",
-                       num_neigh);
-               vty_out(vty, "%*s %-6s %-17s %-21s\n", -wctx.addr_width, "IP",
-                       "Type", "MAC", "Remote VTEP");
-       } else
-               json_object_int_add(json, "numArpNd", num_neigh);
+       p = XCALLOC(MTYPE_HOST_PREFIX, sizeof(struct prefix));
+       memcpy(p, host, sizeof(struct prefix));
 
-       hash_iterate(zvni->neigh_table, zvni_print_neigh_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);
-       }
+       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 (!is_l3vni_oper_up(zl3vni))
+               return -1;
+
+       if (!(n->flags & ZEBRA_NEIGH_REMOTE) ||
+           !(n->flags & ZEBRA_NEIGH_REMOTE_NH))
+               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 int is_vni_l3(vni_t vni)
+{
+       zebra_l3vni_t *zl3vni = NULL;
+
+       zl3vni = zl3vni_lookup(vni);
+       if (zl3vni)
+               return 1;
+       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->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 (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 (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);
+}
+
+/* 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 %-6s\n", "MAC",
+                       "Remote VTEP", "Refcnt");
+       } 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;
+       }
+
+       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;
+
+       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 %6s\n", "IP",
+                       "RMAC", "Refcnt");
+       } else
+               json_object_int_add(json, "numNh", 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);
+       }
+}
+
+/*
+ * Display L3 VNI hash table (VTY command handler).
+ */
+void zebra_vxlan_print_l3vnis(struct vty *vty, u_char use_json)
+{
+       u_int32_t num_vnis;
+       void *args[2];
+       json_object *json = NULL;
+       struct zebra_ns *zns = NULL;
+
+       if (!is_evpn_enabled()) {
+               if (use_json)
+                       vty_out(vty, "{}\n");
+               return;
+       }
+
+       zns = zebra_ns_lookup(NS_DEFAULT);
+       assert(zns);
+
+       num_vnis = hashcount(zns->l3vni_table);
+       if (!num_vnis) {
+               if (use_json)
+                       vty_out(vty, "{}\n");
+               return;
+       }
+
+       if (use_json) {
+               json = json_object_new_object();
+               json_object_int_add(json, "numVnis", num_vnis);
+       } else {
+               vty_out(vty, "Number of L3 VNIs: %u\n", num_vnis);
+               vty_out(vty, "%-10s %-15s %-20s %-20s %-5s %-37s %-18s\n",
+                       "VNI", "Local-ip", "Vx-intf", "L3-SVI", "State",
+                       "VRF", "Rmac");
+       }
+
+       args[0] = vty;
+       args[1] = json;
+       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));
+               json_object_free(json);
+       }
+}
+
+/*
+ * Display Neighbors for a VNI (VTY command handler).
+ */
+void zebra_vxlan_print_neigh_vni(struct vty *vty, struct zebra_vrf *zvrf,
+                                vni_t vni, u_char use_json)
+{
+       zebra_vni_t *zvni;
+       u_int32_t num_neigh;
+       struct neigh_walk_ctx wctx;
+       json_object *json = 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;
+       }
+       num_neigh = hashcount(zvni->neigh_table);
+       if (!num_neigh)
+               return;
+
+       if (use_json)
+               json = json_object_new_object();
+
+       /* Since we have IPv6 addresses to deal with which can vary widely in
+        * size, we try to be a bit more elegant in display by first computing
+        * the maximum width.
+        */
+       memset(&wctx, 0, sizeof(struct neigh_walk_ctx));
+       wctx.zvni = zvni;
+       wctx.vty = vty;
+       wctx.addr_width = 15;
+       wctx.json = json;
+       hash_iterate(zvni->neigh_table, zvni_find_neigh_addr_width, &wctx);
+
+       if (!use_json) {
+               vty_out(vty,
+                       "Number of ARPs (local and remote) known for this VNI: %u\n",
+                       num_neigh);
+               vty_out(vty, "%*s %-6s %-17s %-21s\n", -wctx.addr_width, "IP",
+                       "Type", "MAC", "Remote VTEP");
+       } else
+               json_object_int_add(json, "numArpNd", num_neigh);
+
+       hash_iterate(zvni->neigh_table, zvni_print_neigh_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);
+       }
 }
 
 /*
@@ -2789,9 +4520,9 @@ void zebra_vxlan_print_vnis(struct vty *vty, struct zebra_vrf *zvrf,
                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",
+               vty_out(vty, "%-10s %-21s %-15s %-8s %-8s %-15s %-37s\n", "VNI",
                        "VxLAN IF", "VTEP IP", "# MACs", "# ARPs",
-                       "# Remote VTEPs");
+                       "# Remote VTEPs", "VRF");
        }
        args[0] = vty;
        args[1] = json;
@@ -2816,18 +4547,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 +4576,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 +4631,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,12 +4762,12 @@ 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);
 }
 
@@ -3045,6 +4792,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) {
@@ -3189,6 +4940,10 @@ int zebra_vxlan_remote_macip_add(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));
+
        if (!EVPN_ENABLED(zvrf)) {
                zlog_warn("%s: EVPN Not turned on yet we have received a remote_macip add zapi callback",
                          __PRETTY_FUNCTION__);
@@ -3898,14 +5653,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 +5672,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)
@@ -3958,56 +5713,108 @@ 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;
-       struct neigh_walk_ctx n_wctx;
+       zebra_vni_t *zvni = NULL;
+       zebra_l3vni_t *zl3vni = NULL;
 
-       zvni = zvni_map_svi(ifp, link_if);
-       if (!zvni)
-               return 0;
+       zl3vni = zl3vni_from_svi(ifp, link_if);
+       if (zl3vni) {
 
-       if (!zvni->vxlan_if) {
-               zlog_err("VNI %u hash %p doesn't have intf upon SVI up",
-                        zvni->vni, zvni);
-               return -1;
-       }
+               /* associate with svi */
+               zl3vni->svi_if = ifp;
 
-       if (IS_ZEBRA_DEBUG_VXLAN)
-               zlog_debug("SVI %s(%u) VNI %u is UP, installing neighbors",
-                          ifp->name, ifp->ifindex, zvni->vni);
+               /* 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));
 
-       /* 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);
+               /* 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 - update BGP if required, and do
- * internal cleanup.
+ * Handle VxLAN interface down
  */
 int zebra_vxlan_if_down(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;
 
        /* Check if EVPN is enabled. */
        if (!is_evpn_enabled())
@@ -4018,31 +5825,55 @@ 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;
-       }
+       if (is_vni_l3(vni)) {
 
-       assert(zvni->vxlan_if == ifp);
+               /* process-if-down for l3-vni */
+               zebra_l3vni_t *zl3vni = NULL;
 
-       /* Delete this VNI from BGP. */
-       zvni_send_del_to_client(zvni->vni);
+               if (IS_ZEBRA_DEBUG_VXLAN)
+                       zlog_debug("Intf %s(%u) L3-VNI %u is DOWN",
+                                  ifp->name, ifp->ifindex, 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);
+               zl3vni = zl3vni_lookup(vni);
+               if (!zl3vni) {
+                       zlog_err(
+                               "Failed to locate L3-VNI hash at DOWN, IF %s(%u) VNI %u",
+                               ifp->name, ifp->ifindex, vni);
+                       return -1;
+               }
 
-       /* Free up all remote VTEPs, if any. */
-       zvni_vtep_del_all(zvni, 1);
+               zebra_vxlan_process_l3vni_oper_down(zl3vni);
+
+       } else {
+               /* process if-down for l2-vni */
+               zebra_vni_t *zvni;
 
+               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;
 }
 
@@ -4051,10 +5882,9 @@ int zebra_vxlan_if_down(struct interface *ifp)
  */
 int zebra_vxlan_if_up(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;
 
        /* Check if EVPN is enabled. */
        if (!is_evpn_enabled())
@@ -4065,26 +5895,66 @@ int zebra_vxlan_if_up(struct interface *ifp)
        vxl = &zif->l2info.vxl;
        vni = vxl->vni;
 
-       if (IS_ZEBRA_DEBUG_VXLAN)
-               zlog_debug("Intf %s(%u) VNI %u is UP",
-                          ifp->name, ifp->ifindex, vni);
+       if (is_vni_l3(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;
-       }
+               /* Handle L3-VNI add */
+               zebra_l3vni_t *zl3vni = NULL;
 
-       assert(zvni->vxlan_if == ifp);
+               if (IS_ZEBRA_DEBUG_VXLAN)
+                       zlog_debug("Intf %s(%u) L3-VNI %u is UP",
+                                  ifp->name, ifp->ifindex, vni);
 
-       /* 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);
+               zl3vni = zl3vni_lookup(vni);
+               if (!zl3vni) {
+                       zlog_err(
+                               "Failed to locate L3-VNI hash at UP, IF %s(%u) VNI %u",
+                               ifp->name, ifp->ifindex, vni);
+                       return -1;
+               }
+
+               /* 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 */
+
+               zebra_vni_t *zvni = NULL;
+               zebra_l3vni_t *zl3vni = NULL;
+               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;
@@ -4096,10 +5966,9 @@ int zebra_vxlan_if_up(struct interface *ifp)
  */
 int zebra_vxlan_if_del(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;
 
        /* Check if EVPN is enabled. */
        if (!is_evpn_enabled())
@@ -4110,34 +5979,69 @@ int zebra_vxlan_if_del(struct interface *ifp)
        vxl = &zif->l2info.vxl;
        vni = vxl->vni;
 
-       if (IS_ZEBRA_DEBUG_VXLAN)
-               zlog_debug("Del VNI %u intf %s(%u)",
-                          vni, ifp->name, ifp->ifindex);
+       if (is_vni_l3(vni)) {
 
-       /* 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;
-       }
+               /* process if-del for l3-vni */
+               zebra_l3vni_t *zl3vni = NULL;
 
-       /* Delete VNI from BGP. */
-       zvni_send_del_to_client(zvni->vni);
+               if (IS_ZEBRA_DEBUG_VXLAN)
+                       zlog_debug("Del L3-VNI %u intf %s(%u)",
+                                  vni, ifp->name, ifp->ifindex);
 
-       /* 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);
+               zl3vni = zl3vni_lookup(vni);
+               if (!zl3vni) {
+                       zlog_err(
+                               "Failed to locate L3-VNI hash at del, IF %s(%u) VNI %u",
+                               ifp->name, ifp->ifindex, vni);
+                       return 0;
+               }
 
-       /* Free up all remote VTEPs, if any. */
-       zvni_vtep_del_all(zvni, 0);
+               /* process oper-down for l3-vni */
+               zebra_vxlan_process_l3vni_oper_down(zl3vni);
 
-       /* 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;
+               /* 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*/
+               zebra_vni_t *zvni = NULL;
+               zebra_l3vni_t *zl3vni = NULL;
+
+               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;
@@ -4148,10 +6052,9 @@ int zebra_vxlan_if_del(struct interface *ifp)
  */
 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;
+       struct zebra_if *zif = NULL;
+       struct zebra_l2info_vxlan *vxl = NULL;
 
        /* Check if EVPN is enabled. */
        if (!is_evpn_enabled())
@@ -4162,79 +6065,129 @@ int zebra_vxlan_if_update(struct interface *ifp, u_int16_t chgflags)
        vxl = &zif->l2info.vxl;
        vni = vxl->vni;
 
-       /* 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_vni_l3(vni)) {
+               zebra_l3vni_t *zl3vni = NULL;
 
-       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;
-       }
+               zl3vni = zl3vni_lookup(vni);
+               if (!zl3vni) {
+                       zlog_err(
+                               "Failed to find L3-VNI hash on update, IF %s(%u) VNI %u",
+                               ifp->name, ifp->ifindex, vni);
+                       return -1;
+               }
+
+               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;
+               }
 
-       /* Handle other changes. */
-       if (chgflags & ZEBRA_VXLIF_VLAN_CHANGE) {
-               /* Remove all existing local neighbors and MACs for this VNI
-                * (including from BGP)
+               /* access-vlan change - process oper down, associate with new
+                * svi_if and then process oper up again
                 */
-               zvni_neigh_del_all(zvni, 0, 1, DEL_LOCAL_MAC);
-               zvni_mac_del_all(zvni, 0, 1, DEL_LOCAL_MAC);
-       }
+               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);
+                       }
+               }
 
-       zvni->local_vtep_ip = vxl->vtep_ip;
-       zvni->vxlan_if = ifp;
+               /* 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 {
+               zebra_vni_t *zvni = 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)
-               return 0;
+               /* 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;
+               }
 
-       /* 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 (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;
+               }
 
-       /* 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;
+               /* 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_read_mac_neigh(zvni, ifp);
+               zvni->local_vtep_ip = vxl->vtep_ip;
+               zvni->vxlan_if = 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);
+               /* 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;
 
-               memset(&n_wctx, 0, sizeof(struct neigh_walk_ctx));
-               n_wctx.zvni = zvni;
-               hash_iterate(zvni->neigh_table, zvni_install_neigh_hash,
-                            &n_wctx);
+               /* 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;
@@ -4245,10 +6198,9 @@ int zebra_vxlan_if_update(struct interface *ifp, u_int16_t chgflags)
  */
 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;
 
        /* Check if EVPN is enabled. */
        if (!is_evpn_enabled())
@@ -4259,37 +6211,200 @@ int zebra_vxlan_if_add(struct interface *ifp)
        vxl = &zif->l2info.vxl;
        vni = vxl->vni;
 
-       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);
+       if (is_vni_l3(vni)) {
 
-       /* Create or update VNI hash. */
-       zvni = zvni_lookup(vni);
-       if (!zvni) {
-               zvni = zvni_add(vni);
-               if (!zvni) {
+               /* process if-add for l3-vni*/
+               zebra_l3vni_t *zl3vni = NULL;
+
+               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);
+
+               /*
+                *  we expect the l3-vni has entry to be present here.
+                *  The only place l3-vni is created in zebra is vrf-vni mapping
+                *  command. This might change when we have the switchd support
+                *  for l3-vxlan interface.
+                */
+               zl3vni = zl3vni_lookup(vni);
+               if (!zl3vni) {
                        zlog_err(
-                               "Failed to add VNI hash, IF %s(%u) VNI %u",
+                               "Failed to locate L3-VNI hash at del, IF %s(%u) VNI %u",
                                ifp->name, ifp->ifindex, vni);
+                       return 0;
+               }
+
+               /* associate with vxlan_if */
+               zl3vni->local_vtep_ip = vxl->vtep_ip;
+               zl3vni->vxlan_if = ifp;
+
+               /* 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);
+
+               if (is_l3vni_oper_up(zl3vni))
+                       zebra_vxlan_process_l3vni_oper_up(zl3vni);
+       } else {
+
+               /* process if-add for l2-vni */
+               zebra_vni_t *zvni = NULL;
+               zebra_l3vni_t *zl3vni = NULL;
+               struct interface *vlan_if = NULL;
+
+               /* 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;
+               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 (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);
+
+               /* 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);
+
+               /* Read and populate local MACs and neighbors */
+               zvni_read_mac_neigh(zvni, ifp);
+       }
+
+       return 0;
+}
+
+int zebra_vxlan_process_vrf_vni_cmd(struct zebra_vrf *zvrf,
+                                   vni_t vni,
+                                   char *err, int err_str_sz,
+                                   int add)
+{
+       zebra_l3vni_t *zl3vni = NULL;
+       struct zebra_vrf *zvrf_default = NULL;
+
+       zvrf_default = zebra_vrf_lookup_by_id(VRF_DEFAULT);
+       if (!zvrf_default)
+               return -1;
+
+       if (IS_ZEBRA_DEBUG_VXLAN)
+               zlog_debug("vrf %s vni %u %s",
+                          zvrf_name(zvrf),
+                          vni,
+                          add ? "ADD" : "DEL");
+
+       if (add) {
+
+               zebra_vxlan_handle_vni_transition(zvrf, vni, add);
+
+               /* 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;
+               }
+
+               /* 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;
+               }
+
+               /* 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;
+               }
+
+               /* associate the vrf with vni */
+               zvrf->l3vni = vni;
+
+               /* associate with vxlan-intf;
+                * we need to associate with the vxlan-intf first
+                */
+               zl3vni->vxlan_if = zl3vni_map_to_vxlan_if(zl3vni);
+
+               /* 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);
+
+               /* formulate l2vni list */
+               hash_iterate(zvrf_default->vni_table,
+                            zvni_add_to_l3vni_list, zl3vni);
+
+               if (is_l3vni_oper_up(zl3vni))
+                       zebra_vxlan_process_l3vni_oper_up(zl3vni);
+
+       } else {
+               zl3vni = zl3vni_lookup(vni);
+               if (!zl3vni) {
+                       snprintf(err, err_str_sz, "VNI doesn't exist");
                        return -1;
                }
+
+               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_delete(struct zebra_vrf *zvrf)
+{
+       zebra_l3vni_t *zl3vni = NULL;
 
-       /* If down or not mapped to a bridge, we're done. */
-       if (!if_is_operative(ifp) || !zif->brslave_info.br_if)
+       zl3vni = zl3vni_from_vrf(zvrf_id(zvrf));
+       if (!zl3vni)
                return 0;
 
-       /* Inform BGP */
-       zvni_send_add_to_client(zvni);
-
-       /* Read and populate local MACs and neighbors */
-       zvni_read_mac_neigh(zvni, ifp);
+       zebra_vxlan_process_l3vni_oper_down(zl3vni);
+       zl3vni_del(zl3vni);
+       zebra_vxlan_handle_vni_transition(zvrf, zl3vni->vni, 0);
 
        return 0;
 }
@@ -4410,8 +6525,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 +6565,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:
@@ -4475,3 +6598,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..b7def6acf8cbd12106a925240390dff51ec8ee55 100644 (file)
@@ -51,6 +51,13 @@ 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 void zebra_vxlan_print_specific_nh_l3vni(struct vty *vty, vni_t l3vni,
+                                               struct ipaddr *ip, 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,6 +91,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_l3vnis(struct vty *vty,
+                                    u_char use_json);
 
 extern int zebra_vxlan_add_del_gw_macip(struct interface *ifp, struct prefix *p,
                                        int add);
@@ -129,7 +146,20 @@ extern int zebra_vxlan_advertise_gw_macip(struct zserv *client,
 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_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..db828c337e239eb54d31f195970fb096a34aa82a 100644 (file)
@@ -83,6 +83,30 @@ void zebra_vxlan_print_vnis(struct vty *vty, struct zebra_vrf *zvrf)
 {
 }
 
+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)
+{
+}
+
+void zebra_vxlan_print_l3vnis(struct vty *vty)
+{
+}
+
 int zebra_vxlan_svi_up(struct interface *ifp, struct interface *link_if)
 {
        return 0;
index fa7d0e94578f14e57e4ed171db6bcef987142fbc..ef6f9b99cb765c7e1ef6b33158609e4af38a6a67 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
@@ -75,6 +79,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 +89,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 +232,7 @@ 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 */
 
        /* Local or remote info. */
        union {
@@ -116,6 +246,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 +274,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 +313,15 @@ 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 */
 
        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 +348,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 b6d70084c0c389c6c379f11e954884918b732ed3..3ee2bb59ecef2a5d637f6190f84cf81388572c36 100644 (file)
@@ -48,7 +48,6 @@
 #include "zebra/router-id.h"
 #include "zebra/redistribute.h"
 #include "zebra/debug.h"
-#include "zebra/ipforward.h"
 #include "zebra/zebra_rnh.h"
 #include "zebra/rt_netlink.h"
 #include "zebra/interface.h"
@@ -150,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. */
@@ -222,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++;
@@ -237,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++;
@@ -251,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++;
@@ -266,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++;
@@ -286,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);
@@ -349,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. */
@@ -394,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. */
@@ -505,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));
@@ -582,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)
@@ -603,6 +592,7 @@ int zsend_redistribute_route(int cmd, struct zserv *client, struct prefix *p,
 
        memset(&api, 0, sizeof(api));
        api.vrf_id = re->vrf_id;
+       api.nh_vrf_id = re->nh_vrf_id;
        api.type = re->type;
        api.instance = re->instance;
        api.flags = re->flags;
@@ -958,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) {
@@ -1010,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));
 
@@ -1040,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);
@@ -1064,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);
@@ -1133,23 +1123,27 @@ 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->nh_vrf_id = api.nh_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:
@@ -1160,11 +1154,42 @@ static int zread_route_add(struct zserv *client, u_short length,
                                nexthop = route_entry_nexthop_ipv4_add(
                                        re, &api_nh->gate.ipv4, NULL);
                                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);
+                                       ifindex);
+
+                               /* 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);
@@ -1266,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) {
@@ -1339,6 +1364,7 @@ static int zread_ipv4_add(struct zserv *client, u_short length,
 
        /* VRF ID */
        re->vrf_id = zvrf_id(zvrf);
+       re->nh_vrf_id = zvrf_id(zvrf);
 
        /* Nexthop parse. */
        if (CHECK_FLAG(message, ZAPI_MESSAGE_NEXTHOP)) {
@@ -1467,7 +1493,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:
@@ -1548,6 +1574,7 @@ static int zread_ipv4_route_ipv6_nexthop_add(struct zserv *client,
 
        /* VRF ID */
        re->vrf_id = zvrf_id(zvrf);
+       re->nh_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
@@ -1833,6 +1860,8 @@ static int zread_ipv6_add(struct zserv *client, u_short length,
 
        /* VRF ID */
        re->vrf_id = zvrf_id(zvrf);
+       re->nh_vrf_id = zvrf_id(zvrf);
+
        re->table = zvrf->table_id;
 
        ret = rib_add_multipath(AFI_IP6, safi, &p, src_pp, re);
@@ -1885,7 +1914,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++;
 
@@ -2055,7 +2085,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);
@@ -2117,7 +2147,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 */
@@ -2438,11 +2468,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);
 
@@ -2680,7 +2710,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) {
@@ -2980,6 +3010,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);
 
@@ -3017,105 +3049,6 @@ struct zserv *zebra_find_client(u_char proto, u_short instance)
        return NULL;
 }
 
-#ifdef HAVE_NETLINK
-/* Display default rtm_table for all clients. */
-DEFUN (show_table,
-       show_table_cmd,
-       "show table",
-       SHOW_STR
-       "default routing table to use for all clients\n")
-{
-       vty_out(vty, "table %d\n", zebrad.rtm_table_default);
-       return CMD_SUCCESS;
-}
-
-DEFUN (config_table,
-       config_table_cmd,
-       "table TABLENO",
-       "Configure target kernel routing table\n"
-       "TABLE integer\n")
-{
-       zebrad.rtm_table_default = strtol(argv[1]->arg, (char **)0, 10);
-       return CMD_SUCCESS;
-}
-
-DEFUN (no_config_table,
-       no_config_table_cmd,
-       "no table [TABLENO]",
-       NO_STR
-       "Configure target kernel routing table\n"
-       "TABLE integer\n")
-{
-       zebrad.rtm_table_default = 0;
-       return CMD_SUCCESS;
-}
-#endif
-
-DEFUN (ip_forwarding,
-       ip_forwarding_cmd,
-       "ip forwarding",
-       IP_STR
-       "Turn on IP forwarding\n")
-{
-       int ret;
-
-       ret = ipforward();
-       if (ret == 0)
-               ret = ipforward_on();
-
-       if (ret == 0) {
-               vty_out(vty, "Can't turn on IP forwarding\n");
-               return CMD_WARNING_CONFIG_FAILED;
-       }
-
-       return CMD_SUCCESS;
-}
-
-DEFUN (no_ip_forwarding,
-       no_ip_forwarding_cmd,
-       "no ip forwarding",
-       NO_STR
-       IP_STR
-       "Turn off IP forwarding\n")
-{
-       int ret;
-
-       ret = ipforward();
-       if (ret != 0)
-               ret = ipforward_off();
-
-       if (ret != 0) {
-               vty_out(vty, "Can't turn off IP forwarding\n");
-               return CMD_WARNING_CONFIG_FAILED;
-       }
-
-       return CMD_SUCCESS;
-}
-
-DEFUN (show_zebra,
-       show_zebra_cmd,
-       "show zebra",
-       SHOW_STR
-       ZEBRA_STR)
-{
-       struct vrf *vrf;
-
-       vty_out(vty,
-               "                            Route      Route      Neighbor   LSP        LSP\n");
-       vty_out(vty,
-               "VRF                         Installs   Removals    Updates   Installs   Removals\n");
-       RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
-               struct zebra_vrf *zvrf = vrf->info;
-               vty_out(vty, "%-25s %10" PRIu64 " %10" PRIu64 " %10" PRIu64
-                            " %10" PRIu64 " %10" PRIu64 "\n",
-                       vrf->name, zvrf->installs, zvrf->removals,
-                       zvrf->neigh_updates, zvrf->lsp_installs,
-                       zvrf->lsp_removals);
-       }
-
-       return CMD_SUCCESS;
-}
-
 /* This command is for debugging purpose. */
 DEFUN (show_zebra_client,
        show_zebra_client_cmd,
@@ -3157,127 +3090,6 @@ DEFUN (show_zebra_client_summary,
        return CMD_SUCCESS;
 }
 
-/* Table configuration write function. */
-static int config_write_table(struct vty *vty)
-{
-       if (zebrad.rtm_table_default)
-               vty_out(vty, "table %d\n", zebrad.rtm_table_default);
-       return 0;
-}
-
-/* table node for routing tables. */
-static struct cmd_node table_node = {TABLE_NODE,
-                                    "", /* This node has no interface. */
-                                    1};
-
-/* Only display ip forwarding is enabled or not. */
-DEFUN (show_ip_forwarding,
-       show_ip_forwarding_cmd,
-       "show ip forwarding",
-       SHOW_STR
-       IP_STR
-       "IP forwarding status\n")
-{
-       int ret;
-
-       ret = ipforward();
-
-       if (ret == 0)
-               vty_out(vty, "IP forwarding is off\n");
-       else
-               vty_out(vty, "IP forwarding is on\n");
-       return CMD_SUCCESS;
-}
-
-/* Only display ipv6 forwarding is enabled or not. */
-DEFUN (show_ipv6_forwarding,
-       show_ipv6_forwarding_cmd,
-       "show ipv6 forwarding",
-       SHOW_STR
-       "IPv6 information\n"
-       "Forwarding status\n")
-{
-       int ret;
-
-       ret = ipforward_ipv6();
-
-       switch (ret) {
-       case -1:
-               vty_out(vty, "ipv6 forwarding is unknown\n");
-               break;
-       case 0:
-               vty_out(vty, "ipv6 forwarding is %s\n", "off");
-               break;
-       case 1:
-               vty_out(vty, "ipv6 forwarding is %s\n", "on");
-               break;
-       default:
-               vty_out(vty, "ipv6 forwarding is %s\n", "off");
-               break;
-       }
-       return CMD_SUCCESS;
-}
-
-DEFUN (ipv6_forwarding,
-       ipv6_forwarding_cmd,
-       "ipv6 forwarding",
-       IPV6_STR
-       "Turn on IPv6 forwarding\n")
-{
-       int ret;
-
-       ret = ipforward_ipv6();
-       if (ret == 0)
-               ret = ipforward_ipv6_on();
-
-       if (ret == 0) {
-               vty_out(vty, "Can't turn on IPv6 forwarding\n");
-               return CMD_WARNING_CONFIG_FAILED;
-       }
-
-       return CMD_SUCCESS;
-}
-
-DEFUN (no_ipv6_forwarding,
-       no_ipv6_forwarding_cmd,
-       "no ipv6 forwarding",
-       NO_STR
-       IPV6_STR
-       "Turn off IPv6 forwarding\n")
-{
-       int ret;
-
-       ret = ipforward_ipv6();
-       if (ret != 0)
-               ret = ipforward_ipv6_off();
-
-       if (ret != 0) {
-               vty_out(vty, "Can't turn off IPv6 forwarding\n");
-               return CMD_WARNING_CONFIG_FAILED;
-       }
-
-       return CMD_SUCCESS;
-}
-
-/* IPForwarding configuration write function. */
-static int config_write_forwarding(struct vty *vty)
-{
-       /* FIXME: Find better place for that. */
-       router_id_write(vty);
-
-       if (!ipforward())
-               vty_out(vty, "no ip forwarding\n");
-       if (!ipforward_ipv6())
-               vty_out(vty, "no ipv6 forwarding\n");
-       vty_out(vty, "!\n");
-       return 0;
-}
-
-/* table node for routing tables. */
-static struct cmd_node forwarding_node = {FORWARDING_NODE,
-                                         "", /* This node has no interface. */
-                                         1};
-
 #if defined(HANDLE_ZAPI_FUZZING)
 void zserv_read_file(char *input)
 {
@@ -3298,34 +3110,12 @@ void zserv_read_file(char *input)
 }
 #endif
 
-/* Initialisation of zebra and installation of commands. */
-void zebra_init(void)
+void zserv_init(void)
 {
        /* Client list init. */
        zebrad.client_list = list_new();
        zebrad.client_list->del = (void (*)(void *))zebra_client_free;
 
-       /* Install configuration write function. */
-       install_node(&table_node, config_write_table);
-       install_node(&forwarding_node, config_write_forwarding);
-
-       install_element(VIEW_NODE, &show_ip_forwarding_cmd);
-       install_element(CONFIG_NODE, &ip_forwarding_cmd);
-       install_element(CONFIG_NODE, &no_ip_forwarding_cmd);
-       install_element(ENABLE_NODE, &show_zebra_cmd);
        install_element(ENABLE_NODE, &show_zebra_client_cmd);
        install_element(ENABLE_NODE, &show_zebra_client_summary_cmd);
-
-#ifdef HAVE_NETLINK
-       install_element(VIEW_NODE, &show_table_cmd);
-       install_element(CONFIG_NODE, &config_table_cmd);
-       install_element(CONFIG_NODE, &no_config_table_cmd);
-#endif /* HAVE_NETLINK */
-
-       install_element(VIEW_NODE, &show_ipv6_forwarding_cmd);
-       install_element(CONFIG_NODE, &ipv6_forwarding_cmd);
-       install_element(CONFIG_NODE, &no_ipv6_forwarding_cmd);
-
-       /* Route-map */
-       zebra_route_map_init();
 }
index 6077dc105a42e26cb50c55d2d14d03ae42bf9302..4b3b0041b845faa8fd7d227c8b15705fac96ecf3 100644 (file)
@@ -110,6 +110,8 @@ 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;
 
@@ -148,22 +150,8 @@ extern struct zebra_t zebrad;
 extern unsigned int multipath_num;
 
 /* Prototypes. */
-extern void zebra_init(void);
-extern void zebra_if_init(void);
+extern void zserv_init(void);
 extern void zebra_zserv_socket_init(char *path);
-extern void hostinfo_get(void);
-extern void rib_init(void);
-extern void interface_list(struct zebra_ns *);
-extern void route_read(struct zebra_ns *);
-extern void macfdb_read(struct zebra_ns *);
-extern void macfdb_read_for_bridge(struct zebra_ns *, struct interface *,
-                                  struct interface *);
-extern void neigh_read(struct zebra_ns *);
-extern void neigh_read_for_vlan(struct zebra_ns *, struct interface *);
-extern void kernel_init(struct zebra_ns *);
-extern void kernel_terminate(struct zebra_ns *);
-extern void zebra_route_map_init(void);
-extern void zebra_vty_init(void);
 
 extern int zsend_vrf_add(struct zserv *, struct zebra_vrf *);
 extern int zsend_vrf_delete(struct zserv *, struct zebra_vrf *);
@@ -189,10 +177,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 pid_t pid;
-
-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);