[quagga-dev,16481] Add BGP Large Communities support (draft-ietf-idr-large-community-11)

Message ID 201612310516.uBV5GY26012329@tesla.psc.edu
State Under Review
Headers show

Commit Message

Michael H Lambert Dec. 31, 2016, 4:09 a.m.
Signed-off-by: Michael Lambert <lambert@psc.edu>
---
 bgpd/Makefile.am      |    6 +-
 bgpd/bgp_attr.c       |  111 +++++-
 bgpd/bgp_attr.h       |    5 +-
 bgpd/bgp_clist.c      |  313 +++++++++++++++
 bgpd/bgp_clist.h      |   18 +-
 bgpd/bgp_ecommunity.c |    1 +
 bgpd/bgp_encap.c      |    1 +
 bgpd/bgp_lcommunity.c |  562 +++++++++++++++++++++++++++
 bgpd/bgp_lcommunity.h |   75 ++++
 bgpd/bgp_mpath.c      |   16 +
 bgpd/bgp_open.c       |    2 +
 bgpd/bgp_packet.c     |    1 +
 bgpd/bgp_route.c      | 1009 ++++++++++++++++++++++++++++++++++++++++++++++++-
 bgpd/bgp_routemap.c   |  440 ++++++++++++++++++++-
 bgpd/bgp_vty.c        |  475 ++++++++++++++++++++++-
 bgpd/bgpd.c           |   19 +-
 bgpd/bgpd.h           |    2 +
 lib/memtypes.c        |    3 +
 18 files changed, 3030 insertions(+), 29 deletions(-)
 create mode 100644 bgpd/bgp_lcommunity.c
 create mode 100644 bgpd/bgp_lcommunity.h

Comments

cisystem@netdef.org Dec. 31, 2016, 5:40 a.m. | #1
Continous Integration Result: FAILED

See below for issues.
This is an EXPERIMENTAL automated CI system.
For questions and feedback, feel free to email
Martin Winter <mwinter@opensourcerouting.org>.

Patches applied :
  Patchwork 2295: http://patchwork.quagga.net/patch/2295
       [quagga-dev,16481] Add BGP Large Communities support (draft-ietf-idr-large-community-11)
Tested on top of Git : 258f3da (as of 20161018.130352 UTC)
CI System Testrun URL: https://ci1.netdef.org/browse/QUAGGA-QPWORK-386/


Get source and apply patch from patchwork: Successful
----------------

Building Stage: Failed
----------------
Ubuntu1204 amd64 build: Successful
FreeBSD9 amd64 build: Successful
CentOS6 amd64 build: Successful
NetBSD6 amd64 build: Successful
FreeBSD11 amd64 build: Successful
NetBSD7 amd64 build: Successful
Debian8 amd64 build: Successful
Ubuntu1404 amd64 build: Successful
OmniOS amd64 build: Successful
FreeBSD10 amd64 build: Successful
Ubuntu1604 amd64 build: Successful
CentOS7 amd64 build: Successful

Make failed for Openbsd60 amd64 build:    (see full log in attachment openbsd60_amd64_make.log)
>   CC       kernel_socket.o
> kernel_socket.c:92:2: warning: #warning "net/route.h does not define RT_ROUNDUP; making unwarranted assumptions!"
> kernel_socket.c:245: error: 'RTF_XRESOLVE' undeclared here (not in a function)
> *** Error 1 in zebra (Makefile:620 'kernel_socket.o': @echo "  CC      " kernel_socket.o;gcc -DHAVE_CONFIG_H -DSYSCONFDIR=\"/home/ci/cibuild...)
> *** Error 1 in . (Makefile:490 'all-recursive')
> *** Error 1 in /home/ci/cibuild.386/quagga-source (Makefile:397 'all')


Regards,
  NetDEF/OpenSourceRouting Continous Integration (CI) System

---
OpenSourceRouting.org is a project of the Network Device Education Foundation,
For more information, see www.netdef.org and www.opensourcerouting.org
For questions in regards to this CI System, contact Martin Winter, mwinter@netdef.org
make  all-recursive
Making all in lib
(gawk -f ./memtypes.awk ./memtypes.c > memtypes.h)
/usr/bin/perl ./route_types.pl < ./route_types.txt > route_types.h
true
make  all-am
  CC       network.lo
  CC       pid_output.lo
  CC       getopt.lo
  CC       getopt1.lo
  CC       daemon.lo
  CC       checksum.lo
  CC       vector.lo
  CC       linklist.lo
  CC       vty.lo
  CC       command.lo
  CC       sockunion.lo
  CC       prefix.lo
  CC       thread.lo
  CC       if.lo
  CC       memory.lo
  CC       buffer.lo
  CC       table.lo
  CC       hash.lo
  CC       filter.lo
  CC       routemap.lo
  CC       distribute.lo
  CC       stream.lo
stream.c:500:2: warning: #warning "Unknown floating-point format, __func__ may be wrong"
stream.c:516:2: warning: #warning "Unknown floating-point format, __func__ may be wrong"
stream.c:638:2: warning: #warning "Unknown floating-point format, __func__ may be wrong"
stream.c:655:2: warning: #warning "Unknown floating-point format, __func__ may be wrong"
  CC       str.lo
  CC       log.lo
  CC       plist.lo
  CC       zclient.lo
  CC       sockopt.lo
  CC       smux.lo
  CC       agentx.lo
  CC       snmp.lo
  CC       md5.lo
  CC       if_rmap.lo
  CC       keychain.lo
  CC       privs.lo
  CC       sigevent.lo
  CC       pqueue.lo
  CC       jhash.lo
  CC       memtypes.lo
  CC       workqueue.lo
  CC       vrf.lo
  CC       event_counter.lo
  CC       nexthop.lo
  CCLD     libzebra.la
Making all in qpb
make  all-am
  CC       qpb.lo
  CCLD     libquagga_pb.la
Making all in fpm
make  all-am
  CC       fpm_pb.lo
  CCLD     libfpm_pb.la
Making all in zebra
  CC       test_main.o
  CC       zebra_rib.o
  CC       interface.o
  CC       connected.o
  CC       debug.o
  CC       zebra_vty.o
  CC       kernel_null.o
  CC       redistribute_null.o
  CC       ioctl_null.o
  CC       misc_null.o
  CC       zebra_rnh_null.o
  CCLD     testzebra
../lib/.libs/libzebra.so.0.0: warning: warning: strcat() is almost always misused, please use strlcat()
../lib/.libs/libzebra.so.0.0: warning: warning: random() may return deterministic values, is that what you want?
../lib/.libs/libzebra.so.0.0: warning: warning: strcpy() is almost always misused, please use strlcpy()
../lib/.libs/libzebra.so.0.0: warning: warning: sprintf() is often misused, please use snprintf()
  CC       zserv.o
zserv.c: In function 'config_write_fpm':
zserv.c:2289: warning: implicit declaration of function 'fpm_remote_srv_write'
  CC       main.o
  CC       zebra_routemap.o
  CC       redistribute.o
  CC       rtadv.o
rtadv.c: In function 'rtadv_send_packet':
rtadv.c:136: warning: unused variable 'sdl'
  CC       zebra_snmp.o
  CC       irdp_main.o
  CC       irdp_interface.o
  CC       irdp_packet.o
  CC       router-id.o
  CC       zebra_fpm.o
zebra_fpm.c: In function 'zfpm_encode_route':
zebra_fpm.c:883: warning: unused variable 'cmd'
zebra_fpm.c: At top level:
zebra_fpm.c:1676: warning: no previous prototype for 'fpm_remote_srv_write'
  CC       zebra_rnh.o
  CC       ioctl.o
  CC       ipforward_sysctl.o
  CC       if_ioctl.o
if_ioctl.c: In function 'interface_list_ioctl':
if_ioctl.c:113: warning: comparison between signed and unsigned
  CC       rt_socket.o
  CC       rtread_sysctl.o
  CC       kernel_socket.o
kernel_socket.c:92:2: warning: #warning "net/route.h does not define RT_ROUNDUP; making unwarranted assumptions!"
kernel_socket.c:245: error: 'RTF_XRESOLVE' undeclared here (not in a function)
*** Error 1 in zebra (Makefile:620 'kernel_socket.o': @echo "  CC      " kernel_socket.o;gcc -DHAVE_CONFIG_H -DSYSCONFDIR=\"/home/ci/cibuild...)
*** Error 1 in . (Makefile:490 'all-recursive')
*** Error 1 in /home/ci/cibuild.386/quagga-source (Makefile:397 'all')
Michael H Lambert Dec. 31, 2016, 5:54 a.m. | #2
The OpenBSD issue does not seem specific to this patch.  It also fails at the same place when building master.  According to the changelog, RTF_XRESOLVE was removed in OpenBSD 5.9.  It doesn't look like RTF_XRESOLVE is actually used in quagga, so it might be safe to conditionally compile or even omit.  RT_ROUNDUP might be more problematic.

Also, what version of FreeBSD 10 is being used?

Michael

> On 31 Dec 2016, at 00:40, cisystem@netdef.org wrote:
> 
> Continous Integration Result: FAILED
> 
> See below for issues.
> This is an EXPERIMENTAL automated CI system.
> For questions and feedback, feel free to email
> Martin Winter <mwinter@opensourcerouting.org>.
> 
> Patches applied :
>  Patchwork 2295: http://patchwork.quagga.net/patch/2295
>       [quagga-dev,16481] Add BGP Large Communities support (draft-ietf-idr-large-community-11)
> Tested on top of Git : 258f3da (as of 20161018.130352 UTC)
> CI System Testrun URL: https://ci1.netdef.org/browse/QUAGGA-QPWORK-386/
> 
> 
> Get source and apply patch from patchwork: Successful
> ----------------
> 
> Building Stage: Failed
> ----------------
> Ubuntu1204 amd64 build: Successful
> FreeBSD9 amd64 build: Successful
> CentOS6 amd64 build: Successful
> NetBSD6 amd64 build: Successful
> FreeBSD11 amd64 build: Successful
> NetBSD7 amd64 build: Successful
> Debian8 amd64 build: Successful
> Ubuntu1404 amd64 build: Successful
> OmniOS amd64 build: Successful
> FreeBSD10 amd64 build: Successful
> Ubuntu1604 amd64 build: Successful
> CentOS7 amd64 build: Successful
> 
> Make failed for Openbsd60 amd64 build:    (see full log in attachment openbsd60_amd64_make.log)
>>  CC       kernel_socket.o
>> kernel_socket.c:92:2: warning: #warning "net/route.h does not define RT_ROUNDUP; making unwarranted assumptions!"
>> kernel_socket.c:245: error: 'RTF_XRESOLVE' undeclared here (not in a function)
>> *** Error 1 in zebra (Makefile:620 'kernel_socket.o': @echo "  CC      " kernel_socket.o;gcc -DHAVE_CONFIG_H -DSYSCONFDIR=\"/home/ci/cibuild...)
>> *** Error 1 in . (Makefile:490 'all-recursive')
>> *** Error 1 in /home/ci/cibuild.386/quagga-source (Makefile:397 'all')
> 
> 
> Regards,
>  NetDEF/OpenSourceRouting Continous Integration (CI) System
> 
> ---
> OpenSourceRouting.org is a project of the Network Device Education Foundation,
> For more information, see www.netdef.org and www.opensourcerouting.org
> For questions in regards to this CI System, contact Martin Winter, mwinter@netdef.org
> <openbsd60_amd64_make.log>

Patch hide | download patch | download mbox

diff --git a/bgpd/Makefile.am b/bgpd/Makefile.am
index fe1be32..753b679 100644
--- a/bgpd/Makefile.am
+++ b/bgpd/Makefile.am
@@ -14,7 +14,8 @@  libbgp_a_SOURCES = \
 	bgpd.c bgp_fsm.c bgp_aspath.c bgp_community.c bgp_attr.c \
 	bgp_debug.c bgp_route.c bgp_zebra.c bgp_open.c bgp_routemap.c \
 	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_dump.c bgp_snmp.c bgp_ecommunity.c bgp_lcommunity.c \
+	bgp_mplsvpn.c bgp_nexthop.c \
 	bgp_damp.c bgp_table.c bgp_advertise.c bgp_vty.c bgp_mpath.c \
 	bgp_encap.c bgp_encap_tlv.c bgp_nht.c
 
@@ -22,7 +23,8 @@  noinst_HEADERS = \
 	bgp_aspath.h bgp_attr.h bgp_community.h bgp_debug.h bgp_fsm.h \
 	bgp_network.h bgp_open.h bgp_packet.h bgp_regex.h bgp_route.h \
 	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_ecommunity.h bgp_lcommunity.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.h bgp_encap_tlv.h bgp_encap_types.h bgp_nht.h
 
diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c
index 6aab50a..1511319 100644
--- a/bgpd/bgp_attr.c
+++ b/bgpd/bgp_attr.c
@@ -39,6 +39,7 @@  Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 #include "bgpd/bgp_debug.h"
 #include "bgpd/bgp_packet.h"
 #include "bgpd/bgp_ecommunity.h"
+#include "bgpd/bgp_lcommunity.h"
 #include "table.h"
 #include "bgp_encap_types.h"
 
@@ -65,6 +66,18 @@  static const struct message attr_str [] =
   { BGP_ATTR_AS4_AGGREGATOR,   "AS4_AGGREGATOR" }, 
   { BGP_ATTR_AS_PATHLIMIT,     "AS_PATHLIMIT" },
   { BGP_ATTR_ENCAP,            "ENCAP" },
+  { 21,                        ""},
+  { 22,                        ""},
+  { 23,                        ""},
+  { 24,                        ""},
+  { 25,                        ""},
+  { 26,                        ""},
+  { 27,                        ""},
+  { 28,                        ""},
+  { 29,                        ""},
+  { 30,                        ""},
+  { 31,                        ""},
+  { BGP_ATTR_LARGE_COMMUNITIES, "LARGE_COMMUNITY" }
 };
 static const int attr_str_max = array_size(attr_str);
 
@@ -505,6 +518,8 @@  attrhash_key_make (void *p)
   
   if (extra)
     {
+      if (extra->lcommunity)
+	MIX(lcommunity_hash_make (extra->lcommunity));
       if (extra->ecommunity)
         MIX(ecommunity_hash_make (extra->ecommunity));
       if (extra->cluster)
@@ -547,6 +562,7 @@  attrhash_cmp (const void *p1, const void *p2)
           && IPV6_ADDR_SAME (&ae1->mp_nexthop_local, &ae2->mp_nexthop_local)
           && IPV4_ADDR_SAME (&ae1->mp_nexthop_global_in, &ae2->mp_nexthop_global_in)
           && ae1->ecommunity == ae2->ecommunity
+	  && ae1->lcommunity == ae2->lcommunity
           && ae1->cluster == ae2->cluster
           && ae1->transit == ae2->transit
 	  && (ae1->encap_tunneltype == ae2->encap_tunneltype)
@@ -658,6 +674,13 @@  bgp_attr_intern (struct attr *attr)
             attre->ecommunity->refcnt++;
           
         }
+      if (attre->lcommunity)
+        {
+          if (! attre->lcommunity->refcnt)
+            attre->lcommunity = lcommunity_intern (attre->lcommunity);
+          else
+            attre->lcommunity->refcnt++;
+        }
       if (attre->cluster)
         {
           if (! attre->cluster->refcnt)
@@ -791,7 +814,11 @@  bgp_attr_unintern_sub (struct attr *attr)
       if (attr->extra->ecommunity)
         ecommunity_unintern (&attr->extra->ecommunity);
       UNSET_FLAG(attr->flag, ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES));
-      
+
+      if (attr->extra->lcommunity)
+        lcommunity_unintern (&attr->extra->lcommunity);
+      UNSET_FLAG(attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LARGE_COMMUNITIES));
+
       if (attr->extra->cluster)
         cluster_unintern (attr->extra->cluster);
       UNSET_FLAG(attr->flag, ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST));
@@ -853,6 +880,8 @@  bgp_attr_flush (struct attr *attr)
 
       if (attre->ecommunity && ! attre->ecommunity->refcnt)
         ecommunity_free (&attre->ecommunity);
+      if (attre->lcommunity && ! attre->lcommunity->refcnt)
+	lcommunity_free (&attre->lcommunity);
       if (attre->cluster && ! attre->cluster->refcnt)
         {
           cluster_free (attre->cluster);
@@ -1002,6 +1031,7 @@  const u_int8_t attr_flags_values [] = {
   [BGP_ATTR_EXT_COMMUNITIES] =  BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
   [BGP_ATTR_AS4_PATH] =         BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
   [BGP_ATTR_AS4_AGGREGATOR] =   BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
+  [BGP_ATTR_LARGE_COMMUNITIES] = BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL
 };
 static const size_t attr_flags_values_max = array_size(attr_flags_values) - 1;
 
@@ -1791,6 +1821,37 @@  bgp_mp_unreach_parse (struct bgp_attr_parser_args *args,
   return BGP_ATTR_PARSE_PROCEED;
 }
 
+/* Large Community attribute. */
+static bgp_attr_parse_ret_t
+bgp_attr_large_community (struct bgp_attr_parser_args *args)
+{
+  struct peer *const peer = args->peer;
+  struct attr *const attr = args->attr;
+  const bgp_size_t length = args->length;
+
+  if (length == 0)
+    {
+      if (attr->extra)
+        attr->extra->lcommunity = NULL;
+      /* Empty extcomm doesn't seem to be invalid per se */
+      return BGP_ATTR_PARSE_PROCEED;
+    }
+
+  (bgp_attr_extra_get (attr))->lcommunity =
+    lcommunity_parse ((u_int8_t *)stream_pnt (peer->ibuf), length);
+  /* XXX: fix ecommunity_parse to use stream API */
+  stream_forward_getp (peer->ibuf, length);
+
+  if (attr->extra && !attr->extra->lcommunity)
+    return bgp_attr_malformed (args,
+                               BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
+                               args->total);
+
+  attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LARGE_COMMUNITIES);
+
+  return BGP_ATTR_PARSE_PROCEED;
+}
+
 /* Extended Community attribute. */
 static bgp_attr_parse_ret_t
 bgp_attr_ext_communities (struct bgp_attr_parser_args *args)
@@ -1812,7 +1873,7 @@  bgp_attr_ext_communities (struct bgp_attr_parser_args *args)
   /* XXX: fix ecommunity_parse to use stream API */
   stream_forward_getp (peer->ibuf, length);
   
-  if (!attr->extra->ecommunity)
+  if (attr->extra && !attr->extra->ecommunity)
     return bgp_attr_malformed (args,
                                BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
                                args->total);
@@ -2225,6 +2286,9 @@  bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
 	case BGP_ATTR_COMMUNITIES:
 	  ret = bgp_attr_community (&attr_args);
 	  break;
+	case BGP_ATTR_LARGE_COMMUNITIES:
+	  ret = bgp_attr_large_community (&attr_args);
+	  break;
 	case BGP_ATTR_ORIGINATOR_ID:
 	  ret = bgp_attr_originator_id (&attr_args);
 	  break;
@@ -2794,6 +2858,28 @@  bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
       stream_put (s, attr->community->val, attr->community->size * 4);
     }
 
+  /*
+   * Large Community attribute.
+   */
+  if (attr->extra &&
+      CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_LARGE_COMMUNITY)
+      && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LARGE_COMMUNITIES)))
+    {
+      if (attr->extra->lcommunity->size * 12 > 255)
+	{
+	  stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
+	  stream_putc (s, BGP_ATTR_LARGE_COMMUNITIES);
+	  stream_putw (s, attr->extra->lcommunity->size * 12);
+	}
+      else
+	{
+	  stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
+	  stream_putc (s, BGP_ATTR_LARGE_COMMUNITIES);
+	  stream_putc (s, attr->extra->lcommunity->size * 12);
+	}
+      stream_put (s, attr->extra->lcommunity->val, attr->extra->lcommunity->size * 12);
+    }
+
   /* Route Reflector. */
   if (peer->sort == BGP_PEER_IBGP
       && from
@@ -3002,6 +3088,7 @@  bgp_attr_init (void)
   attrhash_init ();
   community_init ();
   ecommunity_init ();
+  lcommunity_init ();
   cluster_init ();
   transit_init ();
 }
@@ -3013,6 +3100,7 @@  bgp_attr_finish (void)
   attrhash_finish ();
   community_finish ();
   ecommunity_finish ();
+  lcommunity_finish ();
   cluster_finish ();
   transit_finish ();
 }
@@ -3115,6 +3203,25 @@  bgp_dump_routes_attr (struct stream *s, struct attr *attr,
       stream_put (s, attr->community->val, attr->community->size * 4);
     }
 
+    /* Large Community attribute. */
+  if (attr->extra && attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LARGE_COMMUNITIES))
+    {
+      if (attr->extra->lcommunity->size * 12 > 255)
+	{
+	  stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
+	  stream_putc (s, BGP_ATTR_COMMUNITIES);
+	  stream_putw (s, attr->extra->lcommunity->size * 12);
+	}
+      else
+	{
+	  stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
+	  stream_putc (s, BGP_ATTR_COMMUNITIES);
+	  stream_putc (s, attr->extra->lcommunity->size * 12);
+	}
+
+      stream_put (s, attr->extra->lcommunity->val, attr->extra->lcommunity->size * 12);
+    }
+
   /* Add a MP_NLRI attribute to dump the IPv6 next hop */
   if (prefix != NULL && prefix->family == AF_INET6 && attr->extra &&
      (attr->extra->mp_nexthop_len == 16 || attr->extra->mp_nexthop_len == 32) )
diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h
index 8457f40..cf82765 100644
--- a/bgpd/bgp_attr.h
+++ b/bgpd/bgp_attr.h
@@ -66,7 +66,10 @@  struct attr_extra
 
   /* Extended Communities attribute. */
   struct ecommunity *ecommunity;
-  
+
+  /* Large Communities attribute. */
+  struct lcommunity *lcommunity;
+
   /* Route-Reflector Cluster attribute */
   struct cluster_list *cluster;
   
diff --git a/bgpd/bgp_clist.c b/bgpd/bgp_clist.c
index bb06028..54f9418 100644
--- a/bgpd/bgp_clist.c
+++ b/bgpd/bgp_clist.c
@@ -28,6 +28,7 @@  Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 #include "bgpd/bgpd.h"
 #include "bgpd/bgp_community.h"
 #include "bgpd/bgp_ecommunity.h"
+#include "bgpd/bgp_lcommunity.h"
 #include "bgpd/bgp_aspath.h"
 #include "bgpd/bgp_regex.h"
 #include "bgpd/bgp_clist.h"
@@ -44,6 +45,8 @@  community_list_master_lookup (struct community_list_handler *ch, int master)
 	return &ch->community_list;
       case EXTCOMMUNITY_LIST_MASTER:
 	return &ch->extcommunity_list;
+      case LARGE_COMMUNITY_LIST_MASTER:
+	return &ch->lcommunity_list;
       }
   return NULL;
 }
@@ -65,6 +68,10 @@  community_entry_free (struct community_entry *entry)
       if (entry->u.com)
         community_free (entry->u.com);
       break;
+    case LARGE_COMMUNITY_LIST_STANDARD:
+      if (entry->u.lcom)
+        lcommunity_free (&entry->u.lcom);
+      break;
     case EXTCOMMUNITY_LIST_STANDARD:
       /* In case of standard extcommunity-list, configuration string
          is made by ecommunity_ecom2str().  */
@@ -75,6 +82,7 @@  community_entry_free (struct community_entry *entry)
       break;
     case COMMUNITY_LIST_EXPANDED:
     case EXTCOMMUNITY_LIST_EXPANDED:
+    case LARGE_COMMUNITY_LIST_EXPANDED:
       if (entry->config)
         XFREE (MTYPE_COMMUNITY_LIST_CONFIG, entry->config);
       if (entry->reg)
@@ -315,12 +323,17 @@  community_list_entry_lookup (struct community_list *list, const void *arg,
           if (community_cmp (entry->u.com, arg))
             return entry;
           break;
+	case LARGE_COMMUNITY_LIST_STANDARD:
+          if (lcommunity_cmp (entry->u.lcom, arg))
+            return entry;
+          break;
         case EXTCOMMUNITY_LIST_STANDARD:
           if (ecommunity_cmp (entry->u.ecom, arg))
             return entry;
           break;
         case COMMUNITY_LIST_EXPANDED:
         case EXTCOMMUNITY_LIST_EXPANDED:
+	case LARGE_COMMUNITY_LIST_EXPANDED:
           if (strcmp (entry->config, arg) == 0)
             return entry;
           break;
@@ -441,6 +454,91 @@  community_regexp_match (struct community *com, regex_t * reg)
   return 0;
 }
 
+static char *
+lcommunity_str_get (struct lcommunity *lcom, int i)
+{
+  struct lcommunity_val lcomval;
+  u_int32_t globaladmin;
+  u_int32_t localdata1;
+  u_int32_t localdata2;
+  char *str;
+  u_char *ptr;
+  char *pnt;
+
+  ptr = lcom->val;
+  ptr += (i * LCOMMUNITY_SIZE);
+
+  memcpy (&lcomval, ptr, LCOMMUNITY_SIZE);
+
+  /* Allocate memory.  48 bytes taken off bgp_lcommunity.c */
+  str = pnt = XMALLOC (MTYPE_LCOMMUNITY_STR, 48);
+
+  ptr = (u_char *)lcomval.val;
+  globaladmin = (*ptr++ << 24);
+  globaladmin |= (*ptr++ << 16);
+  globaladmin |= (*ptr++ << 8);
+  globaladmin |= (*ptr++);
+
+  localdata1 = (*ptr++ << 24);
+  localdata1 |= (*ptr++ << 16);
+  localdata1 |= (*ptr++ << 8);
+  localdata1 |= (*ptr++);
+
+  localdata2 = (*ptr++ << 24);
+  localdata2 |= (*ptr++ << 16);
+  localdata2 |= (*ptr++ << 8);
+  localdata2 |= (*ptr++);
+
+  sprintf (pnt, "%u:%u:%u", globaladmin, localdata1, localdata2);
+  pnt += strlen (pnt);
+  *pnt = '\0';
+
+  return str;
+}
+
+/* Internal function to perform regular expression match for
+ *  * a single community. */
+static int
+lcommunity_regexp_include (regex_t * reg, struct lcommunity *lcom, int i)
+{
+  const char *str;
+
+  /* When there is no communities attribute it is treated as empty
+ *      string.  */
+  if (lcom == NULL || lcom->size == 0)
+    str = "";
+  else
+    str = lcommunity_str_get (lcom, i);
+
+  /* Regular expression match.  */
+  if (regexec (reg, str, 0, NULL, 0) == 0)
+    return 1;
+
+  /* No match.  */
+  return 0;
+}
+
+static int
+lcommunity_regexp_match (struct lcommunity *com, regex_t * reg)
+{
+  const char *str;
+
+  /* When there is no communities attribute it is treated as empty
+     string.  */
+  if (com == NULL || com->size == 0)
+    str = "";
+  else
+    str = lcommunity_str (com);
+
+  /* Regular expression match.  */
+  if (regexec (reg, str, 0, NULL, 0) == 0)
+    return 1;
+
+  /* No match.  */
+  return 0;
+}
+
+
 static int
 ecommunity_regexp_match (struct ecommunity *ecom, regex_t * reg)
 {
@@ -491,6 +589,30 @@  community_list_match (struct community *com, struct community_list *list)
 }
 
 int
+lcommunity_list_match (struct lcommunity *lcom, struct community_list *list)
+{
+  struct community_entry *entry;
+
+  for (entry = list->head; entry; entry = entry->next)
+    {
+      if (entry->any)
+        return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
+
+      if (entry->style == LARGE_COMMUNITY_LIST_STANDARD)
+        {
+          if (lcommunity_match (lcom, entry->u.lcom))
+            return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
+        }
+      else if (entry->style == LARGE_COMMUNITY_LIST_EXPANDED)
+        {
+          if (lcommunity_regexp_match (lcom, entry->reg))
+            return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
+        }
+    }
+  return 0;
+}
+
+int
 ecommunity_list_match (struct ecommunity *ecom, struct community_list *list)
 {
   struct community_entry *entry;
@@ -638,12 +760,17 @@  community_list_dup_check (struct community_list *list,
           if (community_cmp (entry->u.com, new->u.com))
             return 1;
           break;
+        case LARGE_COMMUNITY_LIST_STANDARD:
+          if (lcommunity_cmp (entry->u.lcom, new->u.lcom))
+            return 1;
+          break;
         case EXTCOMMUNITY_LIST_STANDARD:
           if (ecommunity_cmp (entry->u.ecom, new->u.ecom))
             return 1;
           break;
         case COMMUNITY_LIST_EXPANDED:
         case EXTCOMMUNITY_LIST_EXPANDED:
+	case LARGE_COMMUNITY_LIST_EXPANDED:
           if (strcmp (entry->config, new->config) == 0)
             return 1;
           break;
@@ -762,6 +889,186 @@  community_list_unset (struct community_list_handler *ch,
   return 0;
 }
 
+/* Delete all permitted large communities in the list from com.  */
+struct lcommunity *
+lcommunity_list_match_delete (struct lcommunity *lcom,
+			      struct community_list *list)
+{
+  struct community_entry *entry;
+  u_int32_t com_index_to_delete[lcom->size];
+  u_char *ptr;
+  int delete_index = 0;
+  int i;
+
+  /* Loop over each lcommunity value and evaluate each against the
+   * community-list.  If we need to delete a community value add its index to
+   * com_index_to_delete.
+   */
+
+  for (i = 0; i < lcom->size; i++)
+    {
+      ptr = lcom->val + (i * LCOMMUNITY_SIZE);
+      for (entry = list->head; entry; entry = entry->next)
+        {
+          if (entry->any)
+            {
+              if (entry->direct == COMMUNITY_PERMIT)
+                {
+                  com_index_to_delete[delete_index] = i;
+                  delete_index++;
+                }
+              break;
+            }
+
+          else if ((entry->style == LARGE_COMMUNITY_LIST_STANDARD)
+                   && lcommunity_include (entry->u.lcom, ptr) )
+            {
+              if (entry->direct == COMMUNITY_PERMIT)
+                {
+                  com_index_to_delete[delete_index] = i;
+                  delete_index++;
+                }
+              break;
+            }
+
+          else if ((entry->style == LARGE_COMMUNITY_LIST_STANDARD)
+                   && entry->reg
+		   && lcommunity_regexp_include (entry->reg, lcom, i))
+            {
+              if (entry->direct == COMMUNITY_PERMIT)
+                {
+                  com_index_to_delete[delete_index] = i;
+                  delete_index++;
+                }
+              break;
+            }
+         }
+     }
+
+  /* Delete all of the communities we flagged for deletion */
+
+  for (i = delete_index-1; i >= 0; i--)
+    {
+      ptr = lcom->val + (com_index_to_delete[i] * LCOMMUNITY_SIZE);
+      lcommunity_del_val (lcom, ptr);
+    }
+
+  return lcom;
+}
+
+/* Set lcommunity-list.  */
+int
+lcommunity_list_set (struct community_list_handler *ch,
+		     const char *name, const char *str, int direct, int style)
+{
+  struct community_entry *entry = NULL;
+  struct community_list *list;
+  struct lcommunity *lcom = NULL;
+  regex_t *regex = NULL;
+
+  /* Get community list. */
+  list = community_list_get (ch, name, LARGE_COMMUNITY_LIST_MASTER);
+
+  /* When community-list already has entry, new entry should have same
+     style.  If you want to have mixed style community-list, you can
+     comment out this check.  */
+  if (!community_list_empty_p (list))
+    {
+      struct community_entry *first;
+
+      first = list->head;
+
+      if (style != first->style)
+	{
+	  return (first->style == COMMUNITY_LIST_STANDARD
+		  ? COMMUNITY_LIST_ERR_STANDARD_CONFLICT
+		  : COMMUNITY_LIST_ERR_EXPANDED_CONFLICT);
+	}
+    }
+
+  if (str)
+    {
+      if (style == LARGE_COMMUNITY_LIST_STANDARD)
+	lcom = lcommunity_str2com (str);
+      else
+	regex = bgp_regcomp (str);
+
+      if (! lcom && ! regex)
+	return COMMUNITY_LIST_ERR_MALFORMED_VAL;
+    }
+
+  entry = community_entry_new ();
+  entry->direct = direct;
+  entry->style = style;
+  entry->any = (str ? 0 : 1);
+  entry->u.lcom = lcom;
+  entry->reg = regex;
+  if (lcom)
+    entry->config = lcommunity_lcom2str (lcom, LCOMMUNITY_FORMAT_COMMUNITY_LIST);
+  else if (regex)
+    entry->config = XSTRDUP (MTYPE_COMMUNITY_LIST_CONFIG, str);
+  else
+    entry->config = NULL;
+
+  /* Do not put duplicated community entry.  */
+  if (community_list_dup_check (list, entry))
+    community_entry_free (entry);
+  else
+    community_list_entry_add (list, entry);
+
+  return 0;
+}
+
+/* Unset community-list.  When str is NULL, delete all of
+   community-list entry belongs to the specified name.  */
+int
+lcommunity_list_unset (struct community_list_handler *ch,
+		       const char *name, const char *str,
+		       int direct, int style)
+{
+  struct community_entry *entry = NULL;
+  struct community_list *list;
+  struct lcommunity *lcom = NULL;
+  regex_t *regex = NULL;
+
+  /* Lookup community list.  */
+  list = community_list_lookup (ch, name, LARGE_COMMUNITY_LIST_MASTER);
+  if (list == NULL)
+    return COMMUNITY_LIST_ERR_CANT_FIND_LIST;
+
+  /* Delete all of entry belongs to this community-list.  */
+  if (!str)
+    {
+      community_list_delete (list);
+      return 0;
+    }
+
+  if (style == LARGE_COMMUNITY_LIST_STANDARD)
+    lcom = lcommunity_str2com (str);
+  else
+    regex = bgp_regcomp (str);
+
+  if (! lcom && ! regex)
+    return COMMUNITY_LIST_ERR_MALFORMED_VAL;
+
+  if (lcom)
+    entry = community_list_entry_lookup (list, lcom, direct);
+  else
+    entry = community_list_entry_lookup (list, str, direct);
+
+  if (lcom)
+    lcommunity_free (&lcom);
+  if (regex)
+    bgp_regex_free (regex);
+
+  if (!entry)
+    return COMMUNITY_LIST_ERR_CANT_FIND_LIST;
+
+  community_list_entry_delete (list, entry, style);
+
+  return 0;
+}
+
 /* Set extcommunity-list.  */
 int
 extcommunity_list_set (struct community_list_handler *ch,
@@ -904,6 +1211,12 @@  community_list_terminate (struct community_list_handler *ch)
   while ((list = cm->str.head) != NULL)
     community_list_delete (list);
 
+  cm = &ch->lcommunity_list;
+  while ((list = cm->num.head) != NULL)
+    community_list_delete (list);
+  while ((list = cm->str.head) != NULL)
+    community_list_delete (list);
+
   cm = &ch->extcommunity_list;
   while ((list = cm->num.head) != NULL)
     community_list_delete (list);
diff --git a/bgpd/bgp_clist.h b/bgpd/bgp_clist.h
index 5dcb3b4..d9db418 100644
--- a/bgpd/bgp_clist.h
+++ b/bgpd/bgp_clist.h
@@ -24,6 +24,7 @@  Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 /* Master Community-list. */
 #define COMMUNITY_LIST_MASTER          0
 #define EXTCOMMUNITY_LIST_MASTER       1
+#define LARGE_COMMUNITY_LIST_MASTER    2
 
 /* Community-list deny and permit.  */
 #define COMMUNITY_DENY                 0
@@ -38,6 +39,8 @@  Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 #define COMMUNITY_LIST_EXPANDED        1 /* Expanded community-list.  */
 #define EXTCOMMUNITY_LIST_STANDARD     2 /* Standard extcommunity-list.  */
 #define EXTCOMMUNITY_LIST_EXPANDED     3 /* Expanded extcommunity-list.  */
+#define LARGE_COMMUNITY_LIST_STANDARD  4 /* Standard Large community-list.  */
+#define LARGE_COMMUNITY_LIST_EXPANDED  5 /* Expanded Large community-list.  */
 
 /* Community-list.  */
 struct community_list
@@ -80,6 +83,7 @@  struct community_entry
   {
     struct community *com;
     struct ecommunity *ecom;
+    struct lcommunity *lcom;
   } u;
 
   /* Configuration string.  */
@@ -112,6 +116,9 @@  struct community_list_handler
 
   /* Exteded community-list.  */
   struct community_list_master extcommunity_list;
+
+  /* Large community-list.  */
+  struct community_list_master lcommunity_list;
 };
 
 /* Error code of community-list.  */
@@ -139,6 +146,12 @@  extern int extcommunity_list_set (struct community_list_handler *ch,
 extern int extcommunity_list_unset (struct community_list_handler *ch,
 				    const char *name, const char *str,
 				    int direct, int style);
+extern int lcommunity_list_set (struct community_list_handler *ch,
+				const char *name, const char *str,
+				int direct, int style);
+extern int lcommunity_list_unset (struct community_list_handler *ch,
+				  const char *name, const char *str,
+				  int direct, int style);
 
 extern struct community_list_master *
 community_list_master_lookup (struct community_list_handler *, int);
@@ -148,9 +161,12 @@  community_list_lookup (struct community_list_handler *, const char *, int);
 
 extern int community_list_match (struct community *, struct community_list *);
 extern int ecommunity_list_match (struct ecommunity *, struct community_list *);
+extern int lcommunity_list_match (struct lcommunity *, struct community_list *);
 extern int community_list_exact_match (struct community *,
 				       struct community_list *);
 extern struct community *
 community_list_match_delete (struct community *, struct community_list *);
-
+extern struct lcommunity *
+lcommunity_list_match_delete (struct lcommunity *lcom,
+			      struct community_list *list);
 #endif /* _QUAGGA_BGP_CLIST_H */
diff --git a/bgpd/bgp_ecommunity.c b/bgpd/bgp_ecommunity.c
index 5d69b42..c06b34e 100644
--- a/bgpd/bgp_ecommunity.c
+++ b/bgpd/bgp_ecommunity.c
@@ -28,6 +28,7 @@  Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 
 #include "bgpd/bgpd.h"
 #include "bgpd/bgp_ecommunity.h"
+#include "bgpd/bgp_lcommunity.h"
 #include "bgpd/bgp_aspath.h"
 
 /* Hash of community attribute. */
diff --git a/bgpd/bgp_encap.c b/bgpd/bgp_encap.c
index edd9d76..ea37cc6 100644
--- a/bgpd/bgp_encap.c
+++ b/bgpd/bgp_encap.c
@@ -41,6 +41,7 @@  Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 #include "bgpd/bgp_route.h"
 #include "bgpd/bgp_attr.h"
 #include "bgpd/bgp_ecommunity.h"
+#include "bgpd/bgp_lcommunity.h"
 #include "bgpd/bgp_mplsvpn.h"
 #include "bgpd/bgp_vty.h"
 #include "bgpd/bgp_encap.h"
diff --git a/bgpd/bgp_lcommunity.c b/bgpd/bgp_lcommunity.c
new file mode 100644
index 0000000..cc67e12
--- /dev/null
+++ b/bgpd/bgp_lcommunity.c
@@ -0,0 +1,562 @@ 
+/* BGP Large Communities Attribute
+
+Copyright (C) 2016 Keyur Patel <keyur@arrcus.com>
+
+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 "hash.h"
+#include "memory.h"
+#include "prefix.h"
+#include "command.h"
+#include "filter.h"
+
+#include "bgpd/bgpd.h"
+#include "bgpd/bgp_lcommunity.h"
+#include "bgpd/bgp_aspath.h"
+
+/* Hash of community attribute. */
+static struct hash *lcomhash;
+
+/* Allocate a new lcommunities.  */
+static struct lcommunity *
+lcommunity_new (void)
+{
+  return (struct lcommunity *) XCALLOC (MTYPE_LCOMMUNITY,
+					sizeof (struct lcommunity));
+}
+
+/* Allocate lcommunities.  */
+void
+lcommunity_free (struct lcommunity **lcom)
+{
+  if ((*lcom)->val)
+    XFREE (MTYPE_LCOMMUNITY_VAL, (*lcom)->val);
+  if ((*lcom)->str)
+    XFREE (MTYPE_LCOMMUNITY_STR, (*lcom)->str);
+  XFREE (MTYPE_LCOMMUNITY, *lcom);
+  lcom = NULL;
+}
+
+/* Add a new Large Communities value to Large Communities
+   Attribute structure.  When the value is already exists in the
+   structure, we don't add the value.  Newly added value is sorted by
+   numerical order.  When the value is added to the structure return 1
+   else return 0.  */
+static int
+lcommunity_add_val (struct lcommunity *lcom, struct lcommunity_val *lval)
+{
+  u_int8_t *p;
+  int ret;
+  int c;
+
+  /* When this is fist value, just add it.  */
+  if (lcom->val == NULL)
+    {
+      lcom->size++;
+      lcom->val = XMALLOC (MTYPE_LCOMMUNITY_VAL, lcom_length (lcom));
+      memcpy (lcom->val, lval->val, LCOMMUNITY_SIZE);
+      return 1;
+    }
+
+  /* If the value already exists in the structure return 0.  */
+  c = 0;
+  for (p = lcom->val; c < lcom->size; p += LCOMMUNITY_SIZE, c++)
+    {
+      ret = memcmp (p, lval->val, LCOMMUNITY_SIZE);
+      if (ret == 0)
+        return 0;
+      if (ret > 0)
+        break;
+    }
+
+  /* Add the value to the structure with numerical sorting.  */
+  lcom->size++;
+  lcom->val = XREALLOC (MTYPE_LCOMMUNITY_VAL, lcom->val, lcom_length (lcom));
+
+  memmove (lcom->val + (c + 1) * LCOMMUNITY_SIZE,
+	   lcom->val + c * LCOMMUNITY_SIZE,
+	   (lcom->size - 1 - c) * LCOMMUNITY_SIZE);
+  memcpy (lcom->val + c * LCOMMUNITY_SIZE, lval->val, LCOMMUNITY_SIZE);
+
+  return 1;
+}
+
+/* This function takes pointer to Large Communites strucutre then
+   create a new Large Communities structure by uniq and sort each
+   Large Communities value.  */
+struct lcommunity *
+lcommunity_uniq_sort (struct lcommunity *lcom)
+{
+  int i;
+  struct lcommunity *new;
+  struct lcommunity_val *lval;
+
+  if (! lcom)
+    return NULL;
+
+  new = lcommunity_new ();
+
+  for (i = 0; i < lcom->size; i++)
+    {
+      lval = (struct lcommunity_val *) (lcom->val + (i * LCOMMUNITY_SIZE));
+      lcommunity_add_val (new, lval);
+    }
+  return new;
+}
+
+/* Parse Large Communites Attribute in BGP packet.  */
+struct lcommunity *
+lcommunity_parse (u_int8_t *pnt, u_short length)
+{
+  struct lcommunity tmp;
+  struct lcommunity *new;
+
+  /* Length check.  */
+  if (length % LCOMMUNITY_SIZE)
+    return NULL;
+
+  /* Prepare tmporary structure for making a new Large Communities
+     Attribute.  */
+  tmp.size = length / LCOMMUNITY_SIZE;
+  tmp.val = pnt;
+
+  /* Create a new Large Communities Attribute by uniq and sort each
+     Large Communities value  */
+  new = lcommunity_uniq_sort (&tmp);
+
+  return lcommunity_intern (new);
+}
+
+/* Duplicate the Large Communities Attribute structure.  */
+struct lcommunity *
+lcommunity_dup (struct lcommunity *lcom)
+{
+  struct lcommunity *new;
+
+  new = XCALLOC (MTYPE_LCOMMUNITY, sizeof (struct lcommunity));
+  new->size = lcom->size;
+  if (new->size)
+    {
+      new->val = XMALLOC (MTYPE_LCOMMUNITY_VAL, lcom->size * LCOMMUNITY_SIZE);
+      memcpy (new->val, lcom->val, lcom->size * LCOMMUNITY_SIZE);
+    }
+  else
+    new->val = NULL;
+  return new;
+}
+
+/* Retrun string representation of communities attribute. */
+char *
+lcommunity_str (struct lcommunity *lcom)
+{
+  if (! lcom->str)
+    lcom->str = lcommunity_lcom2str (lcom, LCOMMUNITY_FORMAT_DISPLAY);
+  return lcom->str;
+}
+
+/* Merge two Large Communities Attribute structure.  */
+struct lcommunity *
+lcommunity_merge (struct lcommunity *lcom1, struct lcommunity *lcom2)
+{
+  if (lcom1->val)
+    lcom1->val = XREALLOC (MTYPE_LCOMMUNITY_VAL, lcom1->val,
+			   (lcom1->size + lcom2->size) * LCOMMUNITY_SIZE);
+  else
+    lcom1->val = XMALLOC (MTYPE_LCOMMUNITY_VAL,
+			  (lcom1->size + lcom2->size) * LCOMMUNITY_SIZE);
+
+  memcpy (lcom1->val + (lcom1->size * LCOMMUNITY_SIZE),
+	  lcom2->val, lcom2->size * LCOMMUNITY_SIZE);
+  lcom1->size += lcom2->size;
+
+  return lcom1;
+}
+
+/* Intern Large Communities Attribute.  */
+struct lcommunity *
+lcommunity_intern (struct lcommunity *lcom)
+{
+  struct lcommunity *find;
+
+  assert (lcom->refcnt == 0);
+
+  find = (struct lcommunity *) hash_get (lcomhash, lcom, hash_alloc_intern);
+
+  if (find != lcom)
+    lcommunity_free (&lcom);
+
+  find->refcnt++;
+
+  if (! find->str)
+    find->str = lcommunity_lcom2str (find, LCOMMUNITY_FORMAT_DISPLAY);
+
+  return find;
+}
+
+/* Unintern Large Communities Attribute.  */
+void
+lcommunity_unintern (struct lcommunity **lcom)
+{
+  struct lcommunity *ret;
+
+  if ((*lcom)->refcnt)
+    (*lcom)->refcnt--;
+
+  /* Pull off from hash.  */
+  if ((*lcom)->refcnt == 0)
+    {
+      /* Large community must be in the hash.  */
+      ret = (struct lcommunity *) hash_release (lcomhash, *lcom);
+      assert (ret != NULL);
+
+      lcommunity_free (lcom);
+    }
+}
+
+/* Utility function to make hash key.  */
+unsigned int
+lcommunity_hash_make (void *arg)
+{
+  const struct lcommunity *lcom = arg;
+  int size = lcom->size * LCOMMUNITY_SIZE;
+  u_int8_t *pnt = lcom->val;
+  unsigned int key = 0;
+  int c;
+
+  for (c = 0; c < size; c += LCOMMUNITY_SIZE)
+    {
+      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];
+      key += pnt[c + 8];
+      key += pnt[c + 9];
+      key += pnt[c + 10];
+      key += pnt[c + 11];
+    }
+
+  return key;
+}
+
+/* Compare two Large Communities Attribute structure.  */
+int
+lcommunity_cmp (const void *arg1, const void *arg2)
+{
+  const struct lcommunity *lcom1 = arg1;
+  const struct lcommunity *lcom2 = arg2;
+
+  return (lcom1->size == lcom2->size
+	  && memcmp (lcom1->val, lcom2->val, lcom1->size * LCOMMUNITY_SIZE) == 0);
+}
+
+/* Return communities hash.  */
+struct hash *
+lcommunity_hash (void)
+{
+  return lcomhash;
+}
+
+/* Initialize Large Comminities related hash. */
+void
+lcommunity_init (void)
+{
+  lcomhash = hash_create (lcommunity_hash_make, lcommunity_cmp);
+}
+
+void
+lcommunity_finish (void)
+{
+  hash_free (lcomhash);
+  lcomhash = NULL;
+}
+
+/* Large Communities token enum. */
+enum lcommunity_token
+{
+  lcommunity_token_unknown = 0,
+  lcommunity_token_val,
+};
+
+/* Get next Large Communities token from the string. */
+static const char *
+lcommunity_gettoken (const char *str, struct lcommunity_val *lval,
+		     enum lcommunity_token *token)
+{
+  const char *p = str;
+
+  /* Skip white space. */
+  while (isspace ((int) *p))
+    {
+      p++;
+      str++;
+    }
+
+  /* Check the end of the line. */
+  if (*p == '\0')
+    return NULL;
+
+  /* Community value. */
+  if (isdigit ((int) *p))
+    {
+      int separator = 0;
+      int digit = 0;
+      u_int32_t globaladmin = 0;
+      u_int32_t localdata1 = 0;
+      u_int32_t localdata2 = 0;
+
+      while (isdigit ((int) *p) || *p == ':')
+	{
+	  if (*p == ':')
+	    {
+	      if (separator == 2)
+		{
+		  *token = lcommunity_token_unknown;
+		  return NULL;
+		}
+	      else
+		{
+		  separator++;
+		  digit = 0;
+		  if (separator == 1) {
+		    globaladmin = localdata2;
+		  } else {
+		    localdata1 = localdata2;
+		  }
+		  localdata2 = 0;
+		}
+	    }
+	  else
+	    {
+	      digit = 1;
+	      localdata2 *= 10;
+	      localdata2 += (*p - '0');
+	    }
+	  p++;
+	}
+      if (! digit)
+	{
+	  *token = lcommunity_token_unknown;
+	  return NULL;
+	}
+
+      /*
+       * Copy the large comm.
+       */
+      lval->val[0] = (globaladmin >> 24) & 0xff;
+      lval->val[1] = (globaladmin >> 16) & 0xff;
+      lval->val[2] = (globaladmin >> 8) & 0xff;
+      lval->val[3] = globaladmin & 0xff;
+      lval->val[4] = (localdata1 >> 24) & 0xff;
+      lval->val[5] = (localdata1 >> 16) & 0xff;
+      lval->val[6] = (localdata1 >> 8) & 0xff;
+      lval->val[7] = localdata1 & 0xff;
+      lval->val[8] = (localdata2 >> 24) & 0xff;
+      lval->val[9] = (localdata2 >> 16) & 0xff;
+      lval->val[10] = (localdata2 >> 8) & 0xff;
+      lval->val[11] = localdata2 & 0xff;
+
+      *token = lcommunity_token_val;
+      return p;
+    }
+  *token = lcommunity_token_unknown;
+  return p;
+}
+
+/*
+  Convert string to large community attribute.
+  When type is already known, please specify both str and type.
+
+  When string includes keyword for each large community value.
+  Please specify keyword_included as non-zero value.
+*/
+struct lcommunity *
+lcommunity_str2com (const char *str)
+{
+    struct lcommunity *lcom = NULL;
+    enum lcommunity_token token = lcommunity_token_unknown;
+    struct lcommunity_val lval;
+
+    while ((str = lcommunity_gettoken (str, &lval, &token)))
+    {
+        switch (token)
+        {
+            case lcommunity_token_val:
+                if (lcom == NULL)
+                    lcom = lcommunity_new ();
+                lcommunity_add_val (lcom, &lval);
+                break;
+            case lcommunity_token_unknown:
+            default:
+                if (lcom)
+                    lcommunity_free (&lcom);
+                return NULL;
+        }
+    }
+    return lcom;
+}
+
+int
+lcommunity_include (struct lcommunity *lcom, u_char *ptr)
+{
+  int i;
+  u_char *lcom_ptr;
+
+  for (i = 0; i < lcom->size; i++) {
+    lcom_ptr = lcom->val + (i * LCOMMUNITY_SIZE);
+    if (memcmp (ptr, lcom_ptr, LCOMMUNITY_SIZE) == 0)
+      return 1;
+  }
+  return 0;
+}
+
+/* Convert large community attribute to string.
+   The large coms will be in 65535:65531:0 format.
+*/
+char *
+lcommunity_lcom2str (struct lcommunity *lcom, int format)
+{
+  int i;
+  u_int8_t *pnt;
+#define LCOMMUNITY_STR_DEFAULT_LEN  40
+  int str_size;
+  int str_pnt;
+  char *str_buf;
+  int len = 0;
+  int first = 1;
+  u_int32_t  globaladmin, localdata1, localdata2;
+
+  if (lcom->size == 0)
+    {
+      str_buf = XMALLOC (MTYPE_LCOMMUNITY_STR, 1);
+      str_buf[0] = '\0';
+      return str_buf;
+    }
+
+  /* Prepare buffer.  */
+  str_buf = XMALLOC (MTYPE_LCOMMUNITY_STR, LCOMMUNITY_STR_DEFAULT_LEN + 1);
+  str_size = LCOMMUNITY_STR_DEFAULT_LEN + 1;
+  str_pnt = 0;
+
+  for (i = 0; i < lcom->size; i++)
+    {
+      /* Make it sure size is enough.  */
+      while (str_pnt + LCOMMUNITY_STR_DEFAULT_LEN >= str_size)
+	{
+	  str_size *= 2;
+	  str_buf = XREALLOC (MTYPE_LCOMMUNITY_STR, str_buf, str_size);
+	}
+
+      /* Space between each value.  */
+      if (! first)
+	str_buf[str_pnt++] = ' ';
+
+      pnt = lcom->val + (i * 12);
+
+      globaladmin = (*pnt++ << 24);
+      globaladmin |= (*pnt++ << 16);
+      globaladmin |= (*pnt++ << 8);
+      globaladmin |= (*pnt++);
+
+      localdata1 = (*pnt++ << 24);
+      localdata1 |= (*pnt++ << 16);
+      localdata1 |= (*pnt++ << 8);
+      localdata1 |= (*pnt++);
+
+      localdata2 = (*pnt++ << 24);
+      localdata2 |= (*pnt++ << 16);
+      localdata2 |= (*pnt++ << 8);
+      localdata2 |= (*pnt++);
+
+      len = sprintf( str_buf + str_pnt, "%u:%u:%u", globaladmin,
+		     localdata1, localdata2);
+      str_pnt += len;
+      first = 0;
+    }
+  return str_buf;
+}
+
+int
+lcommunity_match (const struct lcommunity *lcom1,
+                  const struct lcommunity *lcom2)
+{
+  int i = 0;
+  int j = 0;
+
+  if (lcom1 == NULL && lcom2 == NULL)
+    return 1;
+
+  if (lcom1 == NULL || lcom2 == NULL)
+    return 0;
+
+  if (lcom1->size < lcom2->size)
+    return 0;
+
+  /* Every community on com2 needs to be on com1 for this to match */
+  while (i < lcom1->size && j < lcom2->size)
+    {
+      if (memcmp (lcom1->val + (i*12), lcom2->val + (j*12), LCOMMUNITY_SIZE) == 0)
+        j++;
+      i++;
+    }
+
+  if (j == lcom2->size)
+    return 1;
+  else
+    return 0;
+}
+
+/* Delete one lcommunity. */
+void
+lcommunity_del_val (struct lcommunity *lcom, u_char *ptr)
+{
+  int i = 0;
+  int c = 0;
+
+  if (! lcom->val)
+    return;
+
+  while (i < lcom->size)
+    {
+      if (memcmp (lcom->val + i*LCOMMUNITY_SIZE, ptr, LCOMMUNITY_SIZE) == 0)
+	{
+	  c = lcom->size -i -1;
+
+	  if (c > 0)
+	    memmove (lcom->val + i*LCOMMUNITY_SIZE, lcom->val + (i + 1)*LCOMMUNITY_SIZE, c * LCOMMUNITY_SIZE);
+
+	  lcom->size--;
+
+	  if (lcom->size > 0)
+	    lcom->val = XREALLOC (MTYPE_COMMUNITY_VAL, lcom->val,
+				 lcom_length (lcom));
+	  else
+	    {
+	      XFREE (MTYPE_COMMUNITY_VAL, lcom->val);
+	      lcom->val = NULL;
+	    }
+	  return;
+	}
+      i++;
+    }
+}
diff --git a/bgpd/bgp_lcommunity.h b/bgpd/bgp_lcommunity.h
new file mode 100644
index 0000000..7841b4b
--- /dev/null
+++ b/bgpd/bgp_lcommunity.h
@@ -0,0 +1,75 @@ 
+/* BGP Large Communities Attribute.
+
+Copyright (C) 2016 Keyur Patel <keyur@arrcus.com>
+
+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.  */
+
+#ifndef _QUAGGA_BGP_LCOMMUNITY_H
+#define _QUAGGA_BGP_LCOMMUNITY_H
+
+/* Extended communities attribute string format.  */
+#define LCOMMUNITY_FORMAT_ROUTE_MAP            0
+#define LCOMMUNITY_FORMAT_COMMUNITY_LIST       1
+#define LCOMMUNITY_FORMAT_DISPLAY              2
+
+/* Large Communities value is twelve octets long.  */
+#define LCOMMUNITY_SIZE                        12
+
+/* Large Communities attribute.  */
+struct lcommunity
+{
+  /* Reference counter.  */
+  unsigned long refcnt;
+
+  /* Size of Extended Communities attribute.  */
+  int size;
+
+  /* Extended Communities value.  */
+  u_int8_t *val;
+
+  /* Human readable format string.  */
+  char *str;
+};
+
+/* Extended community value is eight octet.  */
+struct lcommunity_val
+{
+  char val[LCOMMUNITY_SIZE];
+};
+
+#define lcom_length(X)    ((X)->size * LCOMMUNITY_SIZE)
+
+extern void lcommunity_init (void);
+extern void lcommunity_finish (void);
+extern void lcommunity_free (struct lcommunity **);
+extern struct lcommunity *lcommunity_parse (u_int8_t *, u_short);
+extern struct lcommunity *lcommunity_dup (struct lcommunity *);
+extern struct lcommunity *lcommunity_merge (struct lcommunity *, struct lcommunity *);
+extern struct lcommunity *lcommunity_uniq_sort (struct lcommunity *);
+extern struct lcommunity *lcommunity_intern (struct lcommunity *);
+extern int lcommunity_cmp (const void *, const void *);
+extern void lcommunity_unintern (struct lcommunity **);
+extern unsigned int lcommunity_hash_make (void *);
+extern struct hash *lcommunity_hash (void);
+extern struct lcommunity *lcommunity_str2com (const char *);
+extern char *lcommunity_lcom2str (struct lcommunity *, int);
+extern int lcommunity_match (const struct lcommunity *, const struct lcommunity *);
+extern char *lcommunity_str (struct lcommunity *);
+extern int lcommunity_include (struct lcommunity *lcom, u_char *ptr);
+extern void lcommunity_del_val (struct lcommunity *lcom, u_char *ptr);
+#endif /* _QUAGGA_BGP_LCOMMUNITY_H */
diff --git a/bgpd/bgp_mpath.c b/bgpd/bgp_mpath.c
index 6465aad..8195e47 100644
--- a/bgpd/bgp_mpath.c
+++ b/bgpd/bgp_mpath.c
@@ -38,6 +38,7 @@ 
 #include "bgpd/bgp_aspath.h"
 #include "bgpd/bgp_community.h"
 #include "bgpd/bgp_ecommunity.h"
+#include "bgpd/bgp_lcommunity.h"
 #include "bgpd/bgp_mpath.h"
 
 bool
@@ -647,6 +648,7 @@  bgp_info_mpath_aggregate_update (struct bgp_info *new_best,
   u_char origin, attr_chg;
   struct community *community, *commerge;
   struct ecommunity *ecomm, *ecommerge;
+  struct lcommunity *lcomm, *lcommerge;
   struct attr_extra *ae;
   struct attr attr = { 0 };
 
@@ -711,6 +713,8 @@  bgp_info_mpath_aggregate_update (struct bgp_info *new_best,
   ae = attr.extra;
   ecomm = (ae && ae->ecommunity) ? ecommunity_dup (ae->ecommunity) : NULL;
 
+  lcomm = (ae && ae->lcommunity) ? lcommunity_dup (ae->lcommunity) : NULL;
+
   for (mpinfo = bgp_info_mpath_first (new_best); mpinfo;
        mpinfo = bgp_info_mpath_next (mpinfo))
     {
@@ -745,6 +749,18 @@  bgp_info_mpath_aggregate_update (struct bgp_info *new_best,
           else
             ecomm = ecommunity_dup (ae->ecommunity);
         }
+
+      if (ae && ae->lcommunity)
+        {
+          if (lcomm)
+            {
+              lcommerge = lcommunity_merge (lcomm, ae->lcommunity);
+              lcomm = lcommunity_uniq_sort (lcommerge);
+              lcommunity_free (&lcommerge);
+            }
+          else
+            lcomm = lcommunity_dup (ae->lcommunity);
+        }
     }
 
   attr.aspath = aspath;
diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c
index 7b8b657..8920ed6 100644
--- a/bgpd/bgp_open.c
+++ b/bgpd/bgp_open.c
@@ -144,6 +144,8 @@  bgp_afi_safi_valid_indices (afi_t afi, safi_t *safi)
 	  return 1;
 	}
       break;
+    case AFI_ETHER:
+      break;
     }
 
   zlog_debug ("unknown afi/safi (%u/%u)", afi, *safi);
diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c
index f42e544..aad5270 100644
--- a/bgpd/bgp_packet.c
+++ b/bgpd/bgp_packet.c
@@ -45,6 +45,7 @@  Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 #include "bgpd/bgp_aspath.h"
 #include "bgpd/bgp_community.h"
 #include "bgpd/bgp_ecommunity.h"
+#include "bgpd/bgp_lcommunity.h"
 #include "bgpd/bgp_network.h"
 #include "bgpd/bgp_mplsvpn.h"
 #include "bgpd/bgp_encap.h"
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index 4cb6c14..c8c0265 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -1,5 +1,6 @@ 
 /* BGP routing information
    Copyright (C) 1996, 97, 98, 99 Kunihiro Ishiguro
+   Copyright (C) 2016 Job Snijders <job@instituut.net>
 
 This file is part of GNU Zebra.
 
@@ -44,6 +45,7 @@  Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 #include "bgpd/bgp_regex.h"
 #include "bgpd/bgp_community.h"
 #include "bgpd/bgp_ecommunity.h"
+#include "bgpd/bgp_lcommunity.h"
 #include "bgpd/bgp_clist.h"
 #include "bgpd/bgp_packet.h"
 #include "bgpd/bgp_filter.h"
@@ -6428,8 +6430,13 @@  route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p,
       if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES))
 	vty_out (vty, "      Extended Community: %s%s", 
 	         attr->extra->ecommunity->str, VTY_NEWLINE);
-	  
-      /* Line 6 display Originator, Cluster-id */
+
+      /* Line 6 display Large community */
+      if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES))
+	vty_out (vty, "      Large Community: %s%s",
+	         attr->extra->lcommunity->str, VTY_NEWLINE);
+
+      /* Line 7 display Originator, Cluster-id */
       if ((attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID)) ||
 	  (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST)))
 	{
@@ -6452,7 +6459,7 @@  route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p,
       if (binfo->extra && binfo->extra->damp_info)
 	bgp_damp_info_vty (vty, binfo);
 
-      /* Line 7 display Uptime */
+      /* Line 8 display Uptime */
 #ifdef HAVE_CLOCK_MONOTONIC
       tbuf = time(NULL) - (bgp_clock() - binfo->uptime);
       vty_out (vty, "      Last update: %s", ctime(&tbuf));
@@ -6486,6 +6493,9 @@  enum bgp_show_type
   bgp_show_type_community_exact,
   bgp_show_type_community_list,
   bgp_show_type_community_list_exact,
+  bgp_show_type_lcommunity_all,
+  bgp_show_type_lcommunity,
+  bgp_show_type_lcommunity_list,
   bgp_show_type_flap_statistics,
   bgp_show_type_flap_address,
   bgp_show_type_flap_prefix,
@@ -6648,6 +6658,32 @@  bgp_show_table (struct vty *vty, struct bgp_table *table, struct in_addr *router
 		if (! community_list_exact_match (ri->attr->community, list))
 		  continue;
 	      }
+	    if (type == bgp_show_type_community_all)
+	      {
+		if (! ri->attr->community)
+		  continue;
+	      }
+	    if (type == bgp_show_type_lcommunity)
+	      {
+		struct lcommunity *lcom = output_arg;
+
+		if (! ri->attr->extra || ! ri->attr->extra->lcommunity ||
+		    ! lcommunity_match (ri->attr->extra->lcommunity, lcom))
+		  continue;
+	      }
+	    if (type == bgp_show_type_lcommunity_list)
+	      {
+		struct community_list *list = output_arg;
+
+		if (! ri->attr->extra ||
+		    ! lcommunity_list_match (ri->attr->extra->lcommunity, list))
+		  continue;
+	      }
+	    if (type == bgp_show_type_lcommunity_all)
+	      {
+		if (! ri->attr->extra || ! ri->attr->extra->lcommunity)
+		  continue;
+	      }
 	    if (type == bgp_show_type_flap_address
 		|| type == bgp_show_type_flap_prefix)
 	      {
@@ -9163,6 +9199,84 @@  DEFUN (show_ipv6_mbgp_community_all,
 		   bgp_show_type_community_all, NULL);
 }
 
+/* large-community */
+DEFUN (show_ip_bgp_lcommunity_all,
+       show_ip_bgp_lcommunity_all_cmd,
+       "show ip bgp large-community",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Display routes matching the large-communities\n")
+{
+  return bgp_show (vty, NULL, AFI_IP, SAFI_UNICAST,
+		     bgp_show_type_lcommunity_all, NULL);
+}
+
+DEFUN (show_ip_bgp_ipv4_lcommunity_all,
+       show_ip_bgp_ipv4_lcommunity_all_cmd,
+       "show ip bgp ipv4 (unicast|multicast) large-community",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Display routes matching the large-communities\n")
+{
+  if (strncmp (argv[0], "m", 1) == 0)
+    return bgp_show (vty, NULL, AFI_IP, SAFI_MULTICAST,
+		     bgp_show_type_lcommunity_all, NULL);
+
+  return bgp_show (vty, NULL, AFI_IP, SAFI_UNICAST,
+		   bgp_show_type_lcommunity_all, NULL);
+}
+
+DEFUN (show_bgp_lcommunity_all,
+       show_bgp_lcommunity_all_cmd,
+       "show bgp large-community",
+       SHOW_STR
+       BGP_STR
+       "Display routes matching the large-communities\n")
+{
+  return bgp_show (vty, NULL, AFI_IP6, SAFI_UNICAST,
+		   bgp_show_type_lcommunity_all, NULL);
+}
+
+ALIAS (show_bgp_lcommunity_all,
+       show_bgp_ipv6_lcommunity_all_cmd,
+       "show bgp ipv6 large-community",
+       SHOW_STR
+       BGP_STR
+       "Address family\n"
+       "Display routes matching the large-communities\n")
+
+/* old command */
+DEFUN (show_ipv6_bgp_lcommunity_all,
+       show_ipv6_bgp_lcommunity_all_cmd,
+       "show ipv6 bgp large-community",
+       SHOW_STR
+       IPV6_STR
+       BGP_STR
+       "Display routes matching the large-communities\n")
+{
+  return bgp_show (vty, NULL, AFI_IP6, SAFI_UNICAST,
+		   bgp_show_type_lcommunity_all, NULL);
+}
+
+/* old command */
+DEFUN (show_ipv6_mbgp_lcommunity_all,
+       show_ipv6_mbgp_lcommunity_all_cmd,
+       "show ipv6 mbgp large-community",
+       SHOW_STR
+       IPV6_STR
+       MBGP_STR
+       "Display routes matching the large-communities\n")
+{
+  return bgp_show (vty, NULL, AFI_IP6, SAFI_MULTICAST,
+		   bgp_show_type_lcommunity_all, NULL);
+}
+
+
 DEFUN (show_bgp_ipv4_route_map, 
        show_bgp_ipv4_route_map_cmd,
        "show bgp ipv4 route-map WORD",
@@ -11396,6 +11510,795 @@  DEFUN (show_bgp_ipv6_safi_community_list_exact,
   return bgp_show_community_list (vty, argv[1], 1, AFI_IP6, safi);
 }
 
+/*
+ * Large Community show commands.
+ */
+
+DEFUN (show_bgp_afi_lcommunity_all,
+       show_bgp_afi_lcommunity_all_cmd,
+       "show bgp (ipv4|ipv6) large-community",
+       SHOW_STR
+       BGP_STR
+       "Address family\n"
+       "Address family\n"
+       "Display routes matching the large-communities\n")
+{
+  afi_t		afi;
+  safi_t	safi = SAFI_UNICAST;
+
+  if (bgp_parse_afi(argv[0], &afi)) {
+    vty_out (vty, "Error: Bad AFI: %s%s", argv[0], VTY_NEWLINE);
+    return CMD_WARNING;
+  }
+  return bgp_show (vty, NULL, afi, safi, bgp_show_type_lcommunity_all, NULL);
+}
+
+static int
+bgp_show_lcommunity (struct vty *vty, const char *view_name, int argc,
+		     const char **argv, afi_t afi, safi_t safi)
+{
+  struct lcommunity *lcom;
+  struct buffer *b;
+  struct bgp *bgp;
+  int i;
+  char *str;
+  int first = 0;
+
+  /* BGP structure lookup */
+  if (view_name)
+    {
+      bgp = bgp_lookup_by_name (view_name);
+      if (bgp == NULL)
+	{
+	  vty_out (vty, "Can't find BGP view %s%s", view_name, VTY_NEWLINE);
+	  return CMD_WARNING;
+	}
+    }
+  else
+    {
+      bgp = bgp_get_default ();
+      if (bgp == NULL)
+	{
+	  vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE);
+	  return CMD_WARNING;
+	}
+    }
+
+  b = buffer_new (1024);
+  for (i = 0; i < argc; i++)
+    {
+      if (first)
+        buffer_putc (b, ' ');
+      else
+	{
+	  if ((strcmp (argv[i], "unicast") == 0) || (strcmp (argv[i], "multicast") == 0))
+	    continue;
+	  first = 1;
+	}
+
+      buffer_putstr (b, argv[i]);
+    }
+  buffer_putc (b, '\0');
+
+  str = buffer_getstr (b);
+  buffer_free (b);
+
+  lcom = lcommunity_str2com (str);
+  XFREE (MTYPE_TMP, str);
+  if (! lcom)
+    {
+      vty_out (vty, "%% Large-community malformed: %s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  return bgp_show (vty, bgp, afi, safi, bgp_show_type_lcommunity, lcom);
+}
+
+DEFUN (show_ip_bgp_lcommunity,
+       show_ip_bgp_lcommunity_cmd,
+       "show ip bgp large-community (AA:BB:CC)",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Display routes matching the large-communities\n"
+       "large-community number\n")
+{
+  return bgp_show_lcommunity (vty, NULL, argc, argv, AFI_IP, SAFI_UNICAST);
+}
+
+ALIAS (show_ip_bgp_lcommunity,
+       show_ip_bgp_lcommunity2_cmd,
+       "show ip bgp large-community (AA:BB:CC) (AA:BB:CC)",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Display routes matching the large-communities\n"
+       "large-community number\n"
+       "large-community number\n")
+
+ALIAS (show_ip_bgp_lcommunity,
+       show_ip_bgp_lcommunity3_cmd,
+       "show ip bgp large-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Display routes matching the large-communities\n"
+       "largecommunity number\n"
+       "largecommunity number\n"
+       "largecommunity number\n")
+
+ALIAS (show_ip_bgp_lcommunity,
+       show_ip_bgp_lcommunity4_cmd,
+       "show ip bgp large-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Display routes matching the large-communities\n"
+       "large-community number\n"
+       "large-community number\n"
+       "large-community number\n"
+       "large-community number\n")
+
+DEFUN (show_ip_bgp_ipv4_lcommunity,
+       show_ip_bgp_ipv4_lcommunity_cmd,
+       "show ip bgp ipv4 (unicast|multicast) large-community (AA:BB:CC)",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Display routes matching the large-communities\n"
+       "large-community number\n")
+{
+  if (strncmp (argv[0], "m", 1) == 0)
+    return bgp_show_lcommunity (vty, NULL, argc, argv, AFI_IP, SAFI_MULTICAST);
+
+  return bgp_show_lcommunity (vty, NULL, argc, argv, AFI_IP, SAFI_UNICAST);
+}
+
+ALIAS (show_ip_bgp_ipv4_lcommunity,
+       show_ip_bgp_ipv4_lcommunity2_cmd,
+       "show ip bgp ipv4 (unicast|multicast) large-community (AA:BB:CC) (AA:BB:CC)",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Display routes matching the large-communities\n"
+       "large-community number\n"
+       "large-community number\n")
+
+ALIAS (show_ip_bgp_ipv4_lcommunity,
+       show_ip_bgp_ipv4_lcommunity3_cmd,
+       "show ip bgp ipv4 (unicast|multicast) large-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Display routes matching the large-communities\n"
+       "large-community number\n"
+       "large-community number\n"
+       "large-community number\n")
+
+ALIAS (show_ip_bgp_ipv4_lcommunity,
+       show_ip_bgp_ipv4_lcommunity4_cmd,
+       "show ip bgp ipv4 (unicast|multicast) large-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Display routes matching the large-communities\n"
+       "large-community number\n"
+       "large-community number\n"
+       "large-community number\n"
+       "large-community number\n")
+
+DEFUN (show_bgp_lcommunity,
+       show_bgp_lcommunity_cmd,
+       "show bgp large-community (AA:BB:CC)",
+       SHOW_STR
+       BGP_STR
+       "Display routes matching the large-communities\n"
+       "large-community number\n")
+{
+  return bgp_show_lcommunity (vty, NULL, argc, argv, AFI_IP6, SAFI_UNICAST);
+}
+
+ALIAS (show_bgp_lcommunity,
+       show_bgp_ipv6_lcommunity_cmd,
+       "show bgp ipv6 large-community (AA:BB:CC)",
+       SHOW_STR
+       BGP_STR
+       "Address family\n"
+       "Display routes matching the large-communities\n"
+       "large-community number\n")
+
+ALIAS (show_bgp_lcommunity,
+       show_bgp_lcommunity2_cmd,
+       "show bgp large-community (AA:BB:CC) (AA:BB:CC)",
+       SHOW_STR
+       BGP_STR
+       "Display routes matching the large-communities\n"
+       "large-community number\n"
+       "large-community number\n")
+
+ALIAS (show_bgp_lcommunity,
+       show_bgp_ipv6_lcommunity2_cmd,
+       "show bgp ipv6 large-community (AA:BB:CC) (AA:BB:CC)",
+       SHOW_STR
+       BGP_STR
+       "Address family\n"
+       "Display routes matching the large-communities\n"
+       "large-community number\n"
+       "large-community number\n")
+
+ALIAS (show_bgp_lcommunity,
+       show_bgp_lcommunity3_cmd,
+       "show bgp large-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)",
+       SHOW_STR
+       BGP_STR
+       "Display routes matching the large-communities\n"
+       "large-community number\n"
+       "large-community number\n"
+       "large-community number\n")
+
+ALIAS (show_bgp_lcommunity,
+       show_bgp_ipv6_lcommunity3_cmd,
+       "show bgp ipv6 large-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)",
+       SHOW_STR
+       BGP_STR
+       "Address family\n"
+       "Display routes matching the large-communities\n"
+       "large-community number\n"
+       "large-community number\n"
+       "large-community number\n")
+
+ALIAS (show_bgp_lcommunity,
+       show_bgp_lcommunity4_cmd,
+       "show bgp large-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)",
+       SHOW_STR
+       BGP_STR
+       "Display routes matching the large-communities\n"
+       "large-community number\n"
+       "large-community number\n"
+       "large-community number\n"
+       "large-community number\n")
+
+ALIAS (show_bgp_lcommunity,
+       show_bgp_ipv6_lcommunity4_cmd,
+       "show bgp ipv6 large-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)",
+       SHOW_STR
+       BGP_STR
+       "Address family\n"
+       "Display routes matching the large-communities\n"
+       "large-community number\n"
+       "large-community number\n"
+       "large-community number\n"
+       "large-community number\n")
+
+/* old command */
+DEFUN (show_ipv6_bgp_lcommunity,
+       show_ipv6_bgp_lcommunity_cmd,
+       "show ipv6 bgp large-community (AA:BB:CC)",
+       SHOW_STR
+       IPV6_STR
+       BGP_STR
+       "Display routes matching the large-communities\n"
+       "large-community number\n")
+{
+  return bgp_show_lcommunity (vty, NULL, argc, argv, AFI_IP6, SAFI_UNICAST);
+}
+
+/* old command */
+ALIAS (show_ipv6_bgp_lcommunity,
+       show_ipv6_bgp_lcommunity2_cmd,
+       "show ipv6 bgp large-community (AA:BB:CC) (AA:BB:CC)",
+       SHOW_STR
+       IPV6_STR
+       BGP_STR
+       "Display routes matching the large-communities\n"
+       "large-community number\n"
+       "large-community number\n")
+
+/* old command */
+ALIAS (show_ipv6_bgp_lcommunity,
+       show_ipv6_bgp_lcommunity3_cmd,
+       "show ipv6 bgp large-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)",
+       SHOW_STR
+       IPV6_STR
+       BGP_STR
+       "Display routes matching the large-communities\n"
+       "large-community number\n"
+       "large-community number\n"
+       "large-community number\n")
+
+/* old command */
+ALIAS (show_ipv6_bgp_lcommunity,
+       show_ipv6_bgp_lcommunity4_cmd,
+       "show ipv6 bgp large-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)",
+       SHOW_STR
+       IPV6_STR
+       BGP_STR
+       "Display routes matching the large-communities\n"
+       "large-community number\n"
+       "large-community number\n"
+       "large-community number\n"
+       "large-community number\n")
+
+/* old command */
+DEFUN (show_ipv6_mbgp_lcommunity,
+       show_ipv6_mbgp_lcommunity_cmd,
+       "show ipv6 mbgp large-community (AA:BB:CC)",
+       SHOW_STR
+       IPV6_STR
+       MBGP_STR
+       "Display routes matching the large-communities\n"
+       "large-community number\n")
+{
+  return bgp_show_lcommunity (vty, NULL, argc, argv, AFI_IP6, SAFI_MULTICAST);
+}
+
+/* old command */
+ALIAS (show_ipv6_mbgp_lcommunity,
+       show_ipv6_mbgp_lcommunity2_cmd,
+       "show ipv6 mbgp large-community (AA:BB:CC) (AA:BB:CC)",
+       SHOW_STR
+       IPV6_STR
+       MBGP_STR
+       "Display routes matching the large-communities\n"
+       "large-community number\n"
+       "large-community number\n")
+
+/* old command */
+ALIAS (show_ipv6_mbgp_lcommunity,
+       show_ipv6_mbgp_lcommunity3_cmd,
+       "show ipv6 mbgp large-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)",
+       SHOW_STR
+       IPV6_STR
+       MBGP_STR
+       "Display routes matching the large-communities\n"
+       "large-community number\n"
+       "large-community number\n"
+       "large-community number\n")
+
+/* old command */
+ALIAS (show_ipv6_mbgp_lcommunity,
+       show_ipv6_mbgp_lcommunity4_cmd,
+       "show ipv6 mbgp laarge-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)",
+       SHOW_STR
+       IPV6_STR
+       MBGP_STR
+       "Display routes matching the large-communities\n"
+       "large-community number\n"
+       "large-community number\n"
+       "large-community number\n"
+       "large-community number\n")
+
+DEFUN (show_bgp_ipv4_lcommunity,
+       show_bgp_ipv4_lcommunity_cmd,
+       "show bgp ipv4 large-community (AA:BB:CC)",
+       SHOW_STR
+       BGP_STR
+       IP_STR
+       "Display routes matching the large-communities\n"
+       "large-community number\n")
+{
+  return bgp_show_lcommunity (vty, NULL, argc, argv, AFI_IP, SAFI_UNICAST);
+}
+
+ALIAS (show_bgp_ipv4_lcommunity,
+       show_bgp_ipv4_lcommunity2_cmd,
+       "show bgp ipv4 large-community (AA:BB:CC) (AA:BB:CC)",
+       SHOW_STR
+       BGP_STR
+       IP_STR
+       "Display routes matching the large-communities\n"
+       "large-community number\n"
+       "large-community number\n")
+
+ALIAS (show_bgp_ipv4_lcommunity,
+       show_bgp_ipv4_lcommunity3_cmd,
+       "show bgp ipv4 large-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)",
+       SHOW_STR
+       BGP_STR
+       IP_STR
+       "Display routes matching the large-communities\n"
+       "large-community number\n"
+       "large-community number\n"
+       "large-community number\n")
+
+ALIAS (show_bgp_ipv4_lcommunity,
+       show_bgp_ipv4_lcommunity4_cmd,
+       "show bgp ipv4 large-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)",
+       SHOW_STR
+       BGP_STR
+       IP_STR
+       "Display routes matching the large-communities\n"
+       "large-community number\n"
+       "large-community number\n"
+       "large-community number\n"
+       "large-community number\n")
+
+DEFUN (show_bgp_ipv4_safi_lcommunity,
+       show_bgp_ipv4_safi_lcommunity_cmd,
+       "show bgp ipv4 (unicast|multicast) large-community (AA:BB:CC)",
+       SHOW_STR
+       BGP_STR
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Display routes matching the large-communities\n"
+       "large-community number\n")
+{
+  if (strncmp (argv[0], "m", 1) == 0)
+    return bgp_show_lcommunity (vty, NULL, argc, argv, AFI_IP, SAFI_MULTICAST);
+
+  return bgp_show_lcommunity (vty, NULL, argc, argv, AFI_IP, SAFI_UNICAST);
+}
+
+ALIAS (show_bgp_ipv4_safi_lcommunity,
+       show_bgp_ipv4_safi_lcommunity2_cmd,
+       "show bgp ipv4 (unicast|multicast) large-community (AA:BB:CC) (AA:BB:CC)",
+       SHOW_STR
+       BGP_STR
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Display routes matching the large-communities\n"
+       "large-community number\n"
+       "large-community number\n")
+
+ALIAS (show_bgp_ipv4_safi_lcommunity,
+       show_bgp_ipv4_safi_lcommunity3_cmd,
+       "show bgp ipv4 (unicast|multicast) large-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)",
+       SHOW_STR
+       BGP_STR
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Display routes matching the large-communities\n"
+       "large-community number\n"
+       "large-community number\n"
+       "large-community number\n")
+
+ALIAS (show_bgp_ipv4_safi_lcommunity,
+       show_bgp_ipv4_safi_lcommunity4_cmd,
+       "show bgp ipv4 (unicast|multicast) large-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)",
+       SHOW_STR
+       BGP_STR
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Display routes matching the large-communities\n"
+       "large-community number\n"
+       "large-community number\n"
+       "large-community number\n"
+       "large-community number\n")
+
+DEFUN (show_bgp_view_afi_safi_lcommunity_all,
+       show_bgp_view_afi_safi_lcommunity_all_cmd,
+       "show bgp view WORD (ipv4|ipv6) (unicast|multicast) large-community",
+       SHOW_STR
+       BGP_STR
+       "BGP view\n"
+       "View name\n"
+       "Address family\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Display routes matching the large-communities\n")
+{
+  int afi;
+  int safi;
+  struct bgp *bgp;
+
+  /* BGP structure lookup. */
+  bgp = bgp_lookup_by_name (argv[0]);
+  if (bgp == NULL)
+    {
+      vty_out (vty, "Can't find BGP view %s%s", argv[0], VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  afi = (strncmp (argv[1], "ipv6", 4) == 0) ? AFI_IP6 : AFI_IP;
+  safi = (strncmp (argv[2], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST;
+  return bgp_show (vty, bgp, afi, safi, bgp_show_type_lcommunity_all, NULL);
+}
+
+DEFUN (show_bgp_view_afi_safi_lcommunity,
+       show_bgp_view_afi_safi_lcommunity_cmd,
+       "show bgp view WORD (ipv4|ipv6) (unicast|multicast) large-community (AA:BB:CC)",
+       SHOW_STR
+       BGP_STR
+       "BGP view\n"
+       "View name\n"
+       "Address family\n"
+       "Address family\n"
+       "Address family modifier\n"
+       "Address family modifier\n"
+       "Display routes matching the large-communities\n"
+       "large-community number\n")
+{
+  int afi;
+  int safi;
+
+  afi = (strncmp (argv[1], "ipv6", 4) == 0) ? AFI_IP6 : AFI_IP;
+  safi = (strncmp (argv[2], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST;
+  return bgp_show_lcommunity (vty, argv[0], argc-3, &argv[3], afi, safi);
+}
+
+ALIAS (show_bgp_view_afi_safi_lcommunity,
+       show_bgp_view_afi_safi_lcommunity2_cmd,
+       "show bgp view WORD (ipv4|ipv6) (unicast|multicast) large-community (AA:BB:CC) (AA:BB:CC)",
+       SHOW_STR
+       BGP_STR
+       "BGP view\n"
+       "View name\n"
+       "Address family\n"
+       "Address family\n"
+       "Address family modifier\n"
+       "Address family modifier\n"
+       "Display routes matching the large-communities\n"
+       "large-community number\n"
+       "large-community number\n")
+
+ALIAS (show_bgp_view_afi_safi_lcommunity,
+       show_bgp_view_afi_safi_lcommunity3_cmd,
+       "show bgp view WORD (ipv4|ipv6) (unicast|multicast) large-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)",
+       SHOW_STR
+       BGP_STR
+       "BGP view\n"
+       "View name\n"
+       "Address family\n"
+       "Address family\n"
+       "Address family modifier\n"
+       "Address family modifier\n"
+       "Display routes matching the large-communities\n"
+       "large-community number\n"
+       "large-community number\n"
+       "large-community number\n")
+
+ALIAS (show_bgp_view_afi_safi_lcommunity,
+       show_bgp_view_afi_safi_lcommunity4_cmd,
+       "show bgp view WORD (ipv4|ipv6) (unicast|multicast) large-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)",
+       SHOW_STR
+       BGP_STR
+       "BGP view\n"
+       "View name\n"
+       "Address family\n"
+       "Address family\n"
+       "Address family modifier\n"
+       "Address family modifier\n"
+       "Display routes matching the large-communities\n"
+       "large-community number\n"
+       "large-community number\n"
+       "large-community number\n"
+       "large-community number\n")
+
+DEFUN (show_bgp_ipv6_safi_lcommunity,
+       show_bgp_ipv6_safi_lcommunity_cmd,
+       "show bgp ipv6 (encap|multicast|unicast|vpn) large-community AA:BB:CC",
+       SHOW_STR
+       BGP_STR
+       "Address family\n"
+       "Address family modifier\n"
+       "Address family modifier\n"
+       "Address family modifier\n"
+       "Address family modifier\n"
+       "Display routes matching the large-communities\n"
+       "large-community number\n")
+{
+  safi_t	safi;
+
+  if (bgp_parse_safi(argv[0], &safi)) {
+    vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE);
+    return CMD_WARNING;
+  }
+  return bgp_show_lcommunity (vty, NULL, argc-1, argv+1, AFI_IP6, safi);
+}
+
+ALIAS (show_bgp_ipv6_safi_lcommunity,
+       show_bgp_ipv6_safi_lcommunity2_cmd,
+       "show bgp ipv6 (encap|multicast|unicast|vpn) large-community (AA:BB:CC) (AA:BB:CC)",
+       SHOW_STR
+       BGP_STR
+       "Address family\n"
+       "Address family modifier\n"
+       "Address family modifier\n"
+       "Address family modifier\n"
+       "Address family modifier\n"
+       "Display routes matching the large-communities\n"
+       "large-community number\n"
+       "large-community number\n")
+
+ALIAS (show_bgp_ipv6_safi_lcommunity,
+       show_bgp_ipv6_safi_lcommunity3_cmd,
+       "show bgp ipv6 (encap|multicast|unicast|vpn) large-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)",
+       SHOW_STR
+       BGP_STR
+       "Address family\n"
+       "Address family modifier\n"
+       "Address family modifier\n"
+       "Address family modifier\n"
+       "Address family modifier\n"
+       "Display routes matching the large-communities\n"
+       "large-community number\n"
+       "large-community number\n"
+       "large-community number\n")
+
+ALIAS (show_bgp_ipv6_safi_lcommunity,
+       show_bgp_ipv6_safi_lcommunity4_cmd,
+       "show bgp ipv6 (encap|multicast|unicast|vpn) large-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)",
+       SHOW_STR
+       BGP_STR
+       "Address family\n"
+       "Address family modifier\n"
+       "Address family modifier\n"
+       "Address family modifier\n"
+       "Address family modifier\n"
+       "Display routes matching the large-communities\n"
+       "large-community number\n"
+       "large-community number\n"
+       "large-community number\n"
+       "large-community number\n")
+
+static int
+bgp_show_lcommunity_list (struct vty *vty, const char *lcom,
+			  afi_t afi, safi_t safi)
+{
+  struct community_list *list;
+
+  list = community_list_lookup (bgp_clist, lcom, LARGE_COMMUNITY_LIST_MASTER);
+  if (list == NULL)
+    {
+      vty_out (vty, "%% %s is not a valid large-community-list name%s", lcom,
+	       VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  return bgp_show (vty, NULL, afi, safi, bgp_show_type_lcommunity_list, list);
+}
+
+DEFUN (show_ip_bgp_lcommunity_list,
+       show_ip_bgp_lcommunity_list_cmd,
+       "show ip bgp large-community-list (<1-500>|WORD)",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Display routes matching the large-community-list\n"
+       "large-community-list number\n"
+       "large-community-list name\n")
+{
+  return bgp_show_lcommunity_list (vty, argv[0], AFI_IP, SAFI_UNICAST);
+}
+
+DEFUN (show_ip_bgp_ipv4_lcommunity_list,
+       show_ip_bgp_ipv4_lcommunity_list_cmd,
+       "show ip bgp ipv4 (unicast|multicast) large-community-list (<1-500>|WORD)",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Display routes matching the large-community-list\n"
+       "large-community-list number\n"
+       "large-community-list name\n")
+{
+  if (strncmp (argv[0], "m", 1) == 0)
+    return bgp_show_lcommunity_list (vty, argv[1], AFI_IP, SAFI_MULTICAST);
+
+  return bgp_show_lcommunity_list (vty, argv[1], AFI_IP, SAFI_UNICAST);
+}
+
+DEFUN (show_bgp_lcommunity_list,
+       show_bgp_lcommunity_list_cmd,
+       "show bgp large-community-list (<1-500>|WORD)",
+       SHOW_STR
+       BGP_STR
+       "Display routes matching the large-community-list\n"
+       "large-community-list number\n"
+       "large-community-list name\n")
+{
+  return bgp_show_lcommunity_list (vty, argv[0], AFI_IP6, SAFI_UNICAST);
+}
+
+ALIAS (show_bgp_lcommunity_list,
+       show_bgp_ipv6_lcommunity_list_cmd,
+       "show bgp ipv6 large-community-list (<1-500>|WORD)",
+       SHOW_STR
+       BGP_STR
+       "Address family\n"
+       "Display routes matching the large-community-list\n"
+       "large-community-list number\n"
+       "large-community-list name\n")
+
+/* old command */
+DEFUN (show_ipv6_bgp_lcommunity_list,
+       show_ipv6_bgp_lcommunity_list_cmd,
+       "show ipv6 bgp large-community-list WORD",
+       SHOW_STR
+       IPV6_STR
+       BGP_STR
+       "Display routes matching the large-community-list\n"
+       "large-community-list name\n")
+{
+  return bgp_show_lcommunity_list (vty, argv[0], AFI_IP6, SAFI_UNICAST);
+}
+
+/* old command */
+DEFUN (show_ipv6_mbgp_lcommunity_list,
+       show_ipv6_mbgp_lcommunity_list_cmd,
+       "show ipv6 mbgp large-community-list WORD",
+       SHOW_STR
+       IPV6_STR
+       MBGP_STR
+       "Display routes matching the large-community-list\n"
+       "large-community-list name\n")
+{
+  return bgp_show_lcommunity_list (vty, argv[0], AFI_IP6, SAFI_MULTICAST);
+}
+
+DEFUN (show_bgp_ipv4_lcommunity_list,
+       show_bgp_ipv4_lcommunity_list_cmd,
+       "show bgp ipv4 large-community-list (<1-500>|WORD)",
+       SHOW_STR
+       BGP_STR
+       IP_STR
+       "Display routes matching the large-community-list\n"
+       "large-community-list number\n"
+       "large-community-list name\n")
+{
+  return bgp_show_lcommunity_list (vty, argv[0], AFI_IP, SAFI_UNICAST);
+}
+
+DEFUN (show_bgp_ipv4_safi_lcommunity_list,
+       show_bgp_ipv4_safi_lcommunity_list_cmd,
+       "show bgp ipv4 (unicast|multicast) large-community-list (<1-500>|WORD)",
+       SHOW_STR
+       BGP_STR
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Display routes matching the large-community-list\n"
+       "large-community-list number\n"
+       "large-community-list name\n")
+{
+  if (strncmp (argv[0], "m", 1) == 0)
+    return bgp_show_lcommunity_list (vty, argv[1], AFI_IP, SAFI_MULTICAST);
+
+  return bgp_show_lcommunity_list (vty, argv[1], AFI_IP, SAFI_UNICAST);
+}
+
+DEFUN (show_bgp_ipv6_safi_lcommunity_list,
+       show_bgp_ipv6_safi_lcommunity_list_cmd,
+       "show bgp ipv6 (encap|multicast|unicast|vpn) large-community-list (<1-500>|WORD)",
+       SHOW_STR
+       BGP_STR
+       "Address family\n"
+       "Address family modifier\n"
+       "Address family modifier\n"
+       "Address family modifier\n"
+       "Address family modifier\n"
+       "Display routes matching the large-community-list\n"
+       "large-community-list number\n"
+       "large-community-list name\n")
+{
+  safi_t	safi;
+
+  if (bgp_parse_safi(argv[0], &safi)) {
+    vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE);
+    return CMD_WARNING;
+  }
+  return bgp_show_lcommunity_list (vty, argv[1], AFI_IP6, safi);
+}
+
 static int
 bgp_show_prefix_longer (struct vty *vty, const char *prefix, afi_t afi,
 			safi_t safi, enum bgp_show_type type)
@@ -16407,6 +17310,24 @@  bgp_route_init (void)
   install_element (VIEW_NODE, &show_bgp_ipv4_safi_community_list_cmd);
   install_element (VIEW_NODE, &show_bgp_ipv4_community_list_exact_cmd);
   install_element (VIEW_NODE, &show_bgp_ipv4_safi_community_list_exact_cmd);
+
+  /* large-communities */
+  install_element (VIEW_NODE, &show_bgp_ipv4_lcommunity_cmd);
+  install_element (VIEW_NODE, &show_bgp_ipv4_lcommunity2_cmd);
+  install_element (VIEW_NODE, &show_bgp_ipv4_lcommunity3_cmd);
+  install_element (VIEW_NODE, &show_bgp_ipv4_lcommunity4_cmd);
+  install_element (VIEW_NODE, &show_bgp_ipv4_safi_lcommunity_cmd);
+  install_element (VIEW_NODE, &show_bgp_ipv4_safi_lcommunity2_cmd);
+  install_element (VIEW_NODE, &show_bgp_ipv4_safi_lcommunity3_cmd);
+  install_element (VIEW_NODE, &show_bgp_ipv4_safi_lcommunity4_cmd);
+  install_element (VIEW_NODE, &show_bgp_view_afi_safi_lcommunity_all_cmd);
+  install_element (VIEW_NODE, &show_bgp_view_afi_safi_lcommunity_cmd);
+  install_element (VIEW_NODE, &show_bgp_view_afi_safi_lcommunity2_cmd);
+  install_element (VIEW_NODE, &show_bgp_view_afi_safi_lcommunity3_cmd);
+  install_element (VIEW_NODE, &show_bgp_view_afi_safi_lcommunity4_cmd);
+  install_element (VIEW_NODE, &show_bgp_ipv4_lcommunity_list_cmd);
+  install_element (VIEW_NODE, &show_bgp_ipv4_safi_lcommunity_list_cmd);
+
   install_element (VIEW_NODE, &show_bgp_ipv4_prefix_longer_cmd);
   install_element (VIEW_NODE, &show_bgp_ipv4_safi_prefix_longer_cmd);
   install_element (VIEW_NODE, &show_bgp_ipv6_safi_prefix_longer_cmd);
@@ -16504,6 +17425,22 @@  bgp_route_init (void)
   install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_community2_exact_cmd);
   install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_community3_exact_cmd);
   install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_community4_exact_cmd);
+
+  /* large-community */
+  install_element (RESTRICTED_NODE, &show_bgp_ipv4_lcommunity_cmd);
+  install_element (RESTRICTED_NODE, &show_bgp_ipv4_lcommunity2_cmd);
+  install_element (RESTRICTED_NODE, &show_bgp_ipv4_lcommunity3_cmd);
+  install_element (RESTRICTED_NODE, &show_bgp_ipv4_lcommunity4_cmd);
+  install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_lcommunity_cmd);
+  install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_lcommunity2_cmd);
+  install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_lcommunity3_cmd);
+  install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_lcommunity4_cmd);
+  install_element (RESTRICTED_NODE, &show_bgp_view_afi_safi_lcommunity_all_cmd);
+  install_element (RESTRICTED_NODE, &show_bgp_view_afi_safi_lcommunity_cmd);
+  install_element (RESTRICTED_NODE, &show_bgp_view_afi_safi_lcommunity2_cmd);
+  install_element (RESTRICTED_NODE, &show_bgp_view_afi_safi_lcommunity3_cmd);
+  install_element (RESTRICTED_NODE, &show_bgp_view_afi_safi_lcommunity4_cmd);
+
   install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_rsclient_route_cmd);
   install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_rsclient_prefix_cmd);
   install_element (RESTRICTED_NODE, &show_bgp_view_ipv4_safi_rsclient_route_cmd);
@@ -16512,6 +17449,7 @@  bgp_route_init (void)
   /* BGP dampening clear commands */
   install_element (ENABLE_NODE, &clear_ip_bgp_dampening_cmd);
   install_element (ENABLE_NODE, &clear_ip_bgp_dampening_prefix_cmd);
+
   install_element (ENABLE_NODE, &clear_ip_bgp_dampening_address_cmd);
   install_element (ENABLE_NODE, &clear_ip_bgp_dampening_address_mask_cmd);
 
@@ -16556,6 +17494,14 @@  bgp_route_init (void)
   install_element (VIEW_NODE, &show_bgp_ipv6_safi_community3_exact_cmd);
   install_element (VIEW_NODE, &show_bgp_ipv6_safi_community4_exact_cmd);
   install_element (VIEW_NODE, &show_bgp_community_list_cmd);
+
+  /* large-community */
+  install_element (VIEW_NODE, &show_bgp_ipv6_safi_lcommunity_cmd);
+  install_element (VIEW_NODE, &show_bgp_ipv6_safi_lcommunity2_cmd);
+  install_element (VIEW_NODE, &show_bgp_ipv6_safi_lcommunity3_cmd);
+  install_element (VIEW_NODE, &show_bgp_ipv6_safi_lcommunity4_cmd);
+  install_element (VIEW_NODE, &show_bgp_lcommunity_list_cmd);
+
   install_element (VIEW_NODE, &show_bgp_ipv6_prefix_longer_cmd);
   install_element (VIEW_NODE, &show_bgp_ipv6_neighbor_advertised_route_cmd);
   install_element (VIEW_NODE, &show_bgp_ipv6_neighbor_received_routes_cmd);
@@ -16602,6 +17548,10 @@  bgp_route_init (void)
   install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_community2_exact_cmd);
   install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_community3_exact_cmd);
   install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_community4_exact_cmd);
+  install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_lcommunity_cmd);
+  install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_lcommunity2_cmd);
+  install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_lcommunity3_cmd);
+  install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_lcommunity4_cmd);
   install_element (RESTRICTED_NODE, &show_bgp_ipv6_rsclient_route_cmd);
   install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_rsclient_route_cmd);
   install_element (RESTRICTED_NODE, &show_bgp_ipv6_rsclient_prefix_cmd);
@@ -16751,6 +17701,18 @@  bgp_route_init (void)
   install_element (VIEW_NODE, &show_ip_bgp_ipv4_community_list_cmd);
   install_element (VIEW_NODE, &show_ip_bgp_community_list_exact_cmd);
   install_element (VIEW_NODE, &show_ip_bgp_ipv4_community_list_exact_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_lcommunity_all_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_ipv4_lcommunity_all_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_lcommunity_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_lcommunity2_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_lcommunity3_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_lcommunity4_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_ipv4_lcommunity_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_ipv4_lcommunity2_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_ipv4_lcommunity3_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_ipv4_lcommunity4_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_lcommunity_list_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_ipv4_lcommunity_list_cmd);
   install_element (VIEW_NODE, &show_ip_bgp_prefix_longer_cmd);
   install_element (VIEW_NODE, &show_ip_bgp_ipv4_prefix_longer_cmd);
   install_element (VIEW_NODE, &show_ip_bgp_neighbor_advertised_route_cmd);
@@ -16824,6 +17786,14 @@  bgp_route_init (void)
   install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_community2_exact_cmd);
   install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_community3_exact_cmd);
   install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_community4_exact_cmd);
+  install_element (RESTRICTED_NODE, &show_ip_bgp_lcommunity_cmd);
+  install_element (RESTRICTED_NODE, &show_ip_bgp_lcommunity2_cmd);
+  install_element (RESTRICTED_NODE, &show_ip_bgp_lcommunity3_cmd);
+  install_element (RESTRICTED_NODE, &show_ip_bgp_lcommunity4_cmd);
+  install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_lcommunity_cmd);
+  install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_lcommunity2_cmd);
+  install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_lcommunity3_cmd);
+  install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_lcommunity4_cmd);
   install_element (RESTRICTED_NODE, &show_ip_bgp_rsclient_route_cmd);
   install_element (RESTRICTED_NODE, &show_ip_bgp_rsclient_prefix_cmd);
   install_element (RESTRICTED_NODE, &show_ip_bgp_view_rsclient_route_cmd);
@@ -16860,6 +17830,13 @@  bgp_route_init (void)
   install_element (VIEW_NODE, &show_bgp_ipv6_safi_community_list_cmd);
   install_element (VIEW_NODE, &show_bgp_community_list_exact_cmd);
   install_element (VIEW_NODE, &show_bgp_ipv6_safi_community_list_exact_cmd);
+  install_element (VIEW_NODE, &show_bgp_lcommunity_all_cmd);
+  install_element (VIEW_NODE, &show_bgp_ipv6_lcommunity_all_cmd);
+  install_element (VIEW_NODE, &show_bgp_lcommunity_cmd);
+  install_element (VIEW_NODE, &show_bgp_lcommunity2_cmd);
+  install_element (VIEW_NODE, &show_bgp_lcommunity3_cmd);
+  install_element (VIEW_NODE, &show_bgp_lcommunity4_cmd);
+  install_element (VIEW_NODE, &show_bgp_ipv6_safi_lcommunity_list_cmd);
   install_element (VIEW_NODE, &show_bgp_prefix_longer_cmd);
   install_element (VIEW_NODE, &show_bgp_neighbor_advertised_route_cmd);
   install_element (VIEW_NODE, &show_bgp_neighbor_received_routes_cmd);
@@ -16895,6 +17872,10 @@  bgp_route_init (void)
   install_element (RESTRICTED_NODE, &show_bgp_community2_exact_cmd);
   install_element (RESTRICTED_NODE, &show_bgp_community3_exact_cmd);
   install_element (RESTRICTED_NODE, &show_bgp_community4_exact_cmd);
+  install_element (RESTRICTED_NODE, &show_bgp_lcommunity_cmd);
+  install_element (RESTRICTED_NODE, &show_bgp_lcommunity2_cmd);
+  install_element (RESTRICTED_NODE, &show_bgp_lcommunity3_cmd);
+  install_element (RESTRICTED_NODE, &show_bgp_lcommunity4_cmd);
   install_element (RESTRICTED_NODE, &show_bgp_view_route_cmd);
   install_element (RESTRICTED_NODE, &show_bgp_view_prefix_cmd);
   install_element (RESTRICTED_NODE, &show_bgp_view_neighbor_received_prefix_filter_cmd);
@@ -16919,6 +17900,12 @@  bgp_route_init (void)
   install_element (VIEW_NODE, &show_ipv6_bgp_community4_exact_cmd);
   install_element (VIEW_NODE, &show_ipv6_bgp_community_list_cmd);
   install_element (VIEW_NODE, &show_ipv6_bgp_community_list_exact_cmd);
+  install_element (VIEW_NODE, &show_ipv6_bgp_lcommunity_all_cmd);
+  install_element (VIEW_NODE, &show_ipv6_bgp_lcommunity_cmd);
+  install_element (VIEW_NODE, &show_ipv6_bgp_lcommunity2_cmd);
+  install_element (VIEW_NODE, &show_ipv6_bgp_lcommunity3_cmd);
+  install_element (VIEW_NODE, &show_ipv6_bgp_lcommunity4_cmd);
+  install_element (VIEW_NODE, &show_ipv6_bgp_lcommunity_list_cmd);
   install_element (VIEW_NODE, &show_ipv6_bgp_prefix_longer_cmd);
   install_element (VIEW_NODE, &show_ipv6_mbgp_cmd);
   install_element (VIEW_NODE, &show_ipv6_mbgp_route_cmd);
@@ -16937,6 +17924,12 @@  bgp_route_init (void)
   install_element (VIEW_NODE, &show_ipv6_mbgp_community4_exact_cmd);
   install_element (VIEW_NODE, &show_ipv6_mbgp_community_list_cmd);
   install_element (VIEW_NODE, &show_ipv6_mbgp_community_list_exact_cmd);
+  install_element (VIEW_NODE, &show_ipv6_mbgp_lcommunity_all_cmd);
+  install_element (VIEW_NODE, &show_ipv6_mbgp_lcommunity_cmd);
+  install_element (VIEW_NODE, &show_ipv6_mbgp_lcommunity2_cmd);
+  install_element (VIEW_NODE, &show_ipv6_mbgp_lcommunity3_cmd);
+  install_element (VIEW_NODE, &show_ipv6_mbgp_lcommunity4_cmd);
+  install_element (VIEW_NODE, &show_ipv6_mbgp_lcommunity_list_cmd);
   install_element (VIEW_NODE, &show_ipv6_mbgp_prefix_longer_cmd);
   install_element (VIEW_NODE, &ipv6_bgp_neighbor_advertised_route_cmd);
   install_element (VIEW_NODE, &ipv6_mbgp_neighbor_advertised_route_cmd);
@@ -16965,6 +17958,16 @@  bgp_route_init (void)
   install_element (VIEW_NODE, &show_bgp_ipv6_community_list_cmd);
   install_element (VIEW_NODE, &show_bgp_ipv6_community_list_exact_cmd);
 
+  install_element (VIEW_NODE, &show_bgp_ipv6_lcommunity_cmd);
+  install_element (VIEW_NODE, &show_bgp_ipv6_lcommunity2_cmd);
+  install_element (VIEW_NODE, &show_bgp_ipv6_lcommunity3_cmd);
+  install_element (VIEW_NODE, &show_bgp_ipv6_lcommunity4_cmd);
+  install_element (RESTRICTED_NODE, &show_bgp_ipv6_lcommunity_cmd);
+  install_element (RESTRICTED_NODE, &show_bgp_ipv6_lcommunity2_cmd);
+  install_element (RESTRICTED_NODE, &show_bgp_ipv6_lcommunity3_cmd);
+  install_element (RESTRICTED_NODE, &show_bgp_ipv6_lcommunity4_cmd);
+  install_element (VIEW_NODE, &show_bgp_ipv6_lcommunity_list_cmd);
+
   install_element (VIEW_NODE, &show_bgp_rsclient_route_cmd);
   install_element (VIEW_NODE, &show_bgp_rsclient_prefix_cmd);
   install_element (RESTRICTED_NODE, &show_bgp_rsclient_route_cmd);
diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c
index c66f260..8f3632a 100644
--- a/bgpd/bgp_routemap.c
+++ b/bgpd/bgp_routemap.c
@@ -51,6 +51,7 @@  Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 #include "bgpd/bgp_filter.h"
 #include "bgpd/bgp_mplsvpn.h"
 #include "bgpd/bgp_ecommunity.h"
+#include "bgpd/bgp_lcommunity.h"
 #include "bgpd/bgp_vty.h"
 
 /* Memo of route-map commands.
@@ -59,6 +60,7 @@  o Cisco route-map
 
  match as-path          :  Done
        community        :  Done
+       lcommunity       :  Done
        interface        :  Not yet
        ip address       :  Done
        ip next-hop      :  Done
@@ -78,6 +80,8 @@  o Cisco route-map
       as-path tag       :  Not yet
       automatic-tag     :  (This will not be implemented by bgpd)
       community         :  Done
+      large-community   :  Done
+      large-comm-list   :  Done
       comm-list         :  Not yet
       dampning          :  Not yet
       default           :  (This will not be implemented by bgpd)
@@ -840,21 +844,93 @@  struct route_map_rule_cmd route_match_community_cmd =
   route_match_community_free
 };
 
+/* Match function for lcommunity match. */
+static route_map_result_t
+route_match_lcommunity (void *rule, struct prefix *prefix,
+		       route_map_object_t type, void *object)
+{
+  struct community_list *list;
+  struct bgp_info *bgp_info;
+  struct rmap_community *rcom;
+
+  if (type == RMAP_BGP)
+    {
+      bgp_info = object;
+      rcom = rule;
+
+      list = community_list_lookup (bgp_clist, rcom->name,
+				    LARGE_COMMUNITY_LIST_MASTER);
+      if (! list)
+	return RMAP_NOMATCH;
+
+      if (bgp_info->attr->extra &&
+	  lcommunity_list_match (bgp_info->attr->extra->lcommunity, list))
+	return RMAP_MATCH;
+
+    }
+  return RMAP_NOMATCH;
+}
+
+/* Compile function for community match. */
+static void *
+route_match_lcommunity_compile (const char *arg)
+{
+  struct rmap_community *rcom;
+  int len;
+  char *p;
+
+  rcom = XCALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (struct rmap_community));
+
+  p = strchr (arg, ' ');
+  if (p)
+    {
+      len = p - arg;
+      rcom->name = XCALLOC (MTYPE_ROUTE_MAP_COMPILED, len + 1);
+      memcpy (rcom->name, arg, len);
+    }
+  else
+    {
+      rcom->name = XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
+      rcom->exact = 0;
+    }
+  return rcom;
+}
+
+/* Compile function for community match. */
+static void
+route_match_lcommunity_free (void *rule)
+{
+  struct rmap_community *rcom = rule;
+
+  XFREE (MTYPE_ROUTE_MAP_COMPILED, rcom->name);
+  XFREE (MTYPE_ROUTE_MAP_COMPILED, rcom);
+}
+
+/* Route map commands for community matching. */
+struct route_map_rule_cmd route_match_lcommunity_cmd =
+{
+  "large-community",
+  route_match_lcommunity,
+  route_match_lcommunity_compile,
+  route_match_lcommunity_free
+};
+
+
 /* Match function for extcommunity match. */
 static route_map_result_t
-route_match_ecommunity (void *rule, struct prefix *prefix, 
+route_match_ecommunity (void *rule, struct prefix *prefix,
 			route_map_object_t type, void *object)
 {
   struct community_list *list;
   struct bgp_info *bgp_info;
 
-  if (type == RMAP_BGP) 
+  if (type == RMAP_BGP)
     {
       bgp_info = object;
-      
+
       if (!bgp_info->attr->extra)
         return RMAP_NOMATCH;
-      
+
       list = community_list_lookup (bgp_clist, (char *) rule,
 				    EXTCOMMUNITY_LIST_MASTER);
       if (! list)
@@ -1504,6 +1580,225 @@  struct route_map_rule_cmd route_set_community_cmd =
   route_set_community_free,
 };
 
+/* `set community COMMUNITY' */
+struct rmap_lcom_set
+{
+  struct lcommunity *lcom;
+  int additive;
+  int none;
+};
+
+
+/* For lcommunity set mechanism. */
+static route_map_result_t
+route_set_lcommunity (void *rule, struct prefix *prefix,
+		     route_map_object_t type, void *object)
+{
+  struct rmap_lcom_set *rcs;
+  struct bgp_info *binfo;
+  struct attr *attr;
+  struct lcommunity *new = NULL;
+  struct lcommunity *old;
+  struct lcommunity *merge;
+
+  if (type == RMAP_BGP)
+    {
+      rcs = rule;
+      binfo = object;
+      attr = binfo->attr;
+      old = (attr->extra) ? attr->extra->lcommunity : NULL;
+
+      /* "none" case.  */
+      if (rcs->none)
+	{
+	  attr->flag &= ~(ATTR_FLAG_BIT (BGP_ATTR_LARGE_COMMUNITIES));
+	  if (attr->extra) {
+	    attr->extra->lcommunity = NULL;
+	  }
+	  /* See the longer comment down below. */
+	  if (old && old->refcnt == 0)
+	    lcommunity_free(&old);
+	  return RMAP_OKAY;
+	}
+
+      if (rcs->additive && old)
+	{
+	  merge = lcommunity_merge (lcommunity_dup (old), rcs->lcom);
+
+	  /* HACK: if the old large-community is not intern'd,
+           * we should free it here, or all reference to it may be lost.
+           * Really need to cleanup attribute caching sometime.
+           */
+	  if (old->refcnt == 0)
+	    lcommunity_free (&old);
+	  new = lcommunity_uniq_sort (merge);
+	  lcommunity_free (&merge);
+	}
+      else
+	new = lcommunity_dup (rcs->lcom);
+
+	/* will be interned by caller if required */
+	if (attr->extra) {
+	  attr->extra->lcommunity = new;
+	}
+      attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LARGE_COMMUNITIES);
+    }
+
+  return RMAP_OKAY;
+}
+
+/* Compile function for set community. */
+static void *
+route_set_lcommunity_compile (const char *arg)
+{
+  struct rmap_lcom_set *rcs;
+  struct lcommunity *lcom = NULL;
+  char *sp;
+  int additive = 0;
+  int none = 0;
+
+  if (strcmp (arg, "none") == 0)
+    none = 1;
+  else
+    {
+      sp = strstr (arg, "additive");
+
+      if (sp && sp > arg)
+	{
+	  /* "additive" keyworkd is included.  */
+	  additive = 1;
+	  *(sp - 1) = '\0';
+	}
+
+      lcom = lcommunity_str2com (arg);
+
+     if (additive)
+	*(sp - 1) = ' ';
+
+     if (! lcom)
+	return NULL;
+    }
+
+  rcs = XCALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (struct rmap_com_set));
+  rcs->lcom = lcom;
+  rcs->additive = additive;
+  rcs->none = none;
+
+  return rcs;
+}
+
+/* Free function for set lcommunity. */
+static void
+route_set_lcommunity_free (void *rule)
+{
+  struct rmap_lcom_set *rcs = rule;
+
+  if (rcs->lcom) {
+    lcommunity_free (&rcs->lcom);
+  }
+  XFREE (MTYPE_ROUTE_MAP_COMPILED, rcs);
+}
+
+/* Set community rule structure. */
+struct route_map_rule_cmd route_set_lcommunity_cmd =
+{
+  "large-community",
+  route_set_lcommunity,
+  route_set_lcommunity_compile,
+  route_set_lcommunity_free,
+};
+
+/* `set large-comm-list (<1-99>|<100-500>|WORD) delete' */
+
+/* For large community set mechanism. */
+static route_map_result_t
+route_set_lcommunity_delete (void *rule, struct prefix *prefix,
+			     route_map_object_t type, void *object)
+{
+  struct community_list *list;
+  struct lcommunity *merge;
+  struct lcommunity *new;
+  struct lcommunity *old;
+  struct bgp_info *binfo;
+
+  if (type == RMAP_BGP)
+    {
+      if (! rule)
+	return RMAP_OKAY;
+
+      binfo = object;
+      list = community_list_lookup (bgp_clist, rule,
+				    LARGE_COMMUNITY_LIST_MASTER);
+      old = ((binfo->attr->extra) ? binfo->attr->extra->lcommunity : NULL);
+
+      if (list && old)
+	{
+	  merge = lcommunity_list_match_delete (lcommunity_dup (old), list);
+	  new = lcommunity_uniq_sort (merge);
+	  lcommunity_free (&merge);
+
+	  /* HACK: if the old community is not intern'd,
+	   * we should free it here, or all reference to it may be lost.
+	   * Really need to cleanup attribute caching sometime.
+	   */
+	  if (old->refcnt == 0)
+	    lcommunity_free (&old);
+
+	  if (new->size == 0)
+	    {
+	      binfo->attr->extra->lcommunity = NULL;
+	      binfo->attr->flag &= ~ATTR_FLAG_BIT (BGP_ATTR_LARGE_COMMUNITIES);
+	      lcommunity_free (&new);
+	    }
+	  else
+	    {
+	      binfo->attr->extra->lcommunity = new;
+	      binfo->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LARGE_COMMUNITIES);
+	    }
+	}
+    }
+
+  return RMAP_OKAY;
+}
+
+/* Compile function for set lcommunity. */
+static void *
+route_set_lcommunity_delete_compile (const char *arg)
+{
+  char *p;
+  char *str;
+  int len;
+
+  p = strchr (arg, ' ');
+  if (p)
+    {
+      len = p - arg;
+      str = XCALLOC (MTYPE_ROUTE_MAP_COMPILED, len + 1);
+      memcpy (str, arg, len);
+    }
+  else
+    str = NULL;
+
+  return str;
+}
+
+/* Free function for set lcommunity. */
+static void
+route_set_lcommunity_delete_free (void *rule)
+{
+  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+/* Set lcommunity rule structure. */
+struct route_map_rule_cmd route_set_lcommunity_delete_cmd =
+{
+  "large-comm-list",
+  route_set_lcommunity_delete,
+  route_set_lcommunity_delete_compile,
+  route_set_lcommunity_delete_free,
+};
+
+
 /* `set comm-list (<1-99>|<100-500>|WORD) delete' */
 
 /* For community set mechanism. */
@@ -3032,6 +3327,32 @@  ALIAS (no_match_community,
        "Community-list name\n"
        "Do exact matching of communities\n")
 
+DEFUN (match_lcommunity,
+       match_lcommunity_cmd,
+       "match large-community (<1-99>|<100-500>|WORD)",
+       MATCH_STR
+       "Match BGP large community list\n"
+       "Large Community-list number (standard)\n"
+       "Large Community-list number (expanded)\n"
+       "Large Community-list name\n")
+{
+  return bgp_route_match_add (vty, vty->index, "large-community", argv[0]);
+}
+
+DEFUN (no_match_lcommunity,
+       no_match_lcommunity_cmd,
+       "no match large-community (<1-99>|<100-500>|WORD)",
+       NO_STR
+       MATCH_STR
+       "Match BGP large community list\n"
+       "Large Community-list number (standard)\n"
+       "Large Community-list number (expanded)\n"
+       "Large Community-list name\n")
+{
+  return bgp_route_match_delete (vty, vty->index, "large-community", NULL);
+}
+
+
 DEFUN (match_ecommunity, 
        match_ecommunity_cmd,
        "match extcommunity (<1-99>|<100-500>|WORD)",
@@ -3612,6 +3933,104 @@  ALIAS (no_set_community_delete,
        "Community-list name\n"
        "Delete matching communities\n")
 
+
+DEFUN (set_lcommunity,
+       set_lcommunity_cmd,
+       "set large-community .AA:BB:CC",
+       SET_STR
+       "BGP large community attribute\n"
+       "Large Community number in aa:bb:cc format or additive\n")
+{
+  int ret;
+  char *str;
+
+  str = argv_concat (argv, argc, 0);
+  ret = bgp_route_set_add (vty, vty->index, "large-community", str);
+  XFREE (MTYPE_TMP, str);
+
+  return ret;
+}
+
+DEFUN (set_lcommunity_none,
+       set_lcommunity_none_cmd,
+       "set large-community none",
+       SET_STR
+       "BGP large community attribute\n"
+       "No large community attribute\n")
+{
+  return bgp_route_set_add (vty, vty->index, "large-community", "none");
+}
+
+DEFUN (no_set_lcommunity,
+       no_set_lcommunity_cmd,
+       "no set large-community",
+       NO_STR
+       SET_STR
+       "BGP large community attribute\n"
+       "Large community\n")
+{
+  return bgp_route_set_delete (vty, vty->index, "large-community", NULL);
+}
+
+ALIAS (no_set_lcommunity,
+       no_set_lcommunity_val_cmd,
+       "no set large-community .AA:BB:CC",
+       NO_STR
+       SET_STR
+       "BGP large community attribute\n"
+       "Large community in .AA:BB:CC format or additive\n")
+
+ALIAS (no_set_lcommunity,
+       no_set_lcommunity_none_cmd,
+       "no set large-community none",
+       NO_STR
+       SET_STR
+       "BGP community attribute\n"
+       "No community attribute\n")
+
+DEFUN (set_lcommunity_delete,
+       set_lcommunity_delete_cmd,
+       "set large-comm-list (<1-99>|<100-500>|WORD) delete",
+       SET_STR
+       "set BGP large community list (for deletion)\n"
+       "Large Community-list number (standard)\n"
+       "Large Communitly-list number (expanded)\n"
+       "Large Community-list name\n"
+       "Delete matching large communities\n")
+{
+  char *str;
+
+  str = XCALLOC (MTYPE_TMP, strlen (argv[0]) + strlen (" delete") + 1);
+  strcpy (str, argv[0]);
+  strcpy (str + strlen (argv[0]), " delete");
+
+  bgp_route_set_add (vty, vty->index, "large-comm-list", str);
+
+  XFREE (MTYPE_TMP, str);
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_set_lcommunity_delete,
+       no_set_lcommunity_delete_cmd,
+       "no set large-comm-list",
+       NO_STR
+       SET_STR
+       "set BGP large community list (for deletion)\n")
+{
+  return bgp_route_set_delete (vty, vty->index, "large-comm-list", NULL);
+}
+
+ALIAS (no_set_lcommunity_delete,
+       no_set_lcommunity_delete_val_cmd,
+       "no set large-comm-list (<1-99>|<100-500>|WORD) delete",
+       NO_STR
+       SET_STR
+       "set BGP large community list (for deletion)\n"
+       "Large Community-list number (standard)\n"
+       "Large Communitly-list number (expanded)\n"
+       "Large Community-list name\n"
+       "Delete matching large communities\n")
+
 DEFUN (set_ecommunity_rt,
        set_ecommunity_rt_cmd,
        "set extcommunity rt .ASN:nn_or_IP-address:nn",
@@ -4170,6 +4589,7 @@  bgp_route_map_init (void)
   route_map_install_match (&route_match_ip_route_source_prefix_list_cmd);
   route_map_install_match (&route_match_aspath_cmd);
   route_map_install_match (&route_match_community_cmd);
+  route_map_install_match (&route_match_lcommunity_cmd);
   route_map_install_match (&route_match_ecommunity_cmd);
   route_map_install_match (&route_match_local_pref_cmd);
   route_map_install_match (&route_match_metric_cmd);
@@ -4188,6 +4608,8 @@  bgp_route_map_init (void)
   route_map_install_set (&route_set_aggregator_as_cmd);
   route_map_install_set (&route_set_community_cmd);
   route_map_install_set (&route_set_community_delete_cmd);
+  route_map_install_set (&route_set_lcommunity_cmd);
+  route_map_install_set (&route_set_lcommunity_delete_cmd);
   route_map_install_set (&route_set_vpnv4_nexthop_cmd);
   route_map_install_set (&route_set_originator_id_cmd);
   route_map_install_set (&route_set_ecommunity_rt_cmd);
@@ -4232,6 +4654,8 @@  bgp_route_map_init (void)
   install_element (RMAP_NODE, &no_match_community_cmd);
   install_element (RMAP_NODE, &no_match_community_val_cmd);
   install_element (RMAP_NODE, &no_match_community_exact_cmd);
+  install_element (RMAP_NODE, &match_lcommunity_cmd);
+  install_element (RMAP_NODE, &no_match_lcommunity_cmd);
   install_element (RMAP_NODE, &match_ecommunity_cmd);
   install_element (RMAP_NODE, &no_match_ecommunity_cmd);
   install_element (RMAP_NODE, &no_match_ecommunity_val_cmd);
@@ -4283,6 +4707,14 @@  bgp_route_map_init (void)
   install_element (RMAP_NODE, &set_community_delete_cmd);
   install_element (RMAP_NODE, &no_set_community_delete_cmd);
   install_element (RMAP_NODE, &no_set_community_delete_val_cmd);
+  install_element (RMAP_NODE, &set_lcommunity_cmd);
+  install_element (RMAP_NODE, &set_lcommunity_none_cmd);
+  install_element (RMAP_NODE, &no_set_lcommunity_cmd);
+  install_element (RMAP_NODE, &no_set_lcommunity_val_cmd);
+  install_element (RMAP_NODE, &no_set_lcommunity_none_cmd);
+  install_element (RMAP_NODE, &set_lcommunity_delete_cmd);
+  install_element (RMAP_NODE, &no_set_lcommunity_delete_cmd);
+  install_element (RMAP_NODE, &no_set_lcommunity_delete_val_cmd);
   install_element (RMAP_NODE, &set_ecommunity_rt_cmd);
   install_element (RMAP_NODE, &no_set_ecommunity_rt_cmd);
   install_element (RMAP_NODE, &no_set_ecommunity_rt_val_cmd);
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
index 7af4e81..bf53086 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -38,6 +38,7 @@  Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 #include "bgpd/bgp_aspath.h"
 #include "bgpd/bgp_community.h"
 #include "bgpd/bgp_ecommunity.h"
+#include "bgpd/bgp_lcommunity.h"
 #include "bgpd/bgp_damp.h"
 #include "bgpd/bgp_debug.h"
 #include "bgpd/bgp_fsm.h"
@@ -2364,13 +2365,15 @@  DEFUN (no_neighbor_send_community,
 /* neighbor send-community extended. */
 DEFUN (neighbor_send_community_type,
        neighbor_send_community_type_cmd,
-       NEIGHBOR_CMD2 "send-community (both|extended|standard)",
+       NEIGHBOR_CMD2 "send-community (both|all|extended|standard|large)",
        NEIGHBOR_STR
        NEIGHBOR_ADDR_STR2
        "Send Community attribute to this neighbor\n"
-       "Send Standard and Extended Community attributes\n"
+       "Send Standard, Large and Extended Community attributes\n"
+       "Send Standard, Large and Extended Community attributes\n"
        "Send Extended Community attributes\n"
-       "Send Standard Community attributes\n")
+       "Send Standard Community attributes\n"
+       "Send Large Community attributes\n")
 {
   if (strncmp (argv[1], "s", 1) == 0)
     return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty),
@@ -2380,23 +2383,30 @@  DEFUN (neighbor_send_community_type,
     return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty),
 				 bgp_node_safi (vty),
 				 PEER_FLAG_SEND_EXT_COMMUNITY);
+    if (strncmp (argv[1], "l", 1) == 0)
+    return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty),
+				 bgp_node_safi (vty),
+				 PEER_FLAG_SEND_LARGE_COMMUNITY);
 
   return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty),
 			       bgp_node_safi (vty),
 			       (PEER_FLAG_SEND_COMMUNITY|
-				PEER_FLAG_SEND_EXT_COMMUNITY));
+				PEER_FLAG_SEND_EXT_COMMUNITY|
+				PEER_FLAG_SEND_LARGE_COMMUNITY));
 }
 
 DEFUN (no_neighbor_send_community_type,
        no_neighbor_send_community_type_cmd,
-       NO_NEIGHBOR_CMD2 "send-community (both|extended|standard)",
+       NO_NEIGHBOR_CMD2 "send-community (both|all|extended|standard|large)",
        NO_STR
        NEIGHBOR_STR
        NEIGHBOR_ADDR_STR2
        "Send Community attribute to this neighbor\n"
-       "Send Standard and Extended Community attributes\n"
+       "Send Standard, Large and Extended Community attributes\n"
+       "Send Standard, Large and Extended Community attributes\n"
        "Send Extended Community attributes\n"
-       "Send Standard Community attributes\n")
+       "Send Standard Community attributes\n"
+       "Send Large Community attributes\n")
 {
   if (strncmp (argv[1], "s", 1) == 0)
     return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty),
@@ -2406,11 +2416,16 @@  DEFUN (no_neighbor_send_community_type,
     return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty),
 				   bgp_node_safi (vty),
 				   PEER_FLAG_SEND_EXT_COMMUNITY);
+    if (strncmp (argv[1], "l", 1) == 0)
+    return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty),
+				   bgp_node_safi (vty),
+				   PEER_FLAG_SEND_LARGE_COMMUNITY);
 
   return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty),
 				 bgp_node_safi (vty),
 				 (PEER_FLAG_SEND_COMMUNITY |
-				  PEER_FLAG_SEND_EXT_COMMUNITY));
+				  PEER_FLAG_SEND_EXT_COMMUNITY|
+				  PEER_FLAG_SEND_LARGE_COMMUNITY));
 }
 
 /* neighbor soft-reconfig. */
@@ -7434,7 +7449,12 @@  DEFUN (show_bgp_memory,
              mtype_memstr (memstrbuf, sizeof (memstrbuf),
                          count * sizeof (struct ecommunity)),
              VTY_NEWLINE);
-  
+  if ((count = mtype_stats_alloc (MTYPE_LCOMMUNITY)))
+    vty_out (vty, "%ld BGP large-community entries, using %s of memory%s",
+	     count,
+             mtype_memstr (memstrbuf, sizeof (memstrbuf),
+                         count * sizeof (struct lcommunity)),
+             VTY_NEWLINE);
   if ((count = mtype_stats_alloc (MTYPE_CLUSTER)))
     vty_out (vty, "%ld Cluster lists, using %s of memory%s", count,
              mtype_memstr (memstrbuf, sizeof (memstrbuf),
@@ -8232,14 +8252,18 @@  bgp_show_peer_afi (struct vty *vty, struct peer *p, afi_t afi, safi_t safi)
   if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_MED_UNCHANGED))
     vty_out (vty, "  MED is propagated unchanged to this neighbor%s", VTY_NEWLINE);
   if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY)
-      || CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY))
+      || CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)
+      || CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_LARGE_COMMUNITY))
     {
       vty_out (vty, "  Community attribute sent to this neighbor");
       if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY)
-	&& CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY))
-	vty_out (vty, "(both)%s", VTY_NEWLINE);
+	  && CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)
+	  && CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_LARGE_COMMUNITY))
+	vty_out (vty, "(all)%s", VTY_NEWLINE);
       else if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY))
 	vty_out (vty, "(extended)%s", VTY_NEWLINE);
+      else if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_LARGE_COMMUNITY))
+	vty_out (vty, "(large)%s", VTY_NEWLINE);
       else 
 	vty_out (vty, "(standard)%s", VTY_NEWLINE);
     }
@@ -9097,6 +9121,35 @@  DEFUN (show_ip_bgp_community_info,
   return CMD_SUCCESS;
 }
 
+static void
+lcommunity_show_all_iterator (struct hash_backet *backet, struct vty *vty)
+{
+  struct lcommunity *lcom;
+
+  lcom = (struct lcommunity *) backet->data;
+  vty_out (vty, "[%p] (%ld) %s%s", (void *)backet, lcom->refcnt,
+	   lcommunity_str (lcom), VTY_NEWLINE);
+}
+
+/* Show BGP's community internal data. */
+DEFUN (show_ip_bgp_lcommunity_info,
+       show_ip_bgp_lcommunity_info_cmd,
+       "show ip bgp large-community-info",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "List all bgp large-community information\n")
+{
+  vty_out (vty, "Address Refcnt Large-community%s", VTY_NEWLINE);
+
+  hash_iterate (lcommunity_hash (),
+		(void (*) (struct hash_backet *, void *))
+		lcommunity_show_all_iterator,
+		vty);
+
+  return CMD_SUCCESS;
+}
+
 DEFUN (show_ip_bgp_attr_info, 
        show_ip_bgp_attr_info_cmd,
        "show ip bgp attribute-info",
@@ -11206,6 +11259,9 @@  bgp_vty_init (void)
   /* "show ip bgp community" commands. */
   install_element (VIEW_NODE, &show_ip_bgp_community_info_cmd);
 
+  /* "show ip bgp large-community" commands. */
+  install_element (VIEW_NODE, &show_ip_bgp_lcommunity_info_cmd);
+
   /* "show ip bgp attribute-info" commands. */
   install_element (VIEW_NODE, &show_ip_bgp_attr_info_cmd);
 
@@ -11691,6 +11747,359 @@  DEFUN (show_ip_community_list_arg,
   return CMD_SUCCESS;
 }
 
+/*
+ * Large Community code.
+ */
+static int
+lcommunity_list_set_vty (struct vty *vty, int argc, const char **argv,
+			 int style, int reject_all_digit_name)
+{
+  int ret;
+  int direct;
+  char *str;
+
+  /* Check the list type. */
+  if (strncmp (argv[1], "p", 1) == 0)
+    direct = COMMUNITY_PERMIT;
+  else if (strncmp (argv[1], "d", 1) == 0)
+    direct = COMMUNITY_DENY;
+  else
+    {
+      vty_out (vty, "%% Matching condition must be permit or deny%s",
+	       VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* All digit name check.  */
+  if (reject_all_digit_name && all_digit (argv[0]))
+    {
+      vty_out (vty, "%% Community name cannot have all digits%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* Concat community string argument.  */
+  if (argc > 1)
+    str = argv_concat (argv, argc, 2);
+  else
+    str = NULL;
+
+  ret = lcommunity_list_set (bgp_clist, argv[0], str, direct, style);
+
+  /* Free temporary community list string allocated by
+     argv_concat().  */
+  if (str)
+    XFREE (MTYPE_TMP, str);
+
+  if (ret < 0)
+    {
+      community_list_perror (vty, ret);
+      return CMD_WARNING;
+    }
+  return CMD_SUCCESS;
+}
+
+static int
+lcommunity_list_unset_vty (struct vty *vty, int argc, const char **argv,
+			   int style)
+{
+  int ret;
+  int direct = 0;
+  char *str = NULL;
+
+  if (argc > 1)
+    {
+      /* Check the list direct. */
+      if (strncmp (argv[1], "p", 1) == 0)
+	direct = COMMUNITY_PERMIT;
+      else if (strncmp (argv[1], "d", 1) == 0)
+	direct = COMMUNITY_DENY;
+      else
+	{
+	  vty_out (vty, "%% Matching condition must be permit or deny%s",
+		   VTY_NEWLINE);
+	  return CMD_WARNING;
+	}
+
+      /* Concat community string argument.  */
+      str = argv_concat (argv, argc, 2);
+    }
+
+  /* Unset community list.  */
+  ret = lcommunity_list_unset (bgp_clist, argv[0], str, direct, style);
+
+  /* Free temporary community list string allocated by
+     argv_concat().  */
+  if (str)
+    XFREE (MTYPE_TMP, str);
+
+  if (ret < 0)
+    {
+      community_list_perror (vty, ret);
+      return CMD_WARNING;
+    }
+
+  return CMD_SUCCESS;
+}
+
+/* "large-community-list" keyword help string.  */
+#define LCOMMUNITY_LIST_STR "Add a large community list entry\n"
+#define LCOMMUNITY_VAL_STR  "large community in 'aa:bb:cc' format\n"
+
+DEFUN (ip_lcommunity_list_standard,
+       ip_lcommunity_list_standard_cmd,
+       "ip large-community-list <1-99> (deny|permit) .AA:BB:CC",
+       IP_STR
+       LCOMMUNITY_LIST_STR
+       "Large Community list number (standard)\n"
+       "Specify large community to reject\n"
+       "Specify large community to accept\n"
+       LCOMMUNITY_VAL_STR)
+{
+  return lcommunity_list_set_vty (vty, argc, argv, LARGE_COMMUNITY_LIST_STANDARD, 0);
+}
+
+ALIAS (ip_lcommunity_list_standard,
+       ip_lcommunity_list_standard2_cmd,
+       "ip large-community-list <1-99> (deny|permit)",
+       IP_STR
+       LCOMMUNITY_LIST_STR
+       "Large Community list number (standard)\n"
+       "Specify large community to reject\n"
+       "Specify large community to accept\n")
+
+DEFUN (ip_lcommunity_list_expanded,
+       ip_lcommunity_list_expanded_cmd,
+       "ip large-community-list <100-500> (deny|permit) .LINE",
+       IP_STR
+       LCOMMUNITY_LIST_STR
+       "Large Community list number (expanded)\n"
+       "Specify large community to reject\n"
+       "Specify large community to accept\n"
+       "An ordered list as a regular-expression\n")
+{
+  return lcommunity_list_set_vty (vty, argc, argv, LARGE_COMMUNITY_LIST_EXPANDED, 0);
+}
+
+DEFUN (ip_lcommunity_list_name_standard,
+       ip_lcommunity_list_name_standard_cmd,
+       "ip large-community-list standard WORD (deny|permit) .AA:BB.CC",
+       IP_STR
+       LCOMMUNITY_LIST_STR
+       "Specify standard large-community-list\n"
+       "Large Community list name\n"
+       "Specify large community to reject\n"
+       "Specify large community to accept\n"
+       LCOMMUNITY_VAL_STR)
+{
+  return lcommunity_list_set_vty (vty, argc, argv, LARGE_COMMUNITY_LIST_STANDARD, 1);
+}
+
+ALIAS (ip_lcommunity_list_name_standard,
+       ip_lcommunity_list_name_standard2_cmd,
+       "ip large-community-list standard WORD (deny|permit)",
+       IP_STR
+       LCOMMUNITY_LIST_STR
+       "Specify standard large-community-list\n"
+       "Large Community list name\n"
+       "Specify large community to reject\n"
+       "Specify large community to accept\n")
+
+DEFUN (ip_lcommunity_list_name_expanded,
+       ip_lcommunity_list_name_expanded_cmd,
+       "ip large-community-list expanded WORD (deny|permit) .LINE",
+       IP_STR
+       LCOMMUNITY_LIST_STR
+       "Specify expanded large-community-list\n"
+       "Large Community list name\n"
+       "Specify large community to reject\n"
+       "Specify large community to accept\n"
+       "An ordered list as a regular-expression\n")
+{
+  return lcommunity_list_set_vty (vty, argc, argv, LARGE_COMMUNITY_LIST_EXPANDED, 1);
+}
+
+DEFUN (no_ip_lcommunity_list_standard_all,
+       no_ip_lcommunity_list_standard_all_cmd,
+       "no ip large-community-list <1-99>",
+       NO_STR
+       IP_STR
+       LCOMMUNITY_LIST_STR
+       "Large Community list number (standard)\n")
+{
+  return lcommunity_list_unset_vty (vty, argc, argv, LARGE_COMMUNITY_LIST_STANDARD);
+}
+
+DEFUN (no_ip_lcommunity_list_expanded_all,
+       no_ip_lcommunity_list_expanded_all_cmd,
+       "no ip large-community-list <100-500>",
+       NO_STR
+       IP_STR
+       LCOMMUNITY_LIST_STR
+       "Large Community list number (expanded)\n")
+{
+  return lcommunity_list_unset_vty (vty, argc, argv, LARGE_COMMUNITY_LIST_EXPANDED);
+}
+
+DEFUN (no_ip_lcommunity_list_name_standard_all,
+       no_ip_lcommunity_list_name_standard_all_cmd,
+       "no ip large-community-list standard WORD",
+       NO_STR
+       IP_STR
+       LCOMMUNITY_LIST_STR
+       "Specify standard large-community-list\n"
+       "Large Community list name\n")
+{
+  return lcommunity_list_unset_vty (vty, argc, argv, LARGE_COMMUNITY_LIST_STANDARD);
+}
+
+DEFUN (no_ip_lcommunity_list_name_expanded_all,
+       no_ip_lcommunity_list_name_expanded_all_cmd,
+       "no ip large-community-list expanded WORD",
+       NO_STR
+       IP_STR
+       LCOMMUNITY_LIST_STR
+       "Specify expanded large-community-list\n"
+       "Large Community list name\n")
+{
+  return lcommunity_list_unset_vty (vty, argc, argv, LARGE_COMMUNITY_LIST_EXPANDED);
+}
+
+DEFUN (no_ip_lcommunity_list_standard,
+       no_ip_lcommunity_list_standard_cmd,
+       "no ip large-community-list <1-99> (deny|permit) .AA:.AA:NN",
+       NO_STR
+       IP_STR
+       LCOMMUNITY_LIST_STR
+       "Large Community list number (standard)\n"
+       "Specify large community to reject\n"
+       "Specify large community to accept\n"
+       LCOMMUNITY_VAL_STR)
+{
+  return lcommunity_list_unset_vty (vty, argc, argv, LARGE_COMMUNITY_LIST_STANDARD);
+}
+
+DEFUN (no_ip_lcommunity_list_expanded,
+       no_ip_lcommunity_list_expanded_cmd,
+       "no ip large-community-list <100-500> (deny|permit) .LINE",
+       NO_STR
+       IP_STR
+       LCOMMUNITY_LIST_STR
+       "Large Community list number (expanded)\n"
+       "Specify large community to reject\n"
+       "Specify large community to accept\n"
+       "An ordered list as a regular-expression\n")
+{
+  return lcommunity_list_unset_vty (vty, argc, argv, LARGE_COMMUNITY_LIST_EXPANDED);
+}
+
+DEFUN (no_ip_lcommunity_list_name_standard,
+       no_ip_lcommunity_list_name_standard_cmd,
+       "no ip large-community-list standard WORD (deny|permit) .AA:.AA:NN",
+       NO_STR
+       IP_STR
+       LCOMMUNITY_LIST_STR
+       "Specify standard large-community-list\n"
+       "Large Community list name\n"
+       "Specify large community to reject\n"
+       "Specify large community to accept\n"
+       LCOMMUNITY_VAL_STR)
+{
+  return lcommunity_list_unset_vty (vty, argc, argv, LARGE_COMMUNITY_LIST_STANDARD);
+}
+
+DEFUN (no_ip_lcommunity_list_name_expanded,
+       no_ip_lcommunity_list_name_expanded_cmd,
+       "no ip large-community-list expanded WORD (deny|permit) .LINE",
+       NO_STR
+       IP_STR
+       LCOMMUNITY_LIST_STR
+       "Specify expanded large-community-list\n"
+       "Large community list name\n"
+       "Specify large community to reject\n"
+       "Specify large community to accept\n"
+       "An ordered list as a regular-expression\n")
+{
+  return lcommunity_list_unset_vty (vty, argc, argv, LARGE_COMMUNITY_LIST_EXPANDED);
+}
+
+static void
+lcommunity_list_show (struct vty *vty, struct community_list *list)
+{
+  struct community_entry *entry;
+
+  for (entry = list->head; entry; entry = entry->next)
+    {
+      if (entry == list->head)
+	{
+	  if (all_digit (list->name))
+	    vty_out (vty, "Large community %s list %s%s",
+		     entry->style == EXTCOMMUNITY_LIST_STANDARD ?
+		     "standard" : "(expanded) access",
+		     list->name, VTY_NEWLINE);
+	  else
+	    vty_out (vty, "Named large community %s list %s%s",
+		     entry->style == EXTCOMMUNITY_LIST_STANDARD ?
+		     "standard" : "expanded",
+		     list->name, VTY_NEWLINE);
+	}
+      if (entry->any)
+	vty_out (vty, "    %s%s",
+		 community_direct_str (entry->direct), VTY_NEWLINE);
+      else
+	vty_out (vty, "    %s %s%s",
+		 community_direct_str (entry->direct),
+		 entry->style == EXTCOMMUNITY_LIST_STANDARD ?
+		 entry->u.ecom->str : entry->config,
+		 VTY_NEWLINE);
+    }
+}
+
+DEFUN (show_ip_lcommunity_list,
+       show_ip_lcommunity_list_cmd,
+       "show ip large-community-list",
+       SHOW_STR
+       IP_STR
+       "List large-community list\n")
+{
+  struct community_list *list;
+  struct community_list_master *cm;
+
+  cm = community_list_master_lookup (bgp_clist, LARGE_COMMUNITY_LIST_MASTER);
+  if (! cm)
+    return CMD_SUCCESS;
+
+  for (list = cm->num.head; list; list = list->next)
+    lcommunity_list_show (vty, list);
+
+  for (list = cm->str.head; list; list = list->next)
+    lcommunity_list_show (vty, list);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (show_ip_lcommunity_list_arg,
+       show_ip_lcommunity_list_arg_cmd,
+       "show ip large-community-list (<1-500>|WORD)",
+       SHOW_STR
+       IP_STR
+       "List large-community list\n"
+       "large-community-list number\n"
+       "large-community-list name\n")
+{
+  struct community_list *list;
+
+  list = community_list_lookup (bgp_clist, argv[0], LARGE_COMMUNITY_LIST_MASTER);
+  if (! list)
+    {
+      vty_out (vty, "%% Can't find extcommunity-list%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  lcommunity_list_show (vty, list);
+
+  return CMD_SUCCESS;
+}
+
 static int
 extcommunity_list_set_vty (struct vty *vty, int argc, const char **argv, 
                            int style, int reject_all_digit_name)
@@ -12113,6 +12522,30 @@  community_list_config_write (struct vty *vty)
 		 community_list_config_str (entry), VTY_NEWLINE);
 	write++;
       }
+
+
+    /* lcommunity-list.  */
+  cm = community_list_master_lookup (bgp_clist, LARGE_COMMUNITY_LIST_MASTER);
+
+  for (list = cm->num.head; list; list = list->next)
+    for (entry = list->head; entry; entry = entry->next)
+      {
+	vty_out (vty, "ip large-community-list %s %s %s%s",
+		 list->name, community_direct_str (entry->direct),
+		 community_list_config_str (entry), VTY_NEWLINE);
+	write++;
+      }
+  for (list = cm->str.head; list; list = list->next)
+    for (entry = list->head; entry; entry = entry->next)
+      {
+	vty_out (vty, "ip large-community-list %s %s %s %s%s",
+		 entry->style == LARGE_COMMUNITY_LIST_STANDARD
+		 ? "standard" : "expanded",
+		 list->name, community_direct_str (entry->direct),
+		 community_list_config_str (entry), VTY_NEWLINE);
+	write++;
+      }
+
   return write;
 }
 
@@ -12163,4 +12596,22 @@  community_list_vty (void)
   install_element (CONFIG_NODE, &no_ip_extcommunity_list_name_expanded_cmd);
   install_element (VIEW_NODE, &show_ip_extcommunity_list_cmd);
   install_element (VIEW_NODE, &show_ip_extcommunity_list_arg_cmd);
+
+  /* Large Community List */
+  install_element (CONFIG_NODE, &ip_lcommunity_list_standard_cmd);
+  install_element (CONFIG_NODE, &ip_lcommunity_list_standard2_cmd);
+  install_element (CONFIG_NODE, &ip_lcommunity_list_expanded_cmd);
+  install_element (CONFIG_NODE, &ip_lcommunity_list_name_standard_cmd);
+  install_element (CONFIG_NODE, &ip_lcommunity_list_name_standard2_cmd);
+  install_element (CONFIG_NODE, &ip_lcommunity_list_name_expanded_cmd);
+  install_element (CONFIG_NODE, &no_ip_lcommunity_list_standard_all_cmd);
+  install_element (CONFIG_NODE, &no_ip_lcommunity_list_expanded_all_cmd);
+  install_element (CONFIG_NODE, &no_ip_lcommunity_list_name_standard_all_cmd);
+  install_element (CONFIG_NODE, &no_ip_lcommunity_list_name_expanded_all_cmd);
+  install_element (CONFIG_NODE, &no_ip_lcommunity_list_standard_cmd);
+  install_element (CONFIG_NODE, &no_ip_lcommunity_list_expanded_cmd);
+  install_element (CONFIG_NODE, &no_ip_lcommunity_list_name_standard_cmd);
+  install_element (CONFIG_NODE, &no_ip_lcommunity_list_name_expanded_cmd);
+  install_element (VIEW_NODE, &show_ip_lcommunity_list_cmd);
+  install_element (VIEW_NODE, &show_ip_lcommunity_list_arg_cmd);
 }
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index 018a599..b654117 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -627,6 +627,7 @@  peer_af_flag_reset (struct peer *peer, afi_t afi, safi_t safi)
     {
       SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY);
       SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY);
+      SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_LARGE_COMMUNITY);
     }
 
   /* Clear neighbor default_originate_rmap */
@@ -861,6 +862,7 @@  peer_new (struct bgp *bgp)
 	  {
 	    SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY);
 	    SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY);
+	    SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_LARGE_COMMUNITY);
 	  }
 	peer->orf_plist[afi][safi] = NULL;
       }
@@ -2508,6 +2510,7 @@  static const struct peer_flag_action peer_af_flag_action_list[] =
     { PEER_FLAG_NEXTHOP_SELF,             1, peer_change_reset_out },
     { PEER_FLAG_SEND_COMMUNITY,           1, peer_change_reset_out },
     { PEER_FLAG_SEND_EXT_COMMUNITY,       1, peer_change_reset_out },
+    { PEER_FLAG_SEND_LARGE_COMMUNITY,     1, peer_change_reset_out },
     { PEER_FLAG_SOFT_RECONFIG,            0, peer_change_reset_in },
     { PEER_FLAG_REFLECTOR_CLIENT,         1, peer_change_reset },
     { PEER_FLAG_RSERVER_CLIENT,           1, peer_change_reset },
@@ -5251,23 +5254,31 @@  bgp_config_write_peer (struct vty *vty, struct bgp *bgp,
       if (bgp_option_check (BGP_OPT_CONFIG_CISCO))
 	{
 	  if (peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_COMMUNITY)
-	      && peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_EXT_COMMUNITY))
-	    vty_out (vty, " neighbor %s send-community both%s", addr, VTY_NEWLINE);
+	      && peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_EXT_COMMUNITY)
+	      && peer_af_flag_check(peer, afi, safi, PEER_FLAG_SEND_LARGE_COMMUNITY))
+	    vty_out (vty, " neighbor %s send-community all%s", addr, VTY_NEWLINE);
 	  else if (peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_EXT_COMMUNITY))	
 	    vty_out (vty, " neighbor %s send-community extended%s",
 		     addr, VTY_NEWLINE);
+	  else if (peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_LARGE_COMMUNITY))
+	    vty_out (vty, " neighbor %s send-community large%s",
+		     addr, VTY_NEWLINE);
 	  else if (peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_COMMUNITY))
 	    vty_out (vty, " neighbor %s send-community%s", addr, VTY_NEWLINE);
 	}
       else
 	{
 	  if (! peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_COMMUNITY)
-	      && ! peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_EXT_COMMUNITY))
-	    vty_out (vty, " no neighbor %s send-community both%s",
+	      && ! peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_EXT_COMMUNITY)
+	      && ! peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_LARGE_COMMUNITY))
+	    vty_out (vty, " no neighbor %s send-community all%s",
 		     addr, VTY_NEWLINE);
 	  else if (! peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_EXT_COMMUNITY))
 	    vty_out (vty, " no neighbor %s send-community extended%s",
 		     addr, VTY_NEWLINE);
+	  else if (! peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_LARGE_COMMUNITY))
+	    vty_out (vty, " no neighbor %s send-community large%s",
+		     addr, VTY_NEWLINE);
 	  else if (! peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_COMMUNITY))
 	    vty_out (vty, " no neighbor %s send-community%s",
 		     addr, VTY_NEWLINE);
diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h
index 0058b58..e0744ea 100644
--- a/bgpd/bgpd.h
+++ b/bgpd/bgpd.h
@@ -425,6 +425,7 @@  struct peer
 #define PEER_FLAG_MAX_PREFIX_WARNING        (1 << 15) /* maximum prefix warning-only */
 #define PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED   (1 << 16) /* leave link-local nexthop unchanged */
 #define PEER_FLAG_NEXTHOP_SELF_ALL          (1 << 17) /* next-hop-self all */
+#define PEER_FLAG_SEND_LARGE_COMMUNITY      (1 << 18) /* Send large Communities */
 
   /* MD5 password */
   char *password;
@@ -655,6 +656,7 @@  struct bgp_nlri
 #define BGP_ATTR_AS4_AGGREGATOR                 18
 #define BGP_ATTR_AS_PATHLIMIT                   21
 #define BGP_ATTR_ENCAP                          23
+#define BGP_ATTR_LARGE_COMMUNITIES              32
 
 /* BGP update origin.  */
 #define BGP_ORIGIN_IGP                           0
diff --git a/lib/memtypes.c b/lib/memtypes.c
index 8abe99d..768efa7 100644
--- a/lib/memtypes.c
+++ b/lib/memtypes.c
@@ -157,6 +157,9 @@  struct memory_list memory_list_bgp[] =
   { MTYPE_BGP_AGGREGATE,	"BGP aggregate"			},
   { MTYPE_BGP_ADDR,		"BGP own address"		},
   { MTYPE_ENCAP_TLV,		"ENCAP TLV",			},
+  { MTYPE_LCOMMUNITY,           "Large Community",              },
+  { MTYPE_LCOMMUNITY_STR,       "Large Community str",          },
+  { MTYPE_LCOMMUNITY_VAL,       "Large Community val",          },
   { -1, NULL }
 };