[prev in list] [next in list] [prev in thread] [next in thread] 

List:       quagga-dev
Subject:    [quagga-dev 14366] [PATCH 19/25] bgpd: encap: add encap SAFI (RFC5512)
From:       Lou Berger <lberger () labn ! net>
Date:       2015-12-24 18:10:24
Message-ID: 1450980630-11805-20-git-send-email-lberger () labn ! net
[Download RAW message or body]

This is part of the core VPN and Encap SAFI changes. 

Adds RFC5512 and a (per DL) non-compliant version of Encapsulation Attribute.

Signed-off-by: Lou Berger <lberger@labn.net>
Reviewed-by: David Lamparter <equinox@opensourcerouting.org>
---
 bgpd/Makefile.am  |   4 +-
 bgpd/bgp_attr.c   |  57 ++++
 bgpd/bgp_encap.c  | 991 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 bgpd/bgp_encap.h  |  34 ++
 bgpd/bgp_open.c   |  32 +-
 bgpd/bgp_packet.c |  49 +++
 bgpd/bgp_route.c  | 235 ++++++++-----
 bgpd/bgp_route.h  |   3 +
 bgpd/bgp_vty.c    | 222 ++++++++++++
 bgpd/bgpd.c       |  19 +-
 10 files changed, 1561 insertions(+), 85 deletions(-)
 create mode 100644 bgpd/bgp_encap.c
 create mode 100644 bgpd/bgp_encap.h

diff --git a/bgpd/Makefile.am b/bgpd/Makefile.am
index 82c69ea..7da4dd8 100644
--- a/bgpd/Makefile.am
+++ b/bgpd/Makefile.am
@@ -16,7 +16,7 @@ libbgp_a_SOURCES = \
 	bgp_packet.c bgp_network.c bgp_filter.c bgp_regex.c bgp_clist.c \
 	bgp_dump.c bgp_snmp.c bgp_ecommunity.c bgp_mplsvpn.c bgp_nexthop.c \
 	bgp_damp.c bgp_table.c bgp_advertise.c bgp_vty.c bgp_mpath.c \
-	bgp_encap_tlv.c
+	bgp_encap.c bgp_encap_tlv.c
 
 noinst_HEADERS = \
 	bgp_aspath.h bgp_attr.h bgp_community.h bgp_debug.h bgp_fsm.h \
@@ -24,7 +24,7 @@ noinst_HEADERS = \
 	bgpd.h bgp_filter.h bgp_clist.h bgp_dump.h bgp_zebra.h \
 	bgp_ecommunity.h bgp_mplsvpn.h bgp_nexthop.h bgp_damp.h bgp_table.h \
 	bgp_advertise.h bgp_snmp.h bgp_vty.h bgp_mpath.h \
-	bgp_encap_tlv.h bgp_encap_types.h
+	bgp_encap.h bgp_encap_tlv.h bgp_encap_types.h
 
 bgpd_SOURCES = bgp_main.c
 bgpd_LDADD = libbgp.a ../lib/libzebra.la @LIBCAP@ @LIBM@
diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c
index a5f5ea1..3909669 100644
--- a/bgpd/bgp_attr.c
+++ b/bgpd/bgp_attr.c
@@ -2426,6 +2426,10 @@ bgp_packet_mpattr_start (struct stream *s, afi_t afi, safi_t \
safi,  stream_putl (s, 0);
 	  stream_put (s, &attr->extra->mp_nexthop_global_in, 4);
 	  break;
+	case SAFI_ENCAP:
+	  stream_putc (s, 4);
+	  stream_put (s, &attr->extra->mp_nexthop_global_in, 4);
+	  break;
 	default:
 	  break;
 	}
@@ -2467,6 +2471,11 @@ bgp_packet_mpattr_start (struct stream *s, afi_t afi, safi_t \
safi,  }
         }
 	break;
+	case SAFI_ENCAP:
+          assert (attr->extra);
+          stream_putc (s, 16);
+	  stream_put (s, &attr->extra->mp_nexthop_global, 16);
+	  break;
       default:
 	break;
       }
@@ -2948,6 +2957,54 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
       stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
     }
   
+  if ((p->family == AF_INET
+#ifdef HAVE_IPV6
+  || p->family == AF_INET6
+#endif
+  ) &&
+    ((safi == SAFI_ENCAP) || (safi == SAFI_MPLS_VPN)))
+    {
+        struct bgp_attr_encap_subtlv *pEncap;
+        unsigned int	              attrlenfield = 0;
+	/* Tunnel Encap attribute */
+	bgp_packet_mpattr_tea(bgp, peer, s, attr, BGP_ATTR_ENCAP);
+
+      /* compute attr length */
+      if (attr && attr->extra && attr->extra->encap_subtlvs) {
+	for (pEncap = attr->extra->encap_subtlvs; pEncap; pEncap = pEncap->next) {
+	  attrlenfield += (4 + pEncap->length);
+	}
+      }
+
+      if (attrlenfield) { /* only make attr if subtlvs exist */
+	  if (attrlenfield > 0xffff) {
+	    zlog (peer->log, LOG_ERR, 
+		"Tunnel Encap attribute is too long (length=%d), can't send it",
+		attrlenfield);
+	  } else {
+	    if (attrlenfield > 0xff) {
+	      /* 2-octet length field */
+	      stream_putc (s,
+		BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN);
+	      stream_putc (s, BGP_ATTR_ENCAP);
+	      stream_putw (s, attrlenfield & 0xffff);
+	    } else {
+	      /* 1-octet length field */
+	      stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL);
+	      stream_putc (s, BGP_ATTR_ENCAP);
+	      stream_putc (s, attrlenfield & 0xff);
+	    }
+
+	    /* write each sub-tlv */
+	    for (pEncap = attr->extra->encap_subtlvs; pEncap; pEncap = pEncap->next) {
+	      stream_putw (s, pEncap->type);
+	      stream_putw (s, pEncap->length);
+	      stream_put (s, pEncap->value, pEncap->length);
+	    }
+	  }
+       }
+    }
+
   /* Unknown transit attribute. */
   if (attr->extra && attr->extra->transit)
     stream_put (s, attr->extra->transit->val, attr->extra->transit->length);
diff --git a/bgpd/bgp_encap.c b/bgpd/bgp_encap.c
new file mode 100644
index 0000000..235492d
--- /dev/null
+++ b/bgpd/bgp_encap.c
@@ -0,0 +1,991 @@
+
+/*
+ * This file created by LabN Consulting, L.L.C.
+ *
+ *
+ * This file is based on bgp_mplsvpn.c which is Copyright (C) 2000
+ * Kunihiro Ishiguro <kunihiro@zebra.org>
+ *
+ */
+
+/* 
+
+This file is part of GNU Zebra.
+
+GNU Zebra is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+GNU Zebra 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 GNU Zebra; see the file COPYING.  If not, write to the Free
+Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
+
+#include <zebra.h>
+
+#include "command.h"
+#include "prefix.h"
+#include "log.h"
+#include "memory.h"
+#include "stream.h"
+
+#include "bgpd/bgpd.h"
+#include "bgpd/bgp_table.h"
+#include "bgpd/bgp_route.h"
+#include "bgpd/bgp_attr.h"
+#include "bgpd/bgp_ecommunity.h"
+#include "bgpd/bgp_mplsvpn.h"
+#include "bgpd/bgp_vty.h"
+#include "bgpd/bgp_encap.h"
+
+static u_int16_t
+decode_rd_type (u_char *pnt)
+{
+  u_int16_t v;
+  
+  v = ((u_int16_t) *pnt++ << 8);
+  v |= (u_int16_t) *pnt;
+  return v;
+}
+
+
+static void
+decode_rd_as (u_char *pnt, struct rd_as *rd_as)
+{
+  rd_as->as  = (u_int16_t) *pnt++ << 8;
+  rd_as->as |= (u_int16_t) *pnt++;
+  
+  rd_as->val  = ((u_int32_t) *pnt++) << 24;
+  rd_as->val |= ((u_int32_t) *pnt++) << 16;
+  rd_as->val |= ((u_int32_t) *pnt++) << 8;
+  rd_as->val |= (u_int32_t) *pnt;
+}
+
+static void
+decode_rd_as4 (u_char *pnt, struct rd_as *rd_as)
+{
+  rd_as->as  = (u_int32_t) *pnt++ << 24;
+  rd_as->as |= (u_int32_t) *pnt++ << 16;
+  rd_as->as |= (u_int32_t) *pnt++ << 8;
+  rd_as->as |= (u_int32_t) *pnt++;
+  
+  rd_as->val  = ((u_int32_t) *pnt++ << 8);
+  rd_as->val |= (u_int32_t) *pnt;
+}
+
+static void
+decode_rd_ip (u_char *pnt, struct rd_ip *rd_ip)
+{
+  memcpy (&rd_ip->ip, pnt, 4);
+  pnt += 4;
+  
+  rd_ip->val = ((u_int16_t) *pnt++ << 8);
+  rd_ip->val |= (u_int16_t) *pnt;
+}
+
+static void
+ecom2prd(struct ecommunity *ecom, struct prefix_rd *prd)
+{
+    int	i;
+
+    memset(prd, 0, sizeof(struct prefix_rd));
+    prd->family = AF_UNSPEC;
+    prd->prefixlen = 64;
+
+    if (!ecom)
+	return;
+
+    for (i = 0; i < (ecom->size * ECOMMUNITY_SIZE); i += ECOMMUNITY_SIZE) {
+
+	uint8_t *ep;
+
+	ep = ecom->val + i;
+
+	switch (ep[0]) {
+	    default:
+		continue;
+
+	    case 0x80:
+	    case 0x81:
+	    case 0x82:
+		if (ep[1] == 0x0) {
+		    prd->val[1] = ep[0] & 0x03;
+		    memcpy(prd->val + 2, ep + 2, 6);
+		    return;
+		}
+	}
+    }
+}
+
+int
+bgp_nlri_parse_encap(
+    afi_t		afi,
+    struct peer		*peer,
+    struct attr		*attr, 		/* Need even for withdraw */
+    struct bgp_nlri	*packet,
+    int			withdraw)	/* 0=update, !0 = withdraw */
+{
+  u_char *pnt;
+  u_char *lim;
+  struct prefix p;
+  int psize = 0;
+  int prefixlen;
+  struct rd_as rd_as;
+  struct rd_ip rd_ip;
+  struct prefix_rd prd;
+  struct ecommunity *pEcom = NULL;
+  u_int16_t rdtype = 0xffff;
+  char buf[BUFSIZ];
+
+  /* Check peer status. */
+  if (peer->status != Established)
+    return 0;
+  
+  /* Make prefix_rd */
+  if (attr && attr->extra && attr->extra->ecommunity)
+      pEcom = attr->extra->ecommunity;
+
+  ecom2prd(pEcom, &prd);
+  memset(&rd_as, 0, sizeof(rd_as));
+  memset(&rd_ip, 0, sizeof(rd_ip));
+
+  if (pEcom) {
+
+      rdtype = (prd.val[0] << 8) | prd.val[1];
+
+      /* Decode RD value. */
+      if (rdtype == RD_TYPE_AS)
+	decode_rd_as (prd.val + 2, &rd_as);
+      else if (rdtype == RD_TYPE_IP)
+	decode_rd_ip (prd.val + 2, &rd_ip);
+      else if (rdtype == RD_TYPE_AS4)
+	decode_rd_as4 (prd.val + 2, &rd_as);
+      else
+	{
+	  zlog_err ("Invalid RD type %d", rdtype);
+	}
+
+  }
+
+  /*
+   * NB: this code was based on the MPLS VPN code, which supported RDs.
+   * For the moment we are retaining the underlying RIB structure that
+   * keeps a per-RD radix tree, but since the RDs are not carried over
+   * the wire, we set the RD internally to 0.
+   */
+  prd.family = AF_UNSPEC;
+  prd.prefixlen = 64;
+  memset(prd.val, 0, sizeof(prd.val));
+
+  pnt = packet->nlri;
+  lim = pnt + packet->length;
+
+  for (; pnt < lim; pnt += psize)
+    {
+      /* Clear prefix structure. */
+      memset (&p, 0, sizeof (struct prefix));
+
+      /* Fetch prefix length. */
+      prefixlen = *pnt++;
+      p.family = afi2family(afi);
+      if (p.family == 0) {
+	/* bad afi, shouldn't happen */
+	zlog_warn("%s: bad afi %d, dropping incoming route", __func__, afi);
+	continue;
+      }
+      psize = PSIZE (prefixlen);
+
+      p.prefixlen = prefixlen;
+      memcpy (&p.u.prefix, pnt, psize);
+
+      if (pnt + psize > lim)
+	return -1;
+
+
+      if (rdtype == RD_TYPE_AS)
+	zlog_info ("rd-as %u:%u prefix %s/%d", rd_as.as, rd_as.val,
+		   inet_ntop (p.family, &p.u.prefix, buf, BUFSIZ),
+		   p.prefixlen);
+      else if (rdtype == RD_TYPE_IP)
+	zlog_info ("rd-ip %s:%u prefix %s/%d", inet_ntoa (rd_ip.ip),
+		   rd_ip.val,
+		   inet_ntop (p.family, &p.u.prefix, buf, BUFSIZ),
+		   p.prefixlen);
+      else if (rdtype == RD_TYPE_AS4)
+	zlog_info ("rd-as4 %u:%u prefix %s/%d", rd_as.as, rd_as.val,
+		   inet_ntop (p.family, &p.u.prefix, buf, BUFSIZ),
+		   p.prefixlen);
+      else
+	zlog_info ("rd unknown, default to 0:0 prefix %s/%d",
+	    inet_ntop (p.family, &p.u.prefix, buf, BUFSIZ),
+	    p.prefixlen);
+
+      if (!withdraw) {
+	bgp_update (peer, &p, attr, afi, SAFI_ENCAP,
+		    ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, NULL, 0);
+      } else {
+	bgp_withdraw (peer, &p, attr, afi, SAFI_ENCAP,
+		      ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, NULL);
+      }
+    }
+
+  /* Packet length consistency check. */
+  if (pnt != lim)
+    return -1;
+
+  return 0;
+}
+
+
+/* TBD: these routes should probably all be host routes */
+
+/* For testing purpose, static route of ENCAP. */
+DEFUN (encap_network,
+       encap_network_cmd,
+       "network A.B.C.D/M rd ASN:nn_or_IP-address:nn tag WORD",
+       "Specify a network to announce via BGP\n"
+       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+       "Specify Route Distinguisher\n"
+       "ENCAP Route Distinguisher\n"
+       "BGP tag\n"
+       "tag value\n")
+{
+  return bgp_static_set_safi (SAFI_ENCAP, vty, argv[0], argv[1], argv[2], NULL);
+}
+
+/* For testing purpose, static route of ENCAP. */
+DEFUN (no_encap_network,
+       no_encap_network_cmd,
+       "no network A.B.C.D/M rd ASN:nn_or_IP-address:nn tag WORD",
+       NO_STR
+       "Specify a network to announce via BGP\n"
+       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+       "Specify Route Distinguisher\n"
+       "ENCAP Route Distinguisher\n"
+       "BGP tag\n"
+       "tag value\n")
+{
+  return bgp_static_unset_safi (SAFI_ENCAP, vty, argv[0], argv[1], argv[2]);
+}
+
+static int
+show_adj_route_encap (struct vty *vty, struct peer *peer, struct prefix_rd *prd)
+{
+  struct bgp *bgp;
+  struct bgp_table *table;
+  struct bgp_node *rn;
+  struct bgp_node *rm;
+  struct attr *attr;
+  int rd_header;
+  int header = 1;
+  char v4_header[] = "   Network          Next Hop            Metric LocPrf Weight \
Path%s"; +
+  bgp = bgp_get_default ();
+  if (bgp == NULL)
+    {
+      vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  for (rn = bgp_table_top (bgp->rib[AFI_IP][SAFI_ENCAP]); rn;
+       rn = bgp_route_next (rn))
+    {
+      if (prd && memcmp (rn->p.u.val, prd->val, 8) != 0)
+        continue;
+
+      if ((table = rn->info) != NULL)
+        {
+          rd_header = 1;
+
+          for (rm = bgp_table_top (table); rm; rm = bgp_route_next (rm))
+            if ((attr = rm->info) != NULL)
+              {
+                if (header)
+                  {
+                    vty_out (vty, "BGP table version is 0, local router ID is %s%s",
+                             inet_ntoa (bgp->router_id), VTY_NEWLINE);
+                    vty_out (vty, "Status codes: s suppressed, d damped, h history, \
* valid, > best, i - internal%s", +                             VTY_NEWLINE);
+                    vty_out (vty, "Origin codes: i - IGP, e - EGP, ? - \
incomplete%s%s", +                             VTY_NEWLINE, VTY_NEWLINE);
+                    vty_out (vty, v4_header, VTY_NEWLINE);
+                    header = 0;
+                  }
+
+                if (rd_header)
+                  {
+                    u_int16_t type;
+                    struct rd_as rd_as;
+                    struct rd_ip rd_ip;
+                    u_char *pnt;
+
+                    pnt = rn->p.u.val;
+
+                    vty_out (vty, "Route Distinguisher: ");
+
+                    /* Decode RD type. */
+                    type = decode_rd_type (pnt);
+
+		    switch (type) {
+
+		    case RD_TYPE_AS:
+                      decode_rd_as (pnt + 2, &rd_as);
+                      vty_out (vty, "%u:%d", rd_as.as, rd_as.val);
+		      break;
+
+		    case RD_TYPE_IP:
+                      decode_rd_ip (pnt + 2, &rd_ip);
+                      vty_out (vty, "%s:%d", inet_ntoa (rd_ip.ip), rd_ip.val);
+		      break;
+
+		    default:
+                      vty_out (vty, "unknown RD type");
+		    }
+
+
+                    vty_out (vty, "%s", VTY_NEWLINE);
+                    rd_header = 0;
+                  }
+                route_vty_out_tmp (vty, &rm->p, attr, SAFI_ENCAP);
+              }
+        }
+    }
+  return CMD_SUCCESS;
+}
+
+enum bgp_show_type
+{
+  bgp_show_type_normal,
+  bgp_show_type_regexp,
+  bgp_show_type_prefix_list,
+  bgp_show_type_filter_list,
+  bgp_show_type_neighbor,
+  bgp_show_type_cidr_only,
+  bgp_show_type_prefix_longer,
+  bgp_show_type_community_all,
+  bgp_show_type_community,
+  bgp_show_type_community_exact,
+  bgp_show_type_community_list,
+  bgp_show_type_community_list_exact
+};
+
+static int
+bgp_show_encap (
+    struct vty *vty,
+    afi_t afi,
+    struct prefix_rd *prd,
+    enum bgp_show_type type,
+    void *output_arg,
+    int tags)
+{
+  struct bgp *bgp;
+  struct bgp_table *table;
+  struct bgp_node *rn;
+  struct bgp_node *rm;
+  struct bgp_info *ri;
+  int rd_header;
+  int header = 1;
+  char v4_header[] = "   Network          Next Hop            Metric LocPrf Weight \
Path%s"; +  char v4_header_tag[] = "   Network          Next Hop      In tag/Out \
tag%s"; +
+  unsigned long output_count = 0;
+  unsigned long total_count  = 0;
+
+  bgp = bgp_get_default ();
+  if (bgp == NULL)
+    {
+      vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  if ((afi != AFI_IP) && (afi != AFI_IP6)) {
+      vty_out (vty, "Afi %d not supported%s", afi, VTY_NEWLINE);
+      return CMD_WARNING;
+  }
+  
+  for (rn = bgp_table_top (bgp->rib[afi][SAFI_ENCAP]); rn; rn = bgp_route_next (rn))
+    {
+      if (prd && memcmp (rn->p.u.val, prd->val, 8) != 0)
+	continue;
+
+      if ((table = rn->info) != NULL)
+	{
+	  rd_header = 1;
+
+	  for (rm = bgp_table_top (table); rm; rm = bgp_route_next (rm))
+	    for (ri = rm->info; ri; ri = ri->next)
+	      {
+                total_count++;
+		if (type == bgp_show_type_neighbor)
+		  {
+		    union sockunion *su = output_arg;
+
+		    if (ri->peer->su_remote == NULL || ! sockunion_same(ri->peer->su_remote, su))
+		      continue;
+		  }
+		if (header)
+		  {
+		    if (tags)
+		      vty_out (vty, v4_header_tag, VTY_NEWLINE);
+		    else
+		      {
+			vty_out (vty, "BGP table version is 0, local router ID is %s%s",
+				 inet_ntoa (bgp->router_id), VTY_NEWLINE);
+			vty_out (vty, "Status codes: s suppressed, d damped, h history, * valid, > best, \
i - internal%s", +				 VTY_NEWLINE);
+			vty_out (vty, "Origin codes: i - IGP, e - EGP, ? - incomplete%s%s",
+				 VTY_NEWLINE, VTY_NEWLINE);
+			vty_out (vty, v4_header, VTY_NEWLINE);
+		      }
+		    header = 0;
+		  }
+
+		if (rd_header)
+		  {
+		    u_int16_t type;
+		    struct rd_as rd_as;
+		    struct rd_ip rd_ip;
+		    u_char *pnt;
+
+		    pnt = rn->p.u.val;
+
+		    /* Decode RD type. */
+		    type = decode_rd_type (pnt);
+
+		    vty_out (vty, "Route Distinguisher: ");
+
+		    switch (type) {
+
+		    case RD_TYPE_AS:
+		      decode_rd_as (pnt + 2, &rd_as);
+		      vty_out (vty, "%u:%d", rd_as.as, rd_as.val);
+		      break;
+
+		    case RD_TYPE_IP:
+		      decode_rd_ip (pnt + 2, &rd_ip);
+		      vty_out (vty, "%s:%d", inet_ntoa (rd_ip.ip), rd_ip.val);
+		      break;
+
+		    default:
+		      vty_out (vty, "Unknown RD type");
+		      break;
+		    }
+
+		    vty_out (vty, "%s", VTY_NEWLINE);		  
+		    rd_header = 0;
+		  }
+	        if (tags)
+		  route_vty_out_tag (vty, &rm->p, ri, 0, SAFI_ENCAP);
+	        else
+		  route_vty_out (vty, &rm->p, ri, 0, SAFI_ENCAP, 0);
+                output_count++;
+	      }
+        }
+    }
+
+  if (output_count == 0)
+    {
+        vty_out (vty, "No prefixes displayed, %ld exist%s", total_count, \
VTY_NEWLINE); +    }
+  else
+    vty_out (vty, "%sDisplayed %ld out of %ld total prefixes%s",
+	     VTY_NEWLINE, output_count, total_count, VTY_NEWLINE);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (show_bgp_ipv4_encap,
+       show_bgp_ipv4_encap_cmd,
+       "show bgp ipv4 encap",
+       SHOW_STR
+       BGP_STR
+       "Address Family\n"
+       "Display ENCAP NLRI specific information\n")
+{
+  return bgp_show_encap (vty, AFI_IP, NULL, bgp_show_type_normal, NULL, 0);
+}
+#ifdef HAVE_IPV6
+DEFUN (show_bgp_ipv6_encap,
+       show_bgp_ipv6_encap_cmd,
+       "show bgp ipv6 encap",
+       SHOW_STR
+       BGP_STR
+       "Address Family\n"
+       "Display ENCAP NLRI specific information\n")
+{
+  return bgp_show_encap (vty, AFI_IP6, NULL, bgp_show_type_normal, NULL, 0);
+}
+#endif
+
+DEFUN (show_bgp_ipv4_encap_rd,
+       show_bgp_ipv4_encap_rd_cmd,
+       "show bgp ipv4 encap rd ASN:nn_or_IP-address:nn",
+       SHOW_STR
+       BGP_STR
+       "Address Family\n"
+       "Display ENCAP NLRI specific information\n"
+       "Display information for a route distinguisher\n"
+       "ENCAP Route Distinguisher\n")
+{
+  int ret;
+  struct prefix_rd prd;
+
+  ret = str2prefix_rd (argv[0], &prd);
+  if (! ret)
+    {
+      vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  return bgp_show_encap (vty, AFI_IP, &prd, bgp_show_type_normal, NULL, 0);
+}
+#ifdef HAVE_IPV6
+DEFUN (show_bgp_ipv6_encap_rd,
+       show_bgp_ipv6_encap_rd_cmd,
+       "show bgp ipv6 encap rd ASN:nn_or_IP-address:nn",
+       SHOW_STR
+       BGP_STR
+       "Address Family\n"
+       "Display ENCAP NLRI specific information\n"
+       "Display information for a route distinguisher\n"
+       "ENCAP Route Distinguisher\n"
+       "Display BGP tags for prefixes\n")
+{
+  int ret;
+  struct prefix_rd prd;
+
+  ret = str2prefix_rd (argv[0], &prd);
+  if (! ret)
+    {
+      vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  return bgp_show_encap (vty, AFI_IP6, &prd, bgp_show_type_normal, NULL, 0);
+}
+#endif
+
+DEFUN (show_bgp_ipv4_encap_tags,
+       show_bgp_ipv4_encap_tags_cmd,
+       "show bgp ipv4 encap tags",
+       SHOW_STR
+       BGP_STR
+       "Address Family\n"
+       "Display ENCAP NLRI specific information\n"
+       "Display BGP tags for prefixes\n")
+{
+  return bgp_show_encap (vty, AFI_IP, NULL, bgp_show_type_normal, NULL,  1);
+}
+#ifdef HAVE_IPV6
+DEFUN (show_bgp_ipv6_encap_tags,
+       show_bgp_ipv6_encap_tags_cmd,
+       "show bgp ipv6 encap tags",
+       SHOW_STR
+       BGP_STR
+       "Address Family\n"
+       "Display ENCAP NLRI specific information\n"
+       "Display BGP tags for prefixes\n")
+{
+  return bgp_show_encap (vty, AFI_IP6, NULL, bgp_show_type_normal, NULL,  1);
+}
+#endif
+
+DEFUN (show_bgp_ipv4_encap_rd_tags,
+       show_bgp_ipv4_encap_rd_tags_cmd,
+       "show bgp ipv4 encap rd ASN:nn_or_IP-address:nn tags",
+       SHOW_STR
+       BGP_STR
+       "Address Family\n"
+       "Display ENCAP NLRI specific information\n"
+       "Display information for a route distinguisher\n"
+       "ENCAP Route Distinguisher\n"
+       "Display BGP tags for prefixes\n")
+{
+  int ret;
+  struct prefix_rd prd;
+
+  ret = str2prefix_rd (argv[0], &prd);
+  if (! ret)
+    {
+      vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  return bgp_show_encap (vty, AFI_IP, &prd, bgp_show_type_normal, NULL, 1);
+}
+#ifdef HAVE_IPV6
+DEFUN (show_bgp_ipv6_encap_rd_tags,
+       show_bgp_ipv6_encap_rd_tags_cmd,
+       "show bgp ipv6 encap rd ASN:nn_or_IP-address:nn tags",
+       SHOW_STR
+       BGP_STR
+       "Address Family\n"
+       "Display ENCAP NLRI specific information\n"
+       "Display information for a route distinguisher\n"
+       "ENCAP Route Distinguisher\n"
+       "Display BGP tags for prefixes\n")
+{
+  int ret;
+  struct prefix_rd prd;
+
+  ret = str2prefix_rd (argv[0], &prd);
+  if (! ret)
+    {
+      vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  return bgp_show_encap (vty, AFI_IP6, &prd, bgp_show_type_normal, NULL, 1);
+}
+#endif
+
+DEFUN (show_bgp_ipv4_encap_neighbor_routes,
+       show_bgp_ipv4_encap_neighbor_routes_cmd,
+       "show bgp ipv4 encap neighbors A.B.C.D routes",
+       SHOW_STR
+       BGP_STR
+       "Address Family\n"
+       "Display ENCAP NLRI specific information\n"
+       "Detailed information on TCP and BGP neighbor connections\n"
+       "Neighbor to display information about\n"
+       "Display routes learned from neighbor\n")
+{
+  union sockunion *su;
+  struct peer *peer;
+  
+  su = sockunion_str2su (argv[0]);
+  if (su == NULL)
+    {
+      vty_out (vty, "Malformed address: %s%s", argv[0], VTY_NEWLINE);
+               return CMD_WARNING;
+    }
+
+  peer = peer_lookup (NULL, su);
+  if (! peer || ! peer->afc[AFI_IP][SAFI_ENCAP])
+    {
+      vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  return bgp_show_encap (vty, AFI_IP, NULL, bgp_show_type_neighbor, su, 0);
+}
+#ifdef HAVE_IPV6
+DEFUN (show_bgp_ipv6_encap_neighbor_routes,
+       show_bgp_ipv6_encap_neighbor_routes_cmd,
+       "show bgp ipv6 encap neighbors A.B.C.D routes",
+       SHOW_STR
+       BGP_STR
+       "Address Family\n"
+       "Display ENCAP NLRI specific information\n"
+       "Detailed information on TCP and BGP neighbor connections\n"
+       "Neighbor to display information about\n"
+       "Display routes learned from neighbor\n")
+{
+  union sockunion *su;
+  struct peer *peer;
+  
+  su = sockunion_str2su (argv[0]);
+  if (su == NULL)
+    {
+      vty_out (vty, "Malformed address: %s%s", argv[0], VTY_NEWLINE);
+               return CMD_WARNING;
+    }
+
+  peer = peer_lookup (NULL, su);
+  if (! peer || ! peer->afc[AFI_IP6][SAFI_ENCAP])
+    {
+      vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  return bgp_show_encap (vty, AFI_IP6, NULL, bgp_show_type_neighbor, su, 0);
+}
+#endif
+
+DEFUN (show_bgp_ipv4_encap_rd_neighbor_routes,
+       show_bgp_ipv4_encap_rd_neighbor_routes_cmd,
+       "show bgp ipv4 encap rd ASN:nn_or_IP-address:nn neighbors (A.B.C.D|X:X::X:X) \
routes", +       SHOW_STR
+       BGP_STR
+       "Address Family\n"
+       "Display ENCAP NLRI specific information\n"
+       "Display information for a route distinguisher\n"
+       "ENCAP Route Distinguisher\n"
+       "Detailed information on TCP and BGP neighbor connections\n"
+       "Neighbor to display information about\n"
+       "Neighbor to display information about\n"
+       "Display routes learned from neighbor\n")
+{
+  int ret;
+  union sockunion *su;
+  struct peer *peer;
+  struct prefix_rd prd;
+
+  ret = str2prefix_rd (argv[0], &prd);
+  if (! ret)
+    {
+      vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  su = sockunion_str2su (argv[1]);
+  if (su == NULL)
+    {
+      vty_out (vty, "Malformed address: %s%s", argv[1], VTY_NEWLINE);
+               return CMD_WARNING;
+    }
+
+  peer = peer_lookup (NULL, su);
+  if (! peer || ! peer->afc[AFI_IP][SAFI_ENCAP])
+    {
+      vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  return bgp_show_encap (vty, AFI_IP, &prd, bgp_show_type_neighbor, su, 0);
+}
+#ifdef HAVE_IPV6
+DEFUN (show_bgp_ipv6_encap_rd_neighbor_routes,
+       show_bgp_ipv6_encap_rd_neighbor_routes_cmd,
+       "show bgp ipv6 encap rd ASN:nn_or_IP-address:nn neighbors (A.B.C.D|X:X::X:X) \
routes", +       SHOW_STR
+       BGP_STR
+       "Address Family\n"
+       "Display ENCAP NLRI specific information\n"
+       "Display information for a route distinguisher\n"
+       "ENCAP Route Distinguisher\n"
+       "Detailed information on TCP and BGP neighbor connections\n"
+       "Neighbor to display information about\n"
+       "Neighbor to display information about\n"
+       "Display routes learned from neighbor\n")
+{
+  int ret;
+  union sockunion *su;
+  struct peer *peer;
+  struct prefix_rd prd;
+
+  ret = str2prefix_rd (argv[0], &prd);
+  if (! ret)
+    {
+      vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  su = sockunion_str2su (argv[1]);
+  if (su == NULL)
+    {
+      vty_out (vty, "Malformed address: %s%s", argv[1], VTY_NEWLINE);
+               return CMD_WARNING;
+    }
+
+  peer = peer_lookup (NULL, su);
+  if (! peer || ! peer->afc[AFI_IP6][SAFI_ENCAP])
+    {
+      vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  return bgp_show_encap (vty, AFI_IP6, &prd, bgp_show_type_neighbor, su, 0);
+}
+#endif
+
+DEFUN (show_bgp_ipv4_encap_neighbor_advertised_routes,
+       show_bgp_ipv4_encap_neighbor_advertised_routes_cmd,
+       "show bgp ipv4 encap neighbors A.B.C.D advertised-routes",
+       SHOW_STR
+       BGP_STR
+       "Address Family\n"
+       "Display ENCAP NLRI specific information\n"
+       "Detailed information on TCP and BGP neighbor connections\n"
+       "Neighbor to display information about\n"
+       "Display the routes advertised to a BGP neighbor\n")
+{
+  int ret;
+  struct peer *peer;
+  union sockunion su;
+
+  ret = str2sockunion (argv[0], &su);
+  if (ret < 0)
+    {
+      vty_out (vty, "%% Malformed address: %s%s", argv[0], VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  peer = peer_lookup (NULL, &su);
+  if (! peer || ! peer->afc[AFI_IP][SAFI_ENCAP])
+    {
+      vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  return show_adj_route_encap (vty, peer, NULL);
+}
+#ifdef HAVE_IPV6
+DEFUN (show_bgp_ipv6_encap_neighbor_advertised_routes,
+       show_bgp_ipv6_encap_neighbor_advertised_routes_cmd,
+       "show bgp ipv6 encap neighbors A.B.C.D advertised-routes",
+       SHOW_STR
+       BGP_STR
+       "Address Family\n"
+       "Display ENCAP NLRI specific information\n"
+       "Detailed information on TCP and BGP neighbor connections\n"
+       "Neighbor to display information about\n"
+       "Display the routes advertised to a BGP neighbor\n")
+{
+  int ret;
+  struct peer *peer;
+  union sockunion su;
+
+  ret = str2sockunion (argv[0], &su);
+  if (ret < 0)
+    {
+      vty_out (vty, "%% Malformed address: %s%s", argv[0], VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  peer = peer_lookup (NULL, &su);
+  if (! peer || ! peer->afc[AFI_IP6][SAFI_ENCAP])
+    {
+      vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  return show_adj_route_encap (vty, peer, NULL);
+}
+#endif
+
+DEFUN (show_bgp_ipv4_encap_rd_neighbor_advertised_routes,
+       show_bgp_ipv4_encap_rd_neighbor_advertised_routes_cmd,
+       "show bgp ipv4 encap rd ASN:nn_or_IP-address:nn neighbors (A.B.C.D|X:X::X:X) \
advertised-routes", +       SHOW_STR
+       BGP_STR
+       "Address Family\n"
+       "Display ENCAP NLRI specific information\n"
+       "Display information for a route distinguisher\n"
+       "ENCAP Route Distinguisher\n"
+       "Detailed information on TCP and BGP neighbor connections\n"
+       "Neighbor to display information about\n"
+       "Neighbor to display information about\n"
+       "Display the routes advertised to a BGP neighbor\n")
+{
+  int ret;
+  struct peer *peer;
+  struct prefix_rd prd;
+  union sockunion su;
+
+  ret = str2sockunion (argv[1], &su);
+  if (ret < 0)
+    {
+      vty_out (vty, "%% Malformed address: %s%s", argv[1], VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  peer = peer_lookup (NULL, &su);
+  if (! peer || ! peer->afc[AFI_IP][SAFI_ENCAP])
+    {
+      vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  ret = str2prefix_rd (argv[0], &prd);
+  if (! ret)
+    {
+      vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  return show_adj_route_encap (vty, peer, &prd);
+}
+#ifdef HAVE_IPV6
+DEFUN (show_bgp_ipv6_encap_rd_neighbor_advertised_routes,
+       show_bgp_ipv6_encap_rd_neighbor_advertised_routes_cmd,
+       "show bgp ipv6 encap rd ASN:nn_or_IP-address:nn neighbors (A.B.C.D|X:X::X:X) \
advertised-routes", +       SHOW_STR
+       BGP_STR
+       "Address Family\n"
+       "Display ENCAP NLRI specific information\n"
+       "Display information for a route distinguisher\n"
+       "ENCAP Route Distinguisher\n"
+       "Detailed information on TCP and BGP neighbor connections\n"
+       "Neighbor to display information about\n"
+       "Neighbor to display information about\n"
+       "Display the routes advertised to a BGP neighbor\n")
+{
+  int ret;
+  struct peer *peer;
+  struct prefix_rd prd;
+  union sockunion su;
+
+  ret = str2sockunion (argv[1], &su);
+  if (ret < 0)
+    {
+      vty_out (vty, "%% Malformed address: %s%s", argv[1], VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  peer = peer_lookup (NULL, &su);
+  if (! peer || ! peer->afc[AFI_IP6][SAFI_ENCAP])
+    {
+      vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  ret = str2prefix_rd (argv[0], &prd);
+  if (! ret)
+    {
+      vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  return show_adj_route_encap (vty, peer, &prd);
+}
+#endif
+
+void
+bgp_encap_init (void)
+{
+  install_element (BGP_ENCAP_NODE, &encap_network_cmd);
+  install_element (BGP_ENCAP_NODE, &no_encap_network_cmd);
+
+
+  install_element (VIEW_NODE, &show_bgp_ipv4_encap_cmd);
+  install_element (VIEW_NODE, &show_bgp_ipv4_encap_rd_cmd);
+  install_element (VIEW_NODE, &show_bgp_ipv4_encap_tags_cmd);
+  install_element (VIEW_NODE, &show_bgp_ipv4_encap_rd_tags_cmd);
+  install_element (VIEW_NODE, &show_bgp_ipv4_encap_neighbor_routes_cmd);
+  install_element (VIEW_NODE, &show_bgp_ipv4_encap_rd_neighbor_routes_cmd);
+  install_element (VIEW_NODE, &show_bgp_ipv4_encap_neighbor_advertised_routes_cmd);
+  install_element (VIEW_NODE, \
&show_bgp_ipv4_encap_rd_neighbor_advertised_routes_cmd); +
+#ifdef HAVE_IPV6
+  install_element (VIEW_NODE, &show_bgp_ipv6_encap_cmd);
+  install_element (VIEW_NODE, &show_bgp_ipv6_encap_rd_cmd);
+  install_element (VIEW_NODE, &show_bgp_ipv6_encap_tags_cmd);
+  install_element (VIEW_NODE, &show_bgp_ipv6_encap_rd_tags_cmd);
+  install_element (VIEW_NODE, &show_bgp_ipv6_encap_neighbor_routes_cmd);
+  install_element (VIEW_NODE, &show_bgp_ipv6_encap_rd_neighbor_routes_cmd);
+  install_element (VIEW_NODE, &show_bgp_ipv6_encap_neighbor_advertised_routes_cmd);
+  install_element (VIEW_NODE, \
&show_bgp_ipv6_encap_rd_neighbor_advertised_routes_cmd); +#endif
+
+
+  install_element (ENABLE_NODE, &show_bgp_ipv4_encap_cmd);
+  install_element (ENABLE_NODE, &show_bgp_ipv4_encap_rd_cmd);
+  install_element (ENABLE_NODE, &show_bgp_ipv4_encap_tags_cmd);
+  install_element (ENABLE_NODE, &show_bgp_ipv4_encap_rd_tags_cmd);
+  install_element (ENABLE_NODE, &show_bgp_ipv4_encap_neighbor_routes_cmd);
+  install_element (ENABLE_NODE, &show_bgp_ipv4_encap_rd_neighbor_routes_cmd);
+  install_element (ENABLE_NODE, \
&show_bgp_ipv4_encap_neighbor_advertised_routes_cmd); +  install_element \
(ENABLE_NODE, &show_bgp_ipv4_encap_rd_neighbor_advertised_routes_cmd); +
+#ifdef HAVE_IPV6
+  install_element (ENABLE_NODE, &show_bgp_ipv6_encap_cmd);
+  install_element (ENABLE_NODE, &show_bgp_ipv6_encap_rd_cmd);
+  install_element (ENABLE_NODE, &show_bgp_ipv6_encap_tags_cmd);
+  install_element (ENABLE_NODE, &show_bgp_ipv6_encap_rd_tags_cmd);
+  install_element (ENABLE_NODE, &show_bgp_ipv6_encap_neighbor_routes_cmd);
+  install_element (ENABLE_NODE, &show_bgp_ipv6_encap_rd_neighbor_routes_cmd);
+  install_element (ENABLE_NODE, \
&show_bgp_ipv6_encap_neighbor_advertised_routes_cmd); +  install_element \
(ENABLE_NODE, &show_bgp_ipv6_encap_rd_neighbor_advertised_routes_cmd); +#endif
+
+
+}
diff --git a/bgpd/bgp_encap.h b/bgpd/bgp_encap.h
new file mode 100644
index 0000000..6f43b7b
--- /dev/null
+++ b/bgpd/bgp_encap.h
@@ -0,0 +1,34 @@
+/* 
+ *
+ * Copyright 2009-2015, LabN Consulting, L.L.C.
+ *
+ *
+ * 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; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ */
+
+#ifndef _QUAGGA_BGP_ENCAP_H
+#define _QUAGGA_BGP_ENCAP_H
+
+extern void bgp_encap_init (void);
+extern int bgp_nlri_parse_encap (
+    afi_t,
+    struct peer *,
+    struct attr *,
+    struct bgp_nlri *,
+    int withdraw);
+
+#include "bgp_encap_types.h"
+#endif /* _QUAGGA_BGP_ENCAP_H */
diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c
index 129c11f..eadc090 100644
--- a/bgpd/bgp_open.c
+++ b/bgpd/bgp_open.c
@@ -96,6 +96,9 @@ bgp_capability_vty_out (struct vty *vty, struct peer *peer)
 	    case SAFI_MPLS_LABELED_VPN:
 	      vty_out (vty, "SAFI MPLS-labeled VPN");
 	      break;
+	    case SAFI_ENCAP:
+	      vty_out (vty, "SAFI ENCAP");
+	      break;
 	    default:
 	      vty_out (vty, "SAFI Unknown %d ", mpc.safi);
 	      break;
@@ -138,6 +141,7 @@ bgp_afi_safi_valid_indices (afi_t afi, safi_t *safi)
             case SAFI_UNICAST:
             case SAFI_MULTICAST:
             case SAFI_MPLS_VPN:
+            case SAFI_ENCAP:
               return 1;
           }
     }
@@ -807,9 +811,11 @@ bgp_open_option_parse (struct peer *peer, u_char length, int \
*mp_capability)  if (! peer->afc_nego[AFI_IP][SAFI_UNICAST] 
 	  && ! peer->afc_nego[AFI_IP][SAFI_MULTICAST]
 	  && ! peer->afc_nego[AFI_IP][SAFI_MPLS_VPN]
+	  && ! peer->afc_nego[AFI_IP][SAFI_ENCAP]
 	  && ! peer->afc_nego[AFI_IP6][SAFI_UNICAST]
 	  && ! peer->afc_nego[AFI_IP6][SAFI_MULTICAST]
-	  && ! peer->afc_nego[AFI_IP6][SAFI_MPLS_VPN])
+	  && ! peer->afc_nego[AFI_IP6][SAFI_MPLS_VPN]
+	  && ! peer->afc_nego[AFI_IP6][SAFI_ENCAP])
 	{
 	  plog_err (peer->log, "%s [Error] Configured AFI/SAFIs do not "
 		    "overlap with received MP capabilities",
@@ -954,6 +960,18 @@ bgp_open_capability (struct stream *s, struct peer *peer)
       stream_putc (s, 0);
       stream_putc (s, SAFI_MPLS_LABELED_VPN);
     }
+  /* ENCAP */
+  if (peer->afc[AFI_IP][SAFI_ENCAP])
+    {
+      peer->afc_adv[AFI_IP][SAFI_ENCAP] = 1;
+      stream_putc (s, BGP_OPEN_OPT_CAP);
+      stream_putc (s, CAPABILITY_CODE_MP_LEN + 2);
+      stream_putc (s, CAPABILITY_CODE_MP);
+      stream_putc (s, CAPABILITY_CODE_MP_LEN);
+      stream_putw (s, AFI_IP);
+      stream_putc (s, 0);
+      stream_putc (s, SAFI_ENCAP);
+    }
 #ifdef HAVE_IPV6
   /* IPv6 unicast. */
   if (peer->afc[AFI_IP6][SAFI_UNICAST])
@@ -991,6 +1009,18 @@ bgp_open_capability (struct stream *s, struct peer *peer)
       stream_putc (s, 0);
       stream_putc (s, SAFI_MPLS_LABELED_VPN);
     }
+  /* IPv6 ENCAP. */
+  if (peer->afc[AFI_IP6][SAFI_ENCAP])
+    {
+      peer->afc_adv[AFI_IP6][SAFI_ENCAP] = 1;
+      stream_putc (s, BGP_OPEN_OPT_CAP);
+      stream_putc (s, CAPABILITY_CODE_MP_LEN + 2);
+      stream_putc (s, CAPABILITY_CODE_MP);
+      stream_putc (s, CAPABILITY_CODE_MP_LEN);
+      stream_putw (s, AFI_IP6);
+      stream_putc (s, 0);
+      stream_putc (s, SAFI_ENCAP);
+    }
 #endif /* HAVE_IPV6 */
 
   /* Route refresh. */
diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c
index 9d88e11..5902965 100644
--- a/bgpd/bgp_packet.c
+++ b/bgpd/bgp_packet.c
@@ -46,6 +46,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 #include "bgpd/bgp_ecommunity.h"
 #include "bgpd/bgp_network.h"
 #include "bgpd/bgp_mplsvpn.h"
+#include "bgpd/bgp_encap.h"
 #include "bgpd/bgp_advertise.h"
 #include "bgpd/bgp_vty.h"
 
@@ -1938,6 +1939,54 @@ bgp_update_receive (struct peer *peer, bgp_size_t size)
 		  peer->host);
 	}
     }
+  if (peer->afc[AFI_IP][SAFI_ENCAP])
+    {
+      if (mp_update.length 
+	  && mp_update.afi == AFI_IP 
+	  && mp_update.safi == SAFI_ENCAP)
+	bgp_nlri_parse_encap (mp_update.afi, peer, &attr, &mp_update, 0);
+
+      if (mp_withdraw.length 
+	  && mp_withdraw.afi == AFI_IP 
+	  && mp_withdraw.safi == SAFI_ENCAP)
+	bgp_nlri_parse_encap (mp_withdraw.afi, peer, &attr, &mp_withdraw, 1);
+
+      if (! withdraw_len
+	  && mp_withdraw.afi == AFI_IP
+	  && mp_withdraw.safi == SAFI_MPLS_LABELED_VPN
+	  && mp_withdraw.length == 0)
+	{
+	  /* End-of-RIB received */
+
+	  if (BGP_DEBUG (update, UPDATE_IN))
+	    zlog (peer->log, LOG_DEBUG, "rcvd End-of-RIB for Encap Unicast from %s",
+		  peer->host);
+	}
+    }
+  if (peer->afc[AFI_IP6][SAFI_ENCAP])
+    {
+      if (mp_update.length 
+	  && mp_update.afi == AFI_IP6 
+	  && mp_update.safi == SAFI_ENCAP)
+	bgp_nlri_parse_encap (mp_update.afi, peer, &attr, &mp_update, 0);
+
+      if (mp_withdraw.length 
+	  && mp_withdraw.afi == AFI_IP6
+	  && mp_withdraw.safi == SAFI_ENCAP)
+	bgp_nlri_parse_encap (mp_withdraw.afi, peer, &attr, &mp_withdraw, 1);
+
+      if (! withdraw_len
+	  && mp_withdraw.afi == AFI_IP6
+	  && mp_withdraw.safi == SAFI_MPLS_LABELED_VPN
+	  && mp_withdraw.length == 0)
+	{
+	  /* End-of-RIB received */
+
+	  if (BGP_DEBUG (update, UPDATE_IN))
+	    zlog (peer->log, LOG_DEBUG, "rcvd End-of-RIB for Encap Unicast from %s",
+		  peer->host);
+	}
+    }
 
   /* Everything is done.  We unintern temporary structures which
      interned in bgp_attr_parse(). */
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index 006f363..c4b87a0 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -71,7 +71,7 @@ bgp_afi_node_get (struct bgp_table *table, afi_t afi, safi_t safi, \
struct prefix  if (!table)
     return NULL;
   
-  if (safi == SAFI_MPLS_VPN)
+  if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP))
     {
       prn = bgp_node_get (table, (struct prefix *) prd);
 
@@ -84,7 +84,7 @@ bgp_afi_node_get (struct bgp_table *table, afi_t afi, safi_t safi, \
struct prefix  
   rn = bgp_node_get (table, p);
 
-  if (safi == SAFI_MPLS_VPN)
+  if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP))
     rn->prn = prn;
 
   return rn;
@@ -989,13 +989,24 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, \
struct prefix *p,  attr->flag &= ~(ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC));
     }
 
+
+#define NEXTHOP_IS_V4 (\
+    (safi != SAFI_ENCAP && p->family == AF_INET) || \
+    (safi == SAFI_ENCAP && attr->extra->mp_nexthop_len == 4))
+
+#ifdef HAVE_IPV6
+#define NEXTHOP_IS_V6 (\
+    (safi != SAFI_ENCAP && p->family == AF_INET6) || \
+    (safi == SAFI_ENCAP && attr->extra->mp_nexthop_len == 16))
+#endif
+
   /* next-hop-set */
   if (transparent
       || (reflect && ! CHECK_FLAG (peer->af_flags[afi][safi], \
                PEER_FLAG_NEXTHOP_SELF_ALL))
       || (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_NEXTHOP_UNCHANGED)
-	  && ((p->family == AF_INET && attr->nexthop.s_addr)
+	  && ((NEXTHOP_IS_V4 && attr->nexthop.s_addr)
 #ifdef HAVE_IPV6
-	      || (p->family == AF_INET6 && 
+	      || (NEXTHOP_IS_V6 && 
                   ! IN6_IS_ADDR_UNSPECIFIED(&attr->extra->mp_nexthop_global))
 #endif /* HAVE_IPV6 */
 	      )))
@@ -1003,18 +1014,18 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, \
struct prefix *p,  /* NEXT-HOP Unchanged. */
     }
   else if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_NEXTHOP_SELF)
-	   || (p->family == AF_INET && attr->nexthop.s_addr == 0)
+	   || (NEXTHOP_IS_V4 && attr->nexthop.s_addr == 0)
 #ifdef HAVE_IPV6
-	   || (p->family == AF_INET6 && 
+	   || (NEXTHOP_IS_V6 && 
                IN6_IS_ADDR_UNSPECIFIED(&attr->extra->mp_nexthop_global))
 #endif /* HAVE_IPV6 */
 	   || (peer->sort == BGP_PEER_EBGP
 	       && bgp_multiaccess_check_v4 (attr->nexthop, peer->host) == 0))
     {
       /* Set IPv4 nexthop. */
-      if (p->family == AF_INET)
+      if (NEXTHOP_IS_V4)
 	{
-	  if (safi == SAFI_MPLS_VPN)
+	  if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP))
 	    memcpy (&attr->extra->mp_nexthop_global_in, &peer->nexthop.v4,
 	            IPV4_MAX_BYTELEN);
 	  else
@@ -1022,7 +1033,7 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, \
struct prefix *p,  }
 #ifdef HAVE_IPV6
       /* Set IPv6 nexthop. */
-      if (p->family == AF_INET6)
+      if (NEXTHOP_IS_V6)
 	{
 	  /* IPv6 global nexthop must be included. */
 	  memcpy (&attr->extra->mp_nexthop_global, &peer->nexthop.v6_global, 
@@ -1033,7 +1044,7 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, \
struct prefix *p,  }
 
 #ifdef HAVE_IPV6
-  if (p->family == AF_INET6)
+  if (p->family == AF_INET6 && safi != SAFI_ENCAP)
     {
       /* Left nexthop_local unchanged if so configured. */ 
       if ( CHECK_FLAG (peer->af_flags[afi][safi], 
@@ -1223,7 +1234,7 @@ bgp_announce_check_rsclient (struct bgp_info *ri, struct peer \
*rsclient,  /* Set IPv4 nexthop. */
     if (p->family == AF_INET)
       {
-        if (safi == SAFI_MPLS_VPN)
+        if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP))
           memcpy (&attr->extra->mp_nexthop_global_in, &rsclient->nexthop.v4,
                   IPV4_MAX_BYTELEN);
         else
@@ -2644,7 +2655,7 @@ bgp_announce_table (struct peer *peer, afi_t afi, safi_t safi,
   if (! table)
     table = (rsclient) ? peer->rib[afi][safi] : peer->bgp->rib[afi][safi];
 
-  if (safi != SAFI_MPLS_VPN
+  if ((safi != SAFI_MPLS_VPN) && (safi != SAFI_ENCAP)
       && CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_DEFAULT_ORIGINATE))
     bgp_default_originate (peer, afi, safi, 0);
 
@@ -2680,7 +2691,7 @@ bgp_announce_route (struct peer *peer, afi_t afi, safi_t safi)
   if (CHECK_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_ORF_WAIT_REFRESH))
     return;
 
-  if (safi != SAFI_MPLS_VPN)
+  if ((safi != SAFI_MPLS_VPN) && (safi != SAFI_ENCAP))
     bgp_announce_table (peer, afi, safi, NULL, 0);
   else
     for (rn = bgp_table_top (peer->bgp->rib[afi][safi]); rn;
@@ -2730,7 +2741,7 @@ bgp_soft_reconfig_rsclient (struct peer *rsclient, afi_t afi, \
safi_t safi)  struct bgp_table *table;
   struct bgp_node *rn;
   
-  if (safi != SAFI_MPLS_VPN)
+  if ((safi != SAFI_MPLS_VPN) && (safi != SAFI_ENCAP))
     bgp_soft_reconfig_table_rsclient (rsclient, afi, safi, NULL, NULL);
 
   else
@@ -2789,7 +2800,7 @@ bgp_soft_reconfig_in (struct peer *peer, afi_t afi, safi_t \
safi)  if (peer->status != Established)
     return;
 
-  if (safi != SAFI_MPLS_VPN)
+  if ((safi != SAFI_MPLS_VPN) && (safi != SAFI_ENCAP))
     bgp_soft_reconfig_table (peer, afi, safi, NULL, NULL);
   else
     for (rn = bgp_table_top (peer->bgp->rib[afi][safi]); rn;
@@ -3006,7 +3017,7 @@ bgp_clear_route (struct peer *peer, afi_t afi, safi_t safi,
   switch (purpose)
     {
     case BGP_CLEAR_ROUTE_NORMAL:
-      if (safi != SAFI_MPLS_VPN)
+      if ((safi != SAFI_MPLS_VPN) && (safi != SAFI_ENCAP))
         bgp_clear_route_table (peer, afi, safi, NULL, NULL, purpose);
       else
         for (rn = bgp_table_top (peer->bgp->rib[afi][safi]); rn;
@@ -3185,6 +3196,16 @@ bgp_cleanup_routes (void)
 		   bgp_unlock_node(rn);
                 }
 
+	  for (rn = bgp_table_top(bgp->rib[afi][SAFI_ENCAP]); rn;
+               rn = bgp_route_next (rn))
+	      if (rn->info)
+                {
+                   bgp_cleanup_table((struct bgp_table *)(rn->info), SAFI_ENCAP);
+                   bgp_table_finish ((struct bgp_table **)&(rn->info));
+		   rn->info = NULL;
+		   bgp_unlock_node(rn);
+                }
+	}
     }
 }
 
@@ -3307,7 +3328,7 @@ bgp_nlri_sanity_check (struct peer *peer, int afi, safi_t safi,
   u_char prefixlen;
   int psize;
 
-  if (safi == BGP_SAFI_VPN || safi == SAFI_MPLS_VPN) {
+  if (safi == SAFI_MPLS_LABELED_VPN || safi == SAFI_MPLS_VPN) {
 
     return 0;
   }
@@ -3320,11 +3341,22 @@ bgp_nlri_sanity_check (struct peer *peer, int afi, safi_t \
safi,  
   while (pnt < end)
     {
+      int	badlength;
       prefixlen = *pnt++;
       
       /* Prefix length check. */
-      if ((afi == AFI_IP && prefixlen > 32)
-	  || (afi == AFI_IP6 && prefixlen > 128))
+      badlength = 0;
+      if (safi == SAFI_ENCAP) {
+	if (prefixlen > 128)
+	  badlength = 1;
+      } else {
+        if ((afi == AFI_IP && prefixlen > 32) ||
+	    (afi == AFI_IP6 && prefixlen > 128)) {
+
+	    badlength = 1;
+	}
+      }
+      if (badlength)
 	{
 	  plog_err (peer->log, 
 		    "%s [Error] Update packet error (wrong prefix length %d)",
@@ -4067,7 +4099,7 @@ bgp_static_delete (struct bgp *bgp)
       for (rn = bgp_table_top (bgp->route[afi][safi]); rn; rn = bgp_route_next (rn))
 	if (rn->info != NULL)
 	  {      
-	    if (safi == SAFI_MPLS_VPN)
+	    if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP))
 	      {
 		table = rn->info;
 
@@ -4923,7 +4955,7 @@ bgp_aggregate_increment (struct bgp *bgp, struct prefix *p,
   struct bgp_table *table;
 
   /* MPLS-VPN aggregation is not yet supported. */
-  if (safi == SAFI_MPLS_VPN)
+  if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP))
     return;
 
   table = bgp->aggregate[afi][safi];
@@ -4960,7 +4992,7 @@ bgp_aggregate_decrement (struct bgp *bgp, struct prefix *p,
   struct bgp_table *table;
 
   /* MPLS-VPN aggregation is not yet supported. */
-  if (safi == SAFI_MPLS_VPN)
+  if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP))
     return;
 
   table = bgp->aggregate[afi][safi];
@@ -5903,30 +5935,71 @@ route_vty_out (struct vty *vty, struct prefix *p,
   attr = binfo->attr;
   if (attr) 
     {
-      if (p->family == AF_INET)
-	{
-	  if (safi == SAFI_MPLS_VPN)
-	    vty_out (vty, "%-16s",
-                     inet_ntoa (attr->extra->mp_nexthop_global_in));
-	  else
-	    vty_out (vty, "%-16s", inet_ntoa (attr->nexthop));
+
+      /*
+       * NEXTHOP start
+       */
+
+      /*
+       * For ENCAP routes, nexthop address family is not
+       * neccessarily the same as the prefix address family.
+       * Both SAFI_MPLS_VPN and SAFI_ENCAP use the MP nexthop field
+       */
+      if ((safi == SAFI_ENCAP) || (safi == SAFI_MPLS_VPN)) {
+	if (attr->extra) {
+	    char	buf[BUFSIZ];
+	    int		af = NEXTHOP_FAMILY(attr->extra->mp_nexthop_len);
+
+	    switch (af) {
+		case AF_INET:
+		    vty_out (vty, "%s", inet_ntop(af,
+			&attr->extra->mp_nexthop_global_in, buf, BUFSIZ));
+		    break;
+#if HAVE_IPV6
+		case AF_INET6:
+		    vty_out (vty, "%s", inet_ntop(af,
+			&attr->extra->mp_nexthop_global, buf, BUFSIZ));
+		    break;
+#endif
+
+		default:
+		    vty_out(vty, "?");
+	    }
+	} else {
+	    vty_out(vty, "?");
 	}
+      } else {
+
+	  if (p->family == AF_INET)
+	    {
+		vty_out (vty, "%-16s", inet_ntoa (attr->nexthop));
+	    }
 #ifdef HAVE_IPV6      
-      else if (p->family == AF_INET6)
-	{
-	  int len;
-	  char buf[BUFSIZ];
+	  else if (p->family == AF_INET6)
+	    {
+	      int len;
+	      char buf[BUFSIZ];
 
-	  len = vty_out (vty, "%s", 
-			 inet_ntop (AF_INET6, &attr->extra->mp_nexthop_global,
-			 buf, BUFSIZ));
-	  len = 16 - len;
-	  if (len < 1)
-	    vty_out (vty, "%s%*s", VTY_NEWLINE, 36, " ");
-	  else
-	    vty_out (vty, "%*s", len, " ");
-	}
+	      len = vty_out (vty, "%s", 
+			     inet_ntop (AF_INET6, &attr->extra->mp_nexthop_global,
+			     buf, BUFSIZ));
+	      len = 16 - len;
+	      if (len < 1)
+		vty_out (vty, "%s%*s", VTY_NEWLINE, 36, " ");
+	      else
+		vty_out (vty, "%*s", len, " ");
+	    }
 #endif /* HAVE_IPV6 */
+         else
+	   {
+	     vty_out(vty, "?");
+	   }
+      }
+
+      /*
+       * NEXTHOP end
+       */
+
 
       if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
 	vty_out (vty, "%10u", attr->med);
@@ -5968,7 +6041,7 @@ route_vty_out_tmp (struct vty *vty, struct prefix *p,
     {
       if (p->family == AF_INET)
 	{
-	  if (safi == SAFI_MPLS_VPN)
+	  if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP))
 	    vty_out (vty, "%-16s",
                      inet_ntoa (attr->extra->mp_nexthop_global_in));
 	  else
@@ -6041,7 +6114,7 @@ route_vty_out_tag (struct vty *vty, struct prefix *p,
     {
       if (p->family == AF_INET)
 	{
-	  if (safi == SAFI_MPLS_VPN)
+	  if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP))
 	    vty_out (vty, "%-16s",
                      inet_ntoa (attr->extra->mp_nexthop_global_in));
 	  else
@@ -6224,7 +6297,7 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct \
prefix *p,  /* Line2 display Next-hop, Neighbor, Router-id */
       if (p->family == AF_INET)
 	{
-	  vty_out (vty, "    %s", safi == SAFI_MPLS_VPN ?
+	  vty_out (vty, "    %s", ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP)) ?
 		   inet_ntoa (attr->extra->mp_nexthop_global_in) :
 		   inet_ntoa (attr->nexthop));
 	}
@@ -6660,12 +6733,12 @@ route_vty_out_detail_header (struct vty *vty, struct bgp \
*bgp,  int no_advertise = 0;
   int local_as = 0;
   int first = 0;
+  int printrd = ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP));
 
   p = &rn->p;
   vty_out (vty, "BGP routing table entry for %s%s%s/%d%s",
-	   (safi == SAFI_MPLS_VPN ?
-	   prefix_rd2str (prd, buf1, RD_ADDRSTRLEN) : ""),
-	   safi == SAFI_MPLS_VPN ? ":" : "",
+	   (printrd ?  prefix_rd2str (prd, buf1, RD_ADDRSTRLEN) : ""),
+	   printrd ?  ":" : "",
 	   inet_ntop (p->family, &p->u.prefix, buf2, INET6_ADDRSTRLEN),
 	   p->prefixlen, VTY_NEWLINE);
 
@@ -6751,7 +6824,7 @@ bgp_show_route_in_table (struct vty *vty, struct bgp *bgp,
 
   match.family = afi2family (afi);
 
-  if (safi == SAFI_MPLS_VPN)
+  if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP))
     {
       for (rn = bgp_table_top (rib); rn; rn = bgp_route_next (rn))
         {
@@ -6775,12 +6848,12 @@ bgp_show_route_in_table (struct vty *vty, struct bgp *bgp,
                       if (header)
                         {
                           route_vty_out_detail_header (vty, bgp, rm, (struct \
                prefix_rd *)&rn->p,
-                                                       AFI_IP, SAFI_MPLS_VPN);
+                                                       AFI_IP, safi);
 
                           header = 0;
                         }
                       display++;
-                      route_vty_out_detail (vty, bgp, &rm->p, ri, AFI_IP, \
SAFI_MPLS_VPN); +                      route_vty_out_detail (vty, bgp, &rm->p, ri, \
AFI_IP, safi);  }
 
                   bgp_unlock_node (rm);
@@ -9820,22 +9893,28 @@ bgp_table_stats_vty (struct vty *vty, const char *name,
                    afi_str, VTY_NEWLINE);
           return CMD_WARNING;
         }
-      if (strncmp (safi_str, "m", 1) == 0)
-        safi = SAFI_MULTICAST;
-      else if (strncmp (safi_str, "u", 1) == 0)
-        safi = SAFI_UNICAST;
-      else if (strncmp (safi_str, "vpnv4", 5) == 0 || strncmp (safi_str, "vpnv6", 5) \
                == 0)
-        safi = SAFI_MPLS_LABELED_VPN;
-      else
-        {
-          vty_out (vty, "%% Invalid subsequent address family %s%s",
+      switch (safi_str[0]) {
+	case 'm':
+	    safi = SAFI_MULTICAST;
+	    break;
+	case 'u':
+	    safi = SAFI_UNICAST;
+	    break;
+	case 'v':
+	    safi =  SAFI_MPLS_LABELED_VPN;
+	    break;
+	case 'e':
+	    safi = SAFI_ENCAP;
+	    break;
+	default:
+	    vty_out (vty, "%% Invalid subsequent address family %s%s",
                    safi_str, VTY_NEWLINE);
-          return CMD_WARNING;
-        }
+            return CMD_WARNING;
+      }
     }
   else
     {
-      vty_out (vty, "%% Invalid address family %s%s",
+      vty_out (vty, "%% Invalid address family \"%s\"%s",
                afi_str, VTY_NEWLINE);
       return CMD_WARNING;
     }
@@ -9845,30 +9924,23 @@ bgp_table_stats_vty (struct vty *vty, const char *name,
 
 DEFUN (show_bgp_statistics,
        show_bgp_statistics_cmd,
-       "show bgp (ipv4|ipv6) (unicast|multicast) statistics",
+       "show bgp (ipv4|ipv6) (encap|multicast|unicast|vpn) statistics",
        SHOW_STR
        BGP_STR
        "Address family\n"
        "Address family\n"
        "Address Family modifier\n"
        "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
        "BGP RIB advertisement statistics\n")
 {
   return bgp_table_stats_vty (vty, NULL, argv[0], argv[1]);
 }
 
-ALIAS (show_bgp_statistics,
-       show_bgp_statistics_vpnv4_cmd,
-       "show bgp (ipv4) (vpnv4) statistics",
-       SHOW_STR
-       BGP_STR
-       "Address family\n"
-       "Address Family modifier\n"
-       "BGP RIB advertisement statistics\n")
-
 DEFUN (show_bgp_statistics_view,
        show_bgp_statistics_view_cmd,
-       "show bgp view WORD (ipv4|ipv6) (unicast|multicast) statistics",
+       "show bgp view WORD (ipv4|ipv6) (encap|multicast|unicast|vpn) statistics",
        SHOW_STR
        BGP_STR
        "BGP view\n"
@@ -9876,20 +9948,24 @@ DEFUN (show_bgp_statistics_view,
        "Address family\n"
        "Address Family modifier\n"
        "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
        "BGP RIB advertisement statistics\n")
 {
   return bgp_table_stats_vty (vty, NULL, argv[0], argv[1]);
 }
 
+#if 0 /* added as options to above command */
 ALIAS (show_bgp_statistics_view,
-       show_bgp_statistics_view_vpnv4_cmd,
-       "show bgp view WORD (ipv4) (vpnv4) statistics",
+       show_bgp_statistics_view_encap_cmd,
+       "show bgp view WORD (ipv4) (encap) statistics",
        SHOW_STR
        BGP_STR
        "BGP view\n"
        "Address family\n"
        "Address Family modifier\n"
        "BGP RIB advertisement statistics\n")
+#endif
 
 enum bgp_pcounts
 {
@@ -12393,9 +12469,9 @@ bgp_clear_damp_route (struct vty *vty, const char *view_name,
 
   match.family = afi2family (afi);
 
-  if (safi == SAFI_MPLS_VPN)
+  if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP))
     {
-      for (rn = bgp_table_top (bgp->rib[AFI_IP][SAFI_MPLS_VPN]); rn; rn = \
bgp_route_next (rn)) +      for (rn = bgp_table_top (bgp->rib[AFI_IP][safi]); rn; rn \
= bgp_route_next (rn))  {
           if (prd && memcmp (rn->p.u.val, prd->val, 8) != 0)
             continue;
@@ -12512,6 +12588,7 @@ DEFUN (clear_ip_bgp_dampening_address_mask,
 			       SAFI_UNICAST, NULL, 0);
 }
 
+/* also used for encap safi */
 static int
 bgp_config_write_network_vpnv4 (struct vty *vty, struct bgp *bgp,
 				afi_t afi, safi_t safi, int *write)
@@ -12563,7 +12640,7 @@ bgp_config_write_network (struct vty *vty, struct bgp *bgp,
   struct bgp_aggregate *bgp_aggregate;
   char buf[SU_ADDRSTRLEN];
   
-  if (afi == AFI_IP && safi == SAFI_MPLS_VPN)
+  if (afi == AFI_IP && ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP)))
     return bgp_config_write_network_vpnv4 (vty, bgp, afi, safi, write);
 
   /* Network configuration. */
diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h
index d70d12a..455a413 100644
--- a/bgpd/bgp_route.h
+++ b/bgpd/bgp_route.h
@@ -120,6 +120,9 @@ struct bgp_static
     struct route_map *map;
   } rmap;
 
+  /* Route Distinguisher */
+  struct prefix_rd	prd;
+
   /* MPLS label.  */
   u_char tag[3];
 };
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
index 20aaec6..8a102b3 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -4801,6 +4801,33 @@ ALIAS (clear_ip_bgp_all_vpnv4_soft_out,
        "Address Family Modifier\n"
        "Soft reconfig outbound update\n")
 
+DEFUN (clear_ip_bgp_all_encap_soft_out,
+       clear_ip_bgp_all_encap_soft_out_cmd,
+       "clear ip bgp * encap unicast soft out",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "Clear all peers\n"
+       "Address family\n"
+       "Address Family Modifier\n"
+       "Soft reconfig\n"
+       "Soft reconfig outbound update\n")
+{
+  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_ENCAP, clear_all,
+			BGP_CLEAR_SOFT_OUT, NULL);
+}
+
+ALIAS (clear_ip_bgp_all_encap_soft_out,
+       clear_ip_bgp_all_encap_out_cmd,
+       "clear ip bgp * encap unicast out",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "Clear all peers\n"
+       "Address family\n"
+       "Address Family Modifier\n"
+       "Soft reconfig outbound update\n")
+
 DEFUN (clear_bgp_all_soft_out,
        clear_bgp_all_soft_out_cmd,
        "clear bgp * soft out",
@@ -4939,6 +4966,33 @@ ALIAS (clear_ip_bgp_peer_vpnv4_soft_out,
        "Address Family Modifier\n"
        "Soft reconfig outbound update\n")
 
+DEFUN (clear_ip_bgp_peer_encap_soft_out,
+       clear_ip_bgp_peer_encap_soft_out_cmd,
+       "clear ip bgp A.B.C.D encap unicast soft out",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "BGP neighbor address to clear\n"
+       "Address family\n"
+       "Address Family Modifier\n"
+       "Soft reconfig\n"
+       "Soft reconfig outbound update\n")
+{
+  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_ENCAP, clear_peer,
+			BGP_CLEAR_SOFT_OUT, argv[0]);
+}
+
+ALIAS (clear_ip_bgp_peer_encap_soft_out,
+       clear_ip_bgp_peer_encap_out_cmd,
+       "clear ip bgp A.B.C.D encap unicast out",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "BGP neighbor address to clear\n"
+       "Address family\n"
+       "Address Family Modifier\n"
+       "Soft reconfig outbound update\n")
+
 DEFUN (clear_bgp_peer_soft_out,
        clear_bgp_peer_soft_out_cmd,
        "clear bgp (A.B.C.D|X:X::X:X) soft out",
@@ -5266,6 +5320,33 @@ ALIAS (clear_ip_bgp_as_vpnv4_soft_out,
        "Address Family modifier\n"
        "Soft reconfig outbound update\n")
 
+DEFUN (clear_ip_bgp_as_encap_soft_out,
+       clear_ip_bgp_as_encap_soft_out_cmd,
+       "clear ip bgp " CMD_AS_RANGE " encap unicast soft out",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "Clear peers with the AS number\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Soft reconfig\n"
+       "Soft reconfig outbound update\n")
+{
+  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_ENCAP, clear_as,
+			BGP_CLEAR_SOFT_OUT, argv[0]);
+}
+
+ALIAS (clear_ip_bgp_as_encap_soft_out,
+       clear_ip_bgp_as_encap_out_cmd,
+       "clear ip bgp " CMD_AS_RANGE " encap unicast out",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "Clear peers with the AS number\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Soft reconfig outbound update\n")
+
 DEFUN (clear_bgp_as_soft_out,
        clear_bgp_as_soft_out_cmd,
        "clear bgp " CMD_AS_RANGE " soft out",
@@ -5502,6 +5583,33 @@ ALIAS (clear_ip_bgp_all_vpnv4_soft_in,
        "Address Family Modifier\n"
        "Soft reconfig inbound update\n")
 
+DEFUN (clear_ip_bgp_all_encap_soft_in,
+       clear_ip_bgp_all_encap_soft_in_cmd,
+       "clear ip bgp * encap unicast soft in",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "Clear all peers\n"
+       "Address family\n"
+       "Address Family Modifier\n"
+       "Soft reconfig\n"
+       "Soft reconfig inbound update\n")
+{
+  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_ENCAP, clear_all,
+			BGP_CLEAR_SOFT_IN, NULL);
+}
+
+ALIAS (clear_ip_bgp_all_encap_soft_in,
+       clear_ip_bgp_all_encap_in_cmd,
+       "clear ip bgp * encap unicast in",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "Clear all peers\n"
+       "Address family\n"
+       "Address Family Modifier\n"
+       "Soft reconfig inbound update\n")
+
 DEFUN (clear_bgp_all_soft_in,
        clear_bgp_all_soft_in_cmd,
        "clear bgp * soft in",
@@ -5698,6 +5806,33 @@ ALIAS (clear_ip_bgp_peer_vpnv4_soft_in,
        "Address Family Modifier\n"
        "Soft reconfig inbound update\n")
 
+DEFUN (clear_ip_bgp_peer_encap_soft_in,
+       clear_ip_bgp_peer_encap_soft_in_cmd,
+       "clear ip bgp A.B.C.D encap unicast soft in",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "BGP neighbor address to clear\n"
+       "Address family\n"
+       "Address Family Modifier\n"
+       "Soft reconfig\n"
+       "Soft reconfig inbound update\n")
+{
+  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_ENCAP, clear_peer,
+			BGP_CLEAR_SOFT_IN, argv[0]);
+}
+
+ALIAS (clear_ip_bgp_peer_encap_soft_in,
+       clear_ip_bgp_peer_encap_in_cmd,
+       "clear ip bgp A.B.C.D encap unicast in",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "BGP neighbor address to clear\n"
+       "Address family\n"
+       "Address Family Modifier\n"
+       "Soft reconfig inbound update\n")
+
 DEFUN (clear_bgp_peer_soft_in,
        clear_bgp_peer_soft_in_cmd,
        "clear bgp (A.B.C.D|X:X::X:X) soft in",
@@ -6205,6 +6340,33 @@ ALIAS (clear_ip_bgp_as_vpnv4_soft_in,
        "Address Family modifier\n"
        "Soft reconfig inbound update\n")
 
+DEFUN (clear_ip_bgp_as_encap_soft_in,
+       clear_ip_bgp_as_encap_soft_in_cmd,
+       "clear ip bgp " CMD_AS_RANGE " encap unicast soft in",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "Clear peers with the AS number\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Soft reconfig\n"
+       "Soft reconfig inbound update\n")
+{
+  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_ENCAP, clear_as,
+			BGP_CLEAR_SOFT_IN, argv[0]);
+}
+
+ALIAS (clear_ip_bgp_as_encap_soft_in,
+       clear_ip_bgp_as_encap_in_cmd,
+       "clear ip bgp " CMD_AS_RANGE " encap unicast in",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "Clear peers with the AS number\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Soft reconfig inbound update\n")
+
 DEFUN (clear_bgp_as_soft_in,
        clear_bgp_as_soft_in_cmd,
        "clear bgp " CMD_AS_RANGE " soft in",
@@ -6355,6 +6517,21 @@ DEFUN (clear_ip_bgp_all_vpnv4_soft,
 			BGP_CLEAR_SOFT_BOTH, argv[0]);
 }
 
+DEFUN (clear_ip_bgp_all_encap_soft,
+       clear_ip_bgp_all_encap_soft_cmd,
+       "clear ip bgp * encap unicast soft",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "Clear all peers\n"
+       "Address family\n"
+       "Address Family Modifier\n"
+       "Soft reconfig\n")
+{
+  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_ENCAP, clear_all,
+			BGP_CLEAR_SOFT_BOTH, argv[0]);
+}
+
 DEFUN (clear_bgp_all_soft,
        clear_bgp_all_soft_cmd,
        "clear bgp * soft",
@@ -6438,6 +6615,21 @@ DEFUN (clear_ip_bgp_peer_vpnv4_soft,
 			BGP_CLEAR_SOFT_BOTH, argv[0]);
 }
 
+DEFUN (clear_ip_bgp_peer_encap_soft,
+       clear_ip_bgp_peer_encap_soft_cmd,
+       "clear ip bgp A.B.C.D encap unicast soft",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "BGP neighbor address to clear\n"
+       "Address family\n"
+       "Address Family Modifier\n"
+       "Soft reconfig\n")
+{
+  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_ENCAP, clear_peer,
+			BGP_CLEAR_SOFT_BOTH, argv[0]);
+}
+
 DEFUN (clear_bgp_peer_soft,
        clear_bgp_peer_soft_cmd,
        "clear bgp (A.B.C.D|X:X::X:X) soft",
@@ -6621,6 +6813,21 @@ DEFUN (clear_ip_bgp_as_vpnv4_soft,
 			BGP_CLEAR_SOFT_BOTH, argv[0]);
 }
 
+DEFUN (clear_ip_bgp_as_encap_soft,
+       clear_ip_bgp_as_encap_soft_cmd,
+       "clear ip bgp " CMD_AS_RANGE " encap unicast soft",
+       CLEAR_STR
+       IP_STR
+       BGP_STR
+       "Clear peers with the AS number\n"
+       "Address family\n"
+       "Address Family Modifier\n"
+       "Soft reconfig\n")
+{
+  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_ENCAP, clear_as,
+			BGP_CLEAR_SOFT_BOTH, argv[0]);
+}
+
 DEFUN (clear_bgp_as_soft,
        clear_bgp_as_soft_cmd,
        "clear bgp " CMD_AS_RANGE " soft",
@@ -10028,6 +10235,12 @@ bgp_vty_init (void)
   install_element (ENABLE_NODE, &clear_ip_bgp_peer_vpnv4_in_cmd);
   install_element (ENABLE_NODE, &clear_ip_bgp_as_vpnv4_soft_in_cmd);
   install_element (ENABLE_NODE, &clear_ip_bgp_as_vpnv4_in_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_all_encap_soft_in_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_all_encap_in_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_peer_encap_soft_in_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_peer_encap_in_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_as_encap_soft_in_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_as_encap_in_cmd);
 #ifdef HAVE_IPV6
   install_element (ENABLE_NODE, &clear_bgp_all_soft_in_cmd);
   install_element (ENABLE_NODE, &clear_bgp_instance_all_soft_in_cmd);
@@ -10091,6 +10304,12 @@ bgp_vty_init (void)
   install_element (ENABLE_NODE, &clear_ip_bgp_peer_vpnv4_out_cmd);
   install_element (ENABLE_NODE, &clear_ip_bgp_as_vpnv4_soft_out_cmd);
   install_element (ENABLE_NODE, &clear_ip_bgp_as_vpnv4_out_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_all_encap_soft_out_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_all_encap_out_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_peer_encap_soft_out_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_peer_encap_out_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_as_encap_soft_out_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_as_encap_out_cmd);
 #ifdef HAVE_IPV6
   install_element (ENABLE_NODE, &clear_bgp_all_soft_out_cmd);
   install_element (ENABLE_NODE, &clear_bgp_instance_all_soft_out_cmd);
@@ -10131,6 +10350,9 @@ bgp_vty_init (void)
   install_element (ENABLE_NODE, &clear_ip_bgp_all_vpnv4_soft_cmd);
   install_element (ENABLE_NODE, &clear_ip_bgp_peer_vpnv4_soft_cmd);
   install_element (ENABLE_NODE, &clear_ip_bgp_as_vpnv4_soft_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_all_encap_soft_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_peer_encap_soft_cmd);
+  install_element (ENABLE_NODE, &clear_ip_bgp_as_encap_soft_cmd);
 #ifdef HAVE_IPV6
   install_element (ENABLE_NODE, &clear_bgp_all_soft_cmd);
   install_element (ENABLE_NODE, &clear_bgp_instance_all_soft_cmd);
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index 8401e9f..94a0514 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -36,6 +36,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 #include "plist.h"
 #include "linklist.h"
 #include "workqueue.h"
+#include "table.h"
 
 #include "bgpd/bgpd.h"
 #include "bgpd/bgp_table.h"
@@ -55,6 +56,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 #include "bgpd/bgp_nexthop.h"
 #include "bgpd/bgp_damp.h"
 #include "bgpd/bgp_mplsvpn.h"
+#include "bgpd/bgp_encap.h"
 #include "bgpd/bgp_advertise.h"
 #include "bgpd/bgp_network.h"
 #include "bgpd/bgp_vty.h"
@@ -974,12 +976,16 @@ peer_as_change (struct peer *peer, as_t as)
 		  PEER_FLAG_REFLECTOR_CLIENT);
       UNSET_FLAG (peer->af_flags[AFI_IP][SAFI_MPLS_VPN],
 		  PEER_FLAG_REFLECTOR_CLIENT);
+      UNSET_FLAG (peer->af_flags[AFI_IP][SAFI_ENCAP],
+		  PEER_FLAG_REFLECTOR_CLIENT);
       UNSET_FLAG (peer->af_flags[AFI_IP6][SAFI_UNICAST],
 		  PEER_FLAG_REFLECTOR_CLIENT);
       UNSET_FLAG (peer->af_flags[AFI_IP6][SAFI_MULTICAST],
 		  PEER_FLAG_REFLECTOR_CLIENT);
       UNSET_FLAG (peer->af_flags[AFI_IP6][SAFI_MPLS_VPN],
 		  PEER_FLAG_REFLECTOR_CLIENT);
+      UNSET_FLAG (peer->af_flags[AFI_IP6][SAFI_ENCAP],
+		  PEER_FLAG_REFLECTOR_CLIENT);
     }
 
   /* local-as reset */
@@ -1398,9 +1404,11 @@ peer_group_active (struct peer *peer)
   if (peer->af_group[AFI_IP][SAFI_UNICAST]
       || peer->af_group[AFI_IP][SAFI_MULTICAST]
       || peer->af_group[AFI_IP][SAFI_MPLS_VPN]
+      || peer->af_group[AFI_IP][SAFI_ENCAP]
       || peer->af_group[AFI_IP6][SAFI_UNICAST]
       || peer->af_group[AFI_IP6][SAFI_MULTICAST]
-      || peer->af_group[AFI_IP6][SAFI_MPLS_VPN])
+      || peer->af_group[AFI_IP6][SAFI_MPLS_VPN]
+      || peer->af_group[AFI_IP6][SAFI_ENCAP])
     return 1;
   return 0;
 }
@@ -2356,9 +2364,11 @@ peer_active (struct peer *peer)
   if (peer->afc[AFI_IP][SAFI_UNICAST]
       || peer->afc[AFI_IP][SAFI_MULTICAST]
       || peer->afc[AFI_IP][SAFI_MPLS_VPN]
+      || peer->afc[AFI_IP][SAFI_ENCAP]
       || peer->afc[AFI_IP6][SAFI_UNICAST]
       || peer->afc[AFI_IP6][SAFI_MULTICAST]
-      || peer->afc[AFI_IP6][SAFI_MPLS_VPN])
+      || peer->afc[AFI_IP6][SAFI_MPLS_VPN]
+      || peer->afc[AFI_IP6][SAFI_ENCAP])
     return 1;
   return 0;
 }
@@ -2370,9 +2380,11 @@ peer_active_nego (struct peer *peer)
   if (peer->afc_nego[AFI_IP][SAFI_UNICAST]
       || peer->afc_nego[AFI_IP][SAFI_MULTICAST]
       || peer->afc_nego[AFI_IP][SAFI_MPLS_VPN]
+      || peer->afc_nego[AFI_IP][SAFI_ENCAP]
       || peer->afc_nego[AFI_IP6][SAFI_UNICAST]
       || peer->afc_nego[AFI_IP6][SAFI_MULTICAST]
-      || peer->afc_nego[AFI_IP6][SAFI_MPLS_VPN])
+      || peer->afc_nego[AFI_IP6][SAFI_MPLS_VPN]
+      || peer->afc_nego[AFI_IP6][SAFI_ENCAP])
     return 1;
   return 0;
 }
@@ -5594,6 +5606,7 @@ bgp_init (void)
   bgp_address_init ();
   bgp_scan_init ();
   bgp_mplsvpn_init ();
+  bgp_encap_init ();
 
   /* Access list initialize. */
   access_list_init ();
-- 
2.1.3


_______________________________________________
Quagga-dev mailing list
Quagga-dev@lists.quagga.net
https://lists.quagga.net/mailman/listinfo/quagga-dev


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic