summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bgpd/Makefile.am5
-rw-r--r--bgpd/bgp_attr.c80
-rw-r--r--bgpd/bgp_attr.h16
-rw-r--r--bgpd/bgp_attr_evpn.c141
-rw-r--r--bgpd/bgp_attr_evpn.h59
-rw-r--r--bgpd/bgp_clist.c4
-rw-r--r--bgpd/bgp_debug.c31
-rw-r--r--bgpd/bgp_debug.h5
-rw-r--r--bgpd/bgp_ecommunity.c102
-rw-r--r--bgpd/bgp_ecommunity.h13
-rw-r--r--bgpd/bgp_encap.c10
-rw-r--r--bgpd/bgp_encap_tlv.c22
-rw-r--r--bgpd/bgp_encap_types.h7
-rw-r--r--bgpd/bgp_evpn.c225
-rw-r--r--bgpd/bgp_evpn.h40
-rw-r--r--bgpd/bgp_evpn_vty.c750
-rw-r--r--bgpd/bgp_evpn_vty.h29
-rw-r--r--bgpd/bgp_mplsvpn.c197
-rw-r--r--bgpd/bgp_mplsvpn.h3
-rw-r--r--bgpd/bgp_open.c15
-rw-r--r--bgpd/bgp_packet.c25
-rw-r--r--bgpd/bgp_packet.h2
-rw-r--r--bgpd/bgp_route.c635
-rw-r--r--bgpd/bgp_route.h25
-rw-r--r--bgpd/bgp_updgrp_adv.c4
-rw-r--r--bgpd/bgp_updgrp_packet.c55
-rw-r--r--bgpd/bgp_vpn.c200
-rw-r--r--bgpd/bgp_vpn.h30
-rw-r--r--bgpd/bgp_vty.c53
-rw-r--r--bgpd/bgpd.c14
-rw-r--r--bgpd/bgpd.h11
-rw-r--r--bgpd/rfapi/bgp_rfapi_cfg.c26
-rw-r--r--bgpd/rfapi/rfapi.c10
-rw-r--r--bgpd/rfapi/rfapi_import.c28
-rw-r--r--bgpd/rfapi/rfapi_monitor.c12
-rw-r--r--bgpd/rfapi/rfapi_private.h4
-rw-r--r--bgpd/rfapi/rfapi_rib.c10
-rw-r--r--bgpd/rfapi/rfapi_vty.c12
-rw-r--r--bgpd/rfapi/vnc_export_bgp.c32
-rw-r--r--lib/command.c3
-rw-r--r--lib/command.h1
-rw-r--r--lib/plist.c2
-rw-r--r--lib/prefix.c77
-rw-r--r--lib/prefix.h47
-rw-r--r--lib/srcdest_table.c4
-rw-r--r--lib/srcdest_table.h4
-rw-r--r--lib/vty.c1
-rw-r--r--lib/zebra.h16
-rw-r--r--tests/bgpd/test_ecommunity.c4
-rw-r--r--tests/bgpd/test_mp_attr.c5
-rw-r--r--vtysh/vtysh.c33
-rw-r--r--zebra/rib.h4
-rw-r--r--zebra/zebra_rib.c4
53 files changed, 2622 insertions, 525 deletions
diff --git a/bgpd/Makefile.am b/bgpd/Makefile.am
index 611dbb8558..a9e709e231 100644
--- a/bgpd/Makefile.am
+++ b/bgpd/Makefile.am
@@ -79,7 +79,8 @@ libbgp_a_SOURCES = \
bgp_mplsvpn.c bgp_nexthop.c \
bgp_damp.c bgp_table.c bgp_advertise.c bgp_vty.c bgp_mpath.c \
bgp_nht.c bgp_updgrp.c bgp_updgrp_packet.c bgp_updgrp_adv.c bgp_bfd.c \
- bgp_encap.c bgp_encap_tlv.c $(BGP_VNC_RFAPI_SRC)
+ bgp_encap.c bgp_encap_tlv.c $(BGP_VNC_RFAPI_SRC) bgp_attr_evpn.c \
+ bgp_evpn.c bgp_evpn_vty.c bgp_vpn.c
noinst_HEADERS = \
bgp_memory.h \
@@ -90,7 +91,7 @@ noinst_HEADERS = \
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_nht.h \
bgp_updgrp.h bgp_bfd.h bgp_encap.h bgp_encap_tlv.h bgp_encap_types.h \
- $(BGP_VNC_RFAPI_HD)
+ $(BGP_VNC_RFAPI_HD) bgp_attr_evpn.h bgp_evpn.h bgp_evpn_vty.h bgp_vpn.h
bgpd_SOURCES = bgp_main.c
bgpd_LDADD = libbgp.a $(BGP_VNC_RFP_LIB) ../lib/libfrr.la @LIBCAP@ @LIBM@
diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c
index 7dc42e719f..929a9fb4ad 100644
--- a/bgpd/bgp_attr.c
+++ b/bgpd/bgp_attr.c
@@ -50,6 +50,8 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
# include "bgp_encap_types.h"
# include "bgp_vnc_types.h"
#endif
+#include "bgp_encap_types.h"
+#include "bgp_evpn.h"
/* Attribute strings for logging. */
static const struct message attr_str [] =
@@ -419,6 +421,18 @@ encap_finish (void)
#endif
}
+static bool
+overlay_index_same(const struct attr_extra *ae1, const struct attr_extra *ae2)
+{
+ if(!ae1 && ae2)
+ return false;
+ if(!ae2 && ae1)
+ return false;
+ if(!ae1 && !ae2)
+ return true;
+ return !memcmp(&(ae1->evpn_overlay), &(ae2->evpn_overlay), sizeof(struct overlay_index));
+}
+
/* Unknown transit attribute. */
static struct hash *transit_hash;
@@ -730,7 +744,8 @@ attrhash_cmp (const void *p1, const void *p2)
#if ENABLE_BGP_VNC
&& encap_same(ae1->vnc_subtlvs, ae2->vnc_subtlvs)
#endif
- && IPV4_ADDR_SAME (&ae1->originator_id, &ae2->originator_id))
+ && IPV4_ADDR_SAME (&ae1->originator_id, &ae2->originator_id)
+ && overlay_index_same(ae1, ae2))
return 1;
else if (ae1 || ae2)
return 0;
@@ -2799,6 +2814,39 @@ bgp_packet_mpattr_start (struct stream *s, afi_t afi, safi_t safi, afi_t nh_afi,
break;
}
break;
+ case AFI_L2VPN:
+ switch (safi)
+ {
+ case SAFI_EVPN:
+ if (attr->extra->mp_nexthop_len == BGP_ATTR_NHLEN_VPNV4)
+ {
+ stream_putc (s, 12);
+ stream_putl (s, 0); /* RD = 0, per RFC */
+ stream_putl (s, 0);
+ stream_put (s, &attr->extra->mp_nexthop_global_in, 4);
+ }
+ else if (attr->extra->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL)
+ {
+ stream_putc (s, 24);
+ stream_putl (s, 0); /* RD = 0, per RFC */
+ stream_putl (s, 0);
+ stream_put (s, &attr->extra->mp_nexthop_global, IPV6_MAX_BYTELEN);
+ }
+ else if (attr->extra->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL)
+ {
+ stream_putc (s, 48);
+ stream_putl (s, 0); /* RD = 0, per RFC */
+ stream_putl (s, 0);
+ stream_put (s, &attr->extra->mp_nexthop_global, IPV6_MAX_BYTELEN);
+ stream_putl (s, 0); /* RD = 0, per RFC */
+ stream_putl (s, 0);
+ stream_put (s, &attr->extra->mp_nexthop_local, IPV6_MAX_BYTELEN);
+ }
+ break;
+ break;
+ default:
+ break;
+ }
default:
break;
}
@@ -2812,7 +2860,7 @@ void
bgp_packet_mpattr_prefix (struct stream *s, afi_t afi, safi_t safi,
struct prefix *p, struct prefix_rd *prd,
u_char *tag, int addpath_encode,
- u_int32_t addpath_tx_id)
+ u_int32_t addpath_tx_id, struct attr *attr)
{
if (safi == SAFI_MPLS_VPN)
{
@@ -2824,6 +2872,10 @@ bgp_packet_mpattr_prefix (struct stream *s, afi_t afi, safi_t safi,
stream_put (s, prd->val, 8);
stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
}
+ else if ((safi == SAFI_EVPN))
+ {
+ bgp_packet_mpattr_route_type_5(s, p, prd, tag, attr);
+ }
else
stream_put_prefix_addpath (s, p, addpath_encode, addpath_tx_id);
}
@@ -2977,7 +3029,7 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
AFI_MAX), /* get from NH */
vecarr, attr);
bgp_packet_mpattr_prefix(s, afi, safi, p, prd, tag,
- addpath_encode, addpath_tx_id);
+ addpath_encode, addpath_tx_id, attr);
bgp_packet_mpattr_end(s, mpattrlen_pos);
}
@@ -3338,8 +3390,9 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
}
- if ((afi == AFI_IP || afi == AFI_IP6) &&
- (safi == SAFI_ENCAP || safi == SAFI_MPLS_VPN))
+ if (((afi == AFI_IP || afi == AFI_IP6) &&
+ (safi == SAFI_ENCAP || safi == SAFI_MPLS_VPN)) ||
+ (afi == AFI_L2VPN && safi == SAFI_EVPN))
{
/* Tunnel Encap attribute */
bgp_packet_mpattr_tea(bgp, peer, s, attr, BGP_ATTR_ENCAP);
@@ -3385,21 +3438,10 @@ void
bgp_packet_mpunreach_prefix (struct stream *s, struct prefix *p,
afi_t afi, safi_t safi, struct prefix_rd *prd,
u_char *tag, int addpath_encode,
- u_int32_t addpath_tx_id)
+ u_int32_t addpath_tx_id, struct attr *attr)
{
- if (safi == SAFI_MPLS_VPN)
- {
- /* addpath TX ID */
- if (addpath_encode)
- stream_putl(s, addpath_tx_id);
-
- stream_putc (s, p->prefixlen + 88);
- stream_put (s, tag, 3);
- stream_put (s, prd->val, 8);
- stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
- }
- else
- stream_put_prefix_addpath (s, p, addpath_encode, addpath_tx_id);
+ return bgp_packet_mpattr_prefix (s, afi, safi, p, prd,
+ tag, addpath_encode, addpath_tx_id, attr);
}
void
diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h
index c5799ccd0d..015039c6cd 100644
--- a/bgpd/bgp_attr.h
+++ b/bgpd/bgp_attr.h
@@ -21,6 +21,8 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#ifndef _QUAGGA_BGP_ATTR_H
#define _QUAGGA_BGP_ATTR_H
+#include "bgp_attr_evpn.h"
+
/* Simple bit mapping. */
#define BITMAP_NBBY 8
@@ -80,6 +82,13 @@ struct bgp_tea_options {
#endif
+/* Overlay Index Info */
+struct overlay_index
+{
+ struct eth_segment_id eth_s_id;
+ union gw_addr gw_ip;
+};
+
/* Additional/uncommon BGP attributes.
* lazily allocated as and when a struct attr
* requires it.
@@ -131,6 +140,8 @@ struct attr_extra
#if ENABLE_BGP_VNC
struct bgp_attr_encap_subtlv *vnc_subtlvs; /* VNC-specific */
#endif
+ /* EVPN */
+ struct overlay_index evpn_overlay;
};
/* BGP core attribute structure. */
@@ -283,7 +294,8 @@ extern size_t bgp_packet_mpattr_start(struct stream *s, afi_t afi, safi_t safi,
extern void bgp_packet_mpattr_prefix(struct stream *s, afi_t afi, safi_t safi,
struct prefix *p, struct prefix_rd *prd,
u_char *tag, int addpath_encode,
- u_int32_t addpath_tx_id);
+ u_int32_t addpath_tx_id,
+ struct attr *);
extern size_t bgp_packet_mpattr_prefix_size(afi_t afi, safi_t safi,
struct prefix *p);
extern void bgp_packet_mpattr_end(struct stream *s, size_t sizep);
@@ -292,7 +304,7 @@ extern size_t bgp_packet_mpunreach_start (struct stream *s, afi_t afi,
safi_t safi);
extern void bgp_packet_mpunreach_prefix (struct stream *s, struct prefix *p,
afi_t afi, safi_t safi, struct prefix_rd *prd,
- u_char *tag, int, u_int32_t);
+ u_char *tag, int, u_int32_t, struct attr *);
extern void bgp_packet_mpunreach_end (struct stream *s, size_t attrlen_pnt);
static inline int
diff --git a/bgpd/bgp_attr_evpn.c b/bgpd/bgp_attr_evpn.c
new file mode 100644
index 0000000000..be97ffda69
--- /dev/null
+++ b/bgpd/bgp_attr_evpn.c
@@ -0,0 +1,141 @@
+/* Ethernet-VPN Attribute handling file
+ Copyright (C) 2016 6WIND
+
+This file is part of Free Range Routing.
+
+Free Range Routing 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.
+
+Free Range Routing 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 Free Range Routing; see the file COPYING. If not, write to the Free
+Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA. */
+
+#include <zebra.h>
+
+#include "command.h"
+#include "filter.h"
+#include "prefix.h"
+#include "log.h"
+#include "memory.h"
+#include "stream.h"
+
+#include "bgpd/bgpd.h"
+#include "bgpd/bgp_attr.h"
+#include "bgpd/bgp_route.h"
+#include "bgpd/bgp_attr_evpn.h"
+#include "bgpd/bgp_ecommunity.h"
+#include "bgpd/bgp_evpn.h"
+
+void bgp_add_routermac_ecom(struct attr *attr, struct ethaddr *routermac)
+{
+ struct ecommunity_val routermac_ecom;
+
+ if (attr->extra) {
+ memset(&routermac_ecom, 0, sizeof(struct ecommunity_val));
+ routermac_ecom.val[0] = ECOMMUNITY_ENCODE_EVPN;
+ routermac_ecom.val[1] = ECOMMUNITY_EVPN_SUBTYPE_ROUTERMAC;
+ memcpy(&routermac_ecom.val[2], routermac->octet, ETHER_ADDR_LEN);
+ if (!attr->extra->ecommunity)
+ attr->extra->ecommunity = ecommunity_new();
+ ecommunity_add_val(attr->extra->ecommunity, &routermac_ecom);
+ ecommunity_str (attr->extra->ecommunity);
+ }
+}
+
+/* converts to an esi
+ * returns 1 on success, 0 otherwise
+ * format accepted: AA:BB:CC:DD:EE:FF:GG:HH:II:JJ
+ * if id is null, check only is done
+ */
+int str2esi(const char *str, struct eth_segment_id *id)
+{
+ unsigned int a[ESI_LEN];
+ int i;
+
+ if (!str)
+ return 0;
+ if (sscanf (str, "%2x:%2x:%2x:%2x:%2x:%2x:%2x:%2x:%2x:%2x",
+ a + 0, a + 1, a + 2, a + 3, a + 4, a + 5,
+ a + 6, a + 7, a + 8, a + 9) != ESI_LEN)
+ {
+ /* error in incoming str length */
+ return 0;
+ }
+ /* valid mac address */
+ if (!id)
+ return 1;
+ for (i = 0; i < ESI_LEN; ++i)
+ id->val[i] = a[i] & 0xff;
+ return 1;
+}
+
+char *esi2str(struct eth_segment_id *id)
+{
+ char *ptr;
+ u_char *val;
+
+ if (!id)
+ return NULL;
+
+ val = id->val;
+ ptr = (char *)XMALLOC(MTYPE_TMP, (ESI_LEN * 2 + ESI_LEN - 1 + 1) * sizeof(char));
+
+ snprintf(ptr, (ESI_LEN * 2 + ESI_LEN - 1 + 1),
+ "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
+ val[0], val[1], val[2], val[3], val[4],
+ val[5], val[6], val[7], val[8], val[9]);
+
+ return ptr;
+}
+
+char *ecom_mac2str(char *ecom_mac)
+{
+ char *en;
+
+ en = ecom_mac;
+ en += 2;
+ return prefix_mac2str((struct ethaddr *)en, NULL, 0);
+}
+
+/* dst prefix must be AF_INET or AF_INET6 prefix, to forge EVPN prefix */
+extern int
+bgp_build_evpn_prefix(int evpn_type, uint32_t eth_tag, struct prefix *dst)
+{
+ struct evpn_addr *p_evpn_p;
+ struct prefix p2;
+ struct prefix *src = &p2;
+
+ if (!dst || dst->family == 0)
+ return -1;
+ /* store initial prefix in src */
+ prefix_copy(src, dst);
+ memset(dst, 0, sizeof(struct prefix));
+ p_evpn_p = &(dst->u.prefix_evpn);
+ dst->family = AF_ETHERNET;
+ p_evpn_p->route_type = evpn_type;
+ if (evpn_type == EVPN_IP_PREFIX) {
+ p_evpn_p->eth_tag = eth_tag;
+ p_evpn_p->ip_prefix_length = p2.prefixlen;
+ if (src->family == AF_INET) {
+ p_evpn_p->flags = IP_PREFIX_V4;
+ memcpy(&p_evpn_p->ip.v4_addr, &src->u.prefix4,
+ sizeof(struct in_addr));
+ dst->prefixlen = (u_char) PREFIX_LEN_ROUTE_TYPE_5_IPV4;
+ } else {
+ p_evpn_p->flags = IP_PREFIX_V6;
+ memcpy(&p_evpn_p->ip.v6_addr, &src->u.prefix6,
+ sizeof(struct in6_addr));
+ dst->prefixlen = (u_char) PREFIX_LEN_ROUTE_TYPE_5_IPV6;
+ }
+ } else
+ return -1;
+ return 0;
+}
diff --git a/bgpd/bgp_attr_evpn.h b/bgpd/bgp_attr_evpn.h
new file mode 100644
index 0000000000..e6da7e7080
--- /dev/null
+++ b/bgpd/bgp_attr_evpn.h
@@ -0,0 +1,59 @@
+/* E-VPN attribute handling structure file
+ Copyright (C) 2016 6WIND
+
+This file is part of Free Range Routing.
+
+Free Range Routing 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.
+
+Free Range Routing 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 Free Range Routing; 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_ATTR_EVPN_H
+#define _QUAGGA_BGP_ATTR_EVPN_H
+
+/* value of first byte of ESI */
+#define ESI_TYPE_ARBITRARY 0 /* */
+#define ESI_TYPE_LACP 1 /* <> */
+#define ESI_TYPE_BRIDGE 2 /* <Root bridge Mac-6B>:<Root Br Priority-2B>:00 */
+#define ESI_TYPE_MAC 3 /* <Syst Mac Add-6B>:<Local Discriminator Value-3B> */
+#define ESI_TYPE_ROUTER 4 /* <RouterId-4B>:<Local Discriminator Value-4B> */
+#define ESI_TYPE_AS 5 /* <AS-4B>:<Local Discriminator Value-4B> */
+#define MAX_ESI {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}
+#define ESI_LEN 10
+
+#define MAX_ET 0xffffffff
+u_long eth_tag_id;
+struct attr;
+
+struct eth_segment_id {
+ u_char val[ESI_LEN];
+};
+
+union gw_addr {
+ struct in_addr ipv4;
+ struct in6_addr ipv6;
+};
+
+struct bgp_route_evpn {
+ struct eth_segment_id eth_s_id;
+ union gw_addr gw_ip;
+};
+
+extern int str2esi(const char *str, struct eth_segment_id *id);
+extern char *esi2str(struct eth_segment_id *id);
+extern char *ecom_mac2str(char *ecom_mac);
+
+extern void bgp_add_routermac_ecom(struct attr *attr, struct ethaddr *routermac);
+extern int bgp_build_evpn_prefix(int type, uint32_t eth_tag,
+ struct prefix *dst);
+#endif /* _QUAGGA_BGP_ATTR_EVPN_H */
diff --git a/bgpd/bgp_clist.c b/bgpd/bgp_clist.c
index b37034bf29..637c95fa7c 100644
--- a/bgpd/bgp_clist.c
+++ b/bgpd/bgp_clist.c
@@ -1166,14 +1166,14 @@ extcommunity_list_set (struct community_list_handler *ch,
}
if (ecom)
- ecom->str = ecommunity_ecom2str (ecom, ECOMMUNITY_FORMAT_DISPLAY);
+ ecom->str = ecommunity_ecom2str (ecom, ECOMMUNITY_FORMAT_DISPLAY, 0);
entry = community_entry_new ();
entry->direct = direct;
entry->style = style;
entry->any = (str ? 0 : 1);
if (ecom)
- entry->config = ecommunity_ecom2str (ecom, ECOMMUNITY_FORMAT_COMMUNITY_LIST);
+ entry->config = ecommunity_ecom2str (ecom, ECOMMUNITY_FORMAT_COMMUNITY_LIST, 0);
else if (regex)
entry->config = XSTRDUP (MTYPE_COMMUNITY_LIST_CONFIG, str);
else
diff --git a/bgpd/bgp_debug.c b/bgpd/bgp_debug.c
index ab05878210..e1e7cb1d5b 100644
--- a/bgpd/bgp_debug.c
+++ b/bgpd/bgp_debug.c
@@ -38,6 +38,9 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "bgpd/bgp_debug.h"
#include "bgpd/bgp_community.h"
#include "bgpd/bgp_updgrp.h"
+#include "bgpd/bgp_mplsvpn.h"
+
+#define BGP_ADDPATH_STR 20
unsigned long conf_bgp_debug_as4;
unsigned long conf_bgp_debug_neighbor_events;
@@ -2086,3 +2089,31 @@ bgp_debug_zebra (struct prefix *p)
return 0;
}
+
+const char *
+bgp_debug_rdpfxpath2str (struct prefix_rd *prd, union prefixconstptr pu,
+ int addpath_valid, u_int32_t addpath_id,
+ char *str, int size)
+{
+ char rd_buf[RD_ADDRSTRLEN];
+ char pfx_buf[PREFIX_STRLEN];
+ char pathid_buf[BGP_ADDPATH_STR];
+
+ if (size < BGP_PRD_PATH_STRLEN)
+ return NULL;
+
+ /* Note: Path-id is created by default, but only included in update sometimes. */
+ pathid_buf[0] = '\0';
+ if (addpath_valid)
+ sprintf(pathid_buf, " with addpath ID %d", addpath_id);
+
+ if (prd)
+ snprintf (str, size, "RD %s %s%s",
+ prefix_rd2str(prd, rd_buf, sizeof (rd_buf)),
+ prefix2str (pu, pfx_buf, sizeof (pfx_buf)), pathid_buf);
+ else
+ snprintf (str, size, "%s%s",
+ prefix2str (pu, pfx_buf, sizeof (pfx_buf)), pathid_buf);
+
+ return str;
+}
diff --git a/bgpd/bgp_debug.h b/bgpd/bgp_debug.h
index 00fb670a47..23ea7b0e52 100644
--- a/bgpd/bgp_debug.h
+++ b/bgpd/bgp_debug.h
@@ -36,6 +36,9 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
/* dump detail */
#define DUMP_DETAIL 32
+/* RD + Prefix + Path-Id */
+#define BGP_PRD_PATH_STRLEN (PREFIX_STRLEN + RD_ADDRSTRLEN + 20)
+
extern int dump_open;
extern int dump_update;
extern int dump_keepalive;
@@ -151,4 +154,6 @@ extern int bgp_debug_bestpath(struct prefix *p);
extern int bgp_debug_zebra(struct prefix *p);
extern int bgp_debug_count(void);
+extern const char *bgp_debug_rdpfxpath2str (struct prefix_rd *, union prefixconstptr,
+ int, u_int32_t, char *, int);
#endif /* _QUAGGA_BGP_DEBUG_H */
diff --git a/bgpd/bgp_ecommunity.c b/bgpd/bgp_ecommunity.c
index 6689883d94..c80966ec6d 100644
--- a/bgpd/bgp_ecommunity.c
+++ b/bgpd/bgp_ecommunity.c
@@ -175,7 +175,7 @@ char *
ecommunity_str (struct ecommunity *ecom)
{
if (! ecom->str)
- ecom->str = ecommunity_ecom2str (ecom, ECOMMUNITY_FORMAT_DISPLAY);
+ ecom->str = ecommunity_ecom2str (ecom, ECOMMUNITY_FORMAT_DISPLAY, 0);
return ecom->str;
}
@@ -213,7 +213,7 @@ ecommunity_intern (struct ecommunity *ecom)
find->refcnt++;
if (! find->str)
- find->str = ecommunity_ecom2str (find, ECOMMUNITY_FORMAT_DISPLAY);
+ find->str = ecommunity_ecom2str (find, ECOMMUNITY_FORMAT_DISPLAY, 0);
return find;
}
@@ -601,9 +601,12 @@ ecommunity_str2com (const char *str, int type, int keyword_included)
ECOMMUNITY_FORMAT_ROUTE_MAP
ECOMMUNITY_FORMAT_COMMUNITY_LIST
ECOMMUNITY_FORMAT_DISPLAY
+
+ Filter is added to display only ECOMMUNITY_ROUTE_TARGET in some cases.
+ 0 value displays all
*/
char *
-ecommunity_ecom2str (struct ecommunity *ecom, int format)
+ecommunity_ecom2str (struct ecommunity *ecom, int format, int filter)
{
int i;
u_int8_t *pnt;
@@ -640,6 +643,7 @@ ecommunity_ecom2str (struct ecommunity *ecom, int format)
/* Prepare buffer. */
str_buf = XMALLOC (MTYPE_ECOMMUNITY_STR, ECOMMUNITY_STR_DEFAULT_LEN + 1);
str_size = ECOMMUNITY_STR_DEFAULT_LEN + 1;
+ str_buf[0] = '\0';
str_pnt = 0;
for (i = 0; i < ecom->size; i++)
@@ -668,6 +672,10 @@ ecommunity_ecom2str (struct ecommunity *ecom, int format)
break;
case ECOMMUNITY_ENCODE_OPAQUE:
+ if(filter == ECOMMUNITY_ROUTE_TARGET)
+ {
+ continue;
+ }
if (*pnt == ECOMMUNITY_OPAQUE_SUBTYPE_ENCAP)
{
uint16_t tunneltype;
@@ -678,8 +686,31 @@ ecommunity_ecom2str (struct ecommunity *ecom, int format)
first = 0;
continue;
}
- /* fall through */
-
+ len = sprintf (str_buf + str_pnt, "?");
+ str_pnt += len;
+ first = 0;
+ continue;
+ case ECOMMUNITY_ENCODE_EVPN:
+ if(filter == ECOMMUNITY_ROUTE_TARGET)
+ {
+ continue;
+ }
+ if (*pnt == ECOMMUNITY_SITE_ORIGIN)
+ {
+ char macaddr[6];
+ pnt++;
+ memcpy(&macaddr, pnt, 6);
+ len = sprintf(str_buf + str_pnt, "EVPN:%02x:%02x:%02x:%02x:%02x:%02x",
+ macaddr[0], macaddr[1], macaddr[2],
+ macaddr[3], macaddr[4], macaddr[5]);
+ str_pnt += len;
+ first = 0;
+ continue;
+ }
+ len = sprintf (str_buf + str_pnt, "?");
+ str_pnt += len;
+ first = 0;
+ continue;
default:
len = sprintf (str_buf + str_pnt, "?");
str_pnt += len;
@@ -791,3 +822,64 @@ ecommunity_match (const struct ecommunity *ecom1,
else
return 0;
}
+
+/* return first occurence of type */
+extern struct ecommunity_val *ecommunity_lookup (const struct ecommunity *ecom, uint8_t type, uint8_t subtype)
+{
+ u_int8_t *p;
+ int c;
+
+ /* If the value already exists in the structure return 0. */
+ c = 0;
+ for (p = ecom->val; c < ecom->size; p += ECOMMUNITY_SIZE, c++)
+ {
+ if(p == NULL)
+ {
+ continue;
+ }
+ if(p[0] == type && p[1] == subtype)
+ return (struct ecommunity_val *)p;
+ }
+ return NULL;
+}
+
+/* remove ext. community matching type and subtype
+ * return 1 on success ( removed ), 0 otherwise (not present)
+ */
+extern int ecommunity_strip (struct ecommunity *ecom, uint8_t type, uint8_t subtype)
+{
+ u_int8_t *p;
+ int c, found = 0;
+ /* When this is fist value, just add it. */
+ if (ecom == NULL || ecom->val == NULL)
+ {
+ return 0;
+ }
+
+ /* If the value already exists in the structure return 0. */
+ c = 0;
+ for (p = ecom->val; c < ecom->size; p += ECOMMUNITY_SIZE, c++)
+ {
+ if (p[0] == type && p[1] == subtype)
+ {
+ found = 1;
+ break;
+ }
+ }
+ if (found == 0)
+ return 0;
+ /* Strip The selected value */
+ ecom->size--;
+ /* size is reduced. no memmove to do */
+ p = XMALLOC (MTYPE_ECOMMUNITY_VAL, ecom->size * ECOMMUNITY_SIZE);
+ if (c != 0)
+ memcpy(p, ecom->val, c * ECOMMUNITY_SIZE);
+ if( (ecom->size - c) != 0)
+ memcpy(p + (c) * ECOMMUNITY_SIZE,
+ ecom->val + (c +1)* ECOMMUNITY_SIZE,
+ (ecom->size - c) * ECOMMUNITY_SIZE);
+ /* shift last ecommunities */
+ XFREE (MTYPE_ECOMMUNITY, ecom->val);
+ ecom->val = p;
+ return 1;
+}
diff --git a/bgpd/bgp_ecommunity.h b/bgpd/bgp_ecommunity.h
index c5c58e4260..356598f6b1 100644
--- a/bgpd/bgp_ecommunity.h
+++ b/bgpd/bgp_ecommunity.h
@@ -26,11 +26,18 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#define ECOMMUNITY_ENCODE_IP 0x01
#define ECOMMUNITY_ENCODE_AS4 0x02
#define ECOMMUNITY_ENCODE_OPAQUE 0x03
+#define ECOMMUNITY_ENCODE_EVPN 0x06
/* Low-order octet of the Extended Communities type field. */
#define ECOMMUNITY_ROUTE_TARGET 0x02
#define ECOMMUNITY_SITE_ORIGIN 0x03
+#define ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY 0x00
+#define ECOMMUNITY_EVPN_SUBTYPE_ESI_LABEL 0x01
+#define ECOMMUNITY_EVPN_SUBTYPE_ES_IMPORT_RT 0x02
+#define ECOMMUNITY_EVPN_SUBTYPE_ROUTERMAC 0x03
+#define ECOMMUNITY_EVPN_SUBTYPE_DEF_GW 0x0d
+
/* Low-order octet of the Extended Communities type field for OPAQUE types */
#define ECOMMUNITY_OPAQUE_SUBTYPE_ENCAP 0x0c
@@ -81,11 +88,15 @@ extern int ecommunity_cmp (const void *, const void *);
extern void ecommunity_unintern (struct ecommunity **);
extern unsigned int ecommunity_hash_make (void *);
extern struct ecommunity *ecommunity_str2com (const char *, int, int);
-extern char *ecommunity_ecom2str (struct ecommunity *, int);
+extern char *ecommunity_ecom2str (struct ecommunity *, int, int);
extern int ecommunity_match (const struct ecommunity *, const struct ecommunity *);
extern char *ecommunity_str (struct ecommunity *);
+extern struct ecommunity_val *ecommunity_lookup (const struct ecommunity *, uint8_t, uint8_t );
+extern int ecommunity_add_val (struct ecommunity *ecom, struct ecommunity_val *eval);
/* for vpn */
extern struct ecommunity *ecommunity_new (void);
extern int ecommunity_add_val (struct ecommunity *, struct ecommunity_val *);
+extern int ecommunity_strip (struct ecommunity *ecom, uint8_t type, uint8_t subtype);
+extern struct ecommunity *ecommunity_new (void);
#endif /* _QUAGGA_BGP_ECOMMUNITY_H */
diff --git a/bgpd/bgp_encap.c b/bgpd/bgp_encap.c
index 4ec45108b4..6e021c4e9e 100644
--- a/bgpd/bgp_encap.c
+++ b/bgpd/bgp_encap.c
@@ -188,10 +188,10 @@ bgp_nlri_parse_encap(
if (attr) {
bgp_update (peer, &p, 0, attr, afi, SAFI_ENCAP,
- ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, NULL, 0);
+ ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, NULL, 0, NULL);
} else {
bgp_withdraw (peer, &p, 0, attr, afi, SAFI_ENCAP,
- ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, NULL);
+ ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, NULL, NULL);
}
}
@@ -219,7 +219,8 @@ DEFUN (encap_network,
int idx_ipv4 = 1;
int idx_rd = 3;
int idx_word = 5;
- return bgp_static_set_safi (SAFI_ENCAP, vty, argv[idx_ipv4]->arg, argv[idx_rd]->arg, argv[idx_word]->arg, NULL);
+ return bgp_static_set_safi (SAFI_ENCAP, vty, argv[idx_ipv4]->arg, argv[idx_rd]->arg, argv[idx_word]->arg,
+ NULL, 0, NULL, NULL, NULL, NULL);
}
/* For testing purpose, static route of ENCAP. */
@@ -237,7 +238,8 @@ DEFUN (no_encap_network,
int idx_ipv4 = 2;
int idx_rd = 4;
int idx_word = 6;
- return bgp_static_unset_safi (SAFI_ENCAP, vty, argv[idx_ipv4]->arg, argv[idx_rd]->arg, argv[idx_word]->arg);
+ return bgp_static_unset_safi (SAFI_ENCAP, vty, argv[idx_ipv4]->arg, argv[idx_rd]->arg, argv[idx_word]->arg,
+ 0, NULL, NULL, NULL);
}
static int
diff --git a/bgpd/bgp_encap_tlv.c b/bgpd/bgp_encap_tlv.c
index 5c18629aa6..8c5ab8d6f6 100644
--- a/bgpd/bgp_encap_tlv.c
+++ b/bgpd/bgp_encap_tlv.c
@@ -391,8 +391,30 @@ bgp_encap_type_vxlan_to_tlv(
struct attr *attr)
{
struct attr_extra *extra = bgp_attr_extra_get(attr);
+ struct bgp_attr_encap_subtlv *tlv;
+ uint32_t vnid;
extra->encap_tunneltype = BGP_ENCAP_TYPE_VXLAN;
+
+ if(bet == NULL ||!bet->vnid)
+ return;
+ if(extra->encap_subtlvs)
+ XFREE(MTYPE_ENCAP_TLV, extra->encap_subtlvs);
+ tlv = XCALLOC (MTYPE_ENCAP_TLV, sizeof(struct bgp_attr_encap_subtlv)-1+12);
+ tlv->type = 1; /* encapsulation type */
+ tlv->length = 12;
+ if(bet->vnid)
+ {
+ vnid = htonl(bet->vnid | VXLAN_ENCAP_MASK_VNID_VALID);
+ memcpy(&tlv->value, &vnid, 4);
+ }
+ if(bet->mac_address)
+ {
+ char *ptr = (char *)&tlv->value + 4;
+ memcpy( ptr, bet->mac_address, 6);
+ }
+ extra->encap_subtlvs = tlv;
+ return;
}
void
diff --git a/bgpd/bgp_encap_types.h b/bgpd/bgp_encap_types.h
index 0985446ff2..04c0d2f235 100644
--- a/bgpd/bgp_encap_types.h
+++ b/bgpd/bgp_encap_types.h
@@ -167,10 +167,15 @@ struct bgp_encap_type_mpls_in_ip_tunnel_with_ipsec_transport_mode {
struct bgp_tea_subtlv_remote_endpoint st_endpoint; /* optional */
};
+#define VXLAN_ENCAP_MASK_VNID_VALID 0x80000000
+#define VXLAN_ENCAP_MASK_MAC_VALID 0x40000000
+
struct bgp_encap_type_vxlan {
uint32_t valid_subtlvs;
struct bgp_tea_subtlv_remote_endpoint st_endpoint; /* optional */
- /* No subtlvs defined in spec? */
+ /* draft-ietf-idr-tunnel-encaps-02 */
+ uint32_t vnid; /* does not include V and M bit */
+ uint8_t *mac_address; /* optional */
};
struct bgp_encap_type_nvgre {
diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c
new file mode 100644
index 0000000000..b9acbbed08
--- /dev/null
+++ b/bgpd/bgp_evpn.c
@@ -0,0 +1,225 @@
+/* Ethernet-VPN Packet and vty Processing File
+ Copyright (C) 2016 6WIND
+
+This file is part of Free Range Routing.
+
+Free Range Routing 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.
+
+Free Range Routing 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 Free Range Routing; see the file COPYING. If not, write to the Free
+Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA. */
+
+#include <zebra.h>
+
+#include "command.h"
+#include "filter.h"
+#include "prefix.h"
+#include "log.h"
+#include "memory.h"
+#include "stream.h"
+
+#include "bgpd/bgp_attr_evpn.h"
+#include "bgpd/bgpd.h"
+#include "bgpd/bgp_table.h"
+#include "bgpd/bgp_route.h"
+#include "bgpd/bgp_attr.h"
+#include "bgpd/bgp_mplsvpn.h"
+#include "bgpd/bgp_evpn.h"
+
+int
+bgp_nlri_parse_evpn(struct peer *peer, struct attr *attr,
+ struct bgp_nlri *packet, int withdraw)
+{
+ u_char *pnt;
+ u_char *lim;
+ struct prefix p;
+ struct prefix_rd prd;
+ struct evpn_addr *p_evpn_p;
+ struct bgp_route_evpn evpn;
+ uint8_t route_type, route_length;
+ u_char *pnt_label;
+ u_int32_t addpath_id = 0;
+
+ /* Check peer status. */
+ if (peer->status != Established)
+ return 0;
+
+ /* Make prefix_rd */
+ prd.family = AF_UNSPEC;
+ prd.prefixlen = 64;
+
+ p_evpn_p = &p.u.prefix_evpn;
+ pnt = packet->nlri;
+ lim = pnt + packet->length;
+ while (pnt < lim) {
+ /* clear evpn structure */
+ memset(&evpn, 0, sizeof(evpn));
+
+ /* Clear prefix structure. */
+ memset(&p, 0, sizeof(struct prefix));
+ memset(&evpn.gw_ip, 0, sizeof(union gw_addr));
+ memset(&evpn.eth_s_id, 0, sizeof(struct eth_segment_id));
+
+ /* Fetch Route Type */
+ route_type = *pnt++;
+ route_length = *pnt++;
+ /* simply ignore. goto next route type if any */
+ if (route_type != EVPN_IP_PREFIX) {
+ if (pnt + route_length > lim) {
+ zlog_err
+ ("not enough bytes for New Route Type left in NLRI?");
+ return -1;
+ }
+ pnt += route_length;
+ continue;
+ }
+
+ /* Fetch RD */
+ if (pnt + 8 > lim) {
+ zlog_err("not enough bytes for RD left in NLRI?");
+ return -1;
+ }
+
+ /* Copy routing distinguisher to rd. */
+ memcpy(&prd.val, pnt, 8);
+ pnt += 8;
+
+ /* Fetch ESI */
+ if (pnt + 10 > lim) {
+ zlog_err("not enough bytes for ESI left in NLRI?");
+ return -1;
+ }
+ memcpy(&evpn.eth_s_id.val, pnt, 10);
+ pnt += 10;
+
+ /* Fetch Ethernet Tag */
+ if (pnt + 4 > lim) {
+ zlog_err("not enough bytes for Eth Tag left in NLRI?");
+ return -1;
+ }
+
+ if (route_type == EVPN_IP_PREFIX) {
+ p_evpn_p->route_type = route_type;
+ memcpy(&(p_evpn_p->eth_tag), pnt, 4);
+ p_evpn_p->eth_tag = ntohl(p_evpn_p->eth_tag);
+ pnt += 4;
+
+ /* Fetch IP prefix length. */
+ p_evpn_p->ip_prefix_length = *pnt++;
+
+ if (p_evpn_p->ip_prefix_length > 128) {
+ zlog_err("invalid prefixlen %d in EVPN NLRI?",
+ p.prefixlen);
+ return -1;
+ }
+ /* determine IPv4 or IPv6 prefix */
+ if (route_length - 4 - 10 - 8 -
+ 3 /* label to be read */ >= 32) {
+ p_evpn_p->flags = IP_PREFIX_V6;
+ memcpy(&(p_evpn_p->ip.v4_addr), pnt, 16);
+ pnt += 16;
+ memcpy(&evpn.gw_ip.ipv6, pnt, 16);
+ pnt += 16;
+ } else {
+ p_evpn_p->flags = IP_PREFIX_V4;
+ memcpy(&(p_evpn_p->ip.v4_addr), pnt, 4);
+ pnt += 4;
+ memcpy(&evpn.gw_ip.ipv4, pnt, 4);
+ pnt += 4;
+ }
+ p.family = AFI_L2VPN;
+ if (p_evpn_p->flags == IP_PREFIX_V4)
+ p.prefixlen =
+ (u_char) PREFIX_LEN_ROUTE_TYPE_5_IPV4;
+ else
+ p.prefixlen = PREFIX_LEN_ROUTE_TYPE_5_IPV6;
+ p.family = AF_ETHERNET;
+ }
+
+ /* Fetch Label */
+ if (pnt + 3 > lim) {
+ zlog_err("not enough bytes for Label left in NLRI?");
+ return -1;
+ }
+ pnt_label = pnt;
+
+ pnt += 3;
+
+ if (!withdraw) {
+ bgp_update(peer, &p, addpath_id, attr, AFI_L2VPN,
+ SAFI_EVPN, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL,
+ &prd, pnt_label, 0, &evpn);
+ } else {
+ bgp_withdraw(peer, &p, addpath_id, attr, AFI_L2VPN,
+ SAFI_EVPN, ZEBRA_ROUTE_BGP,
+ BGP_ROUTE_NORMAL, &prd, pnt_label, &evpn);
+ }
+ }
+
+ /* Packet length consistency check. */
+ if (pnt != lim)
+ return -1;
+ return 0;
+}
+
+void
+bgp_packet_mpattr_route_type_5(struct stream *s,
+ struct prefix *p, struct prefix_rd *prd,
+ u_char * label, struct attr *attr)
+{
+ int len;
+ char temp[16];
+ struct evpn_addr *p_evpn_p;
+
+ memset(&temp, 0, 16);
+ if (p->family != AF_ETHERNET)
+ return;
+ p_evpn_p = &(p->u.prefix_evpn);
+ if (p_evpn_p->flags & IP_PREFIX_V4)
+ len = 8; /* ipv4 */
+ else
+ len = 32; /* ipv6 */
+ stream_putc(s, EVPN_IP_PREFIX);
+ stream_putc(s,
+ 8 /* RD */ + 10 /* ESI */ + 4 /* EthTag */ + 1 + len +
+ 3 /* label */ );
+ stream_put(s, prd->val, 8);
+ if (attr && attr->extra)
+ stream_put(s, &(attr->extra->evpn_overlay.eth_s_id), 10);
+ else
+ stream_put(s, &temp, 10);
+ stream_putl(s, p_evpn_p->eth_tag);
+ stream_putc(s, p_evpn_p->ip_prefix_length);
+ if (p_evpn_p->flags & IP_PREFIX_V4)
+ stream_put_ipv4(s, p_evpn_p->ip.v4_addr.s_addr);
+ else
+ stream_put(s, &p_evpn_p->ip.v6_addr, 16);
+ if (attr && attr->extra) {
+ if (p_evpn_p->flags & IP_PREFIX_V4)
+ stream_put_ipv4(s,
+ attr->extra->evpn_overlay.gw_ip.ipv4.
+ s_addr);
+ else
+ stream_put(s, &(attr->extra->evpn_overlay.gw_ip.ipv6),
+ 16);
+ } else {
+ if (p_evpn_p->flags & IP_PREFIX_V4)
+ stream_put_ipv4(s, 0);
+ else
+ stream_put(s, &temp, 16);
+ }
+ if (label)
+ stream_put(s, label, 3);
+ else
+ stream_put3(s, 0);
+ return;
+}
diff --git a/bgpd/bgp_evpn.h b/bgpd/bgp_evpn.h
new file mode 100644
index 0000000000..63c1a766ea
--- /dev/null
+++ b/bgpd/bgp_evpn.h
@@ -0,0 +1,40 @@
+/* E-VPN header for packet handling
+ Copyright (C) 2016 6WIND
+
+This file is part of Free Range Routing.
+
+Free Range Routing 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.
+
+Free Range Routing 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 Free Range Routing; 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_EVPN_H
+#define _QUAGGA_BGP_EVPN_H
+
+extern int bgp_nlri_parse_evpn(struct peer *peer, struct attr *attr,
+ struct bgp_nlri *packet, int withdraw);
+
+extern void
+bgp_packet_mpattr_route_type_5(struct stream *s,
+ struct prefix *p, struct prefix_rd *prd,
+ u_char * label, struct attr *attr);
+/* EVPN route types as per RFC7432 and
+ * as per draft-ietf-bess-evpn-prefix-advertisement-02
+ */
+#define EVPN_ETHERNET_AUTO_DISCOVERY 1
+#define EVPN_MACIP_ADVERTISEMENT 2
+#define EVPN_INCLUSIVE_MULTICAST_ETHERNET_TAG 3
+#define EVPN_ETHERNET_SEGMENT 4
+#define EVPN_IP_PREFIX 5
+
+#endif /* _QUAGGA_BGP_EVPN_H */
diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c
new file mode 100644
index 0000000000..ed67a61f69
--- /dev/null
+++ b/bgpd/bgp_evpn_vty.c
@@ -0,0 +1,750 @@
+/* Ethernet-VPN Packet and vty Processing File
+ Copyright (C) 2017 6WIND
+
+This file is part of Free Range Routing
+
+Free Range Routing 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.
+
+Free Range Routing 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 Free Range Routing; see the file COPYING. If not, write to the Free
+Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA. */
+
+#include <zebra.h>
+#include "command.h"
+#include "prefix.h"
+#include "lib/json.h"
+
+#include "bgpd/bgpd.h"
+#include "bgpd/bgp_table.h"
+#include "bgpd/bgp_attr.h"
+#include "bgpd/bgp_route.h"
+#include "bgpd/bgp_mplsvpn.h"
+#include "bgpd/bgp_vpn.h"
+#include "bgpd/bgp_evpn_vty.h"
+#include "bgpd/bgp_evpn.h"
+
+#define SHOW_DISPLAY_STANDARD 0
+#define SHOW_DISPLAY_TAGS 1
+#define SHOW_DISPLAY_OVERLAY 2
+
+static int
+bgp_show_ethernet_vpn(struct vty *vty, struct prefix_rd *prd,
+ enum bgp_show_type type, void *output_arg, int option,
+ u_char use_json)
+{
+ afi_t afi = AFI_L2VPN;
+ struct bgp *bgp;
+ struct bgp_table *table;
+ struct bgp_node *rn;
+ struct bgp_node *rm;
+ struct bgp_info *ri;
+ int rd_header;
+ int header = 1;
+ char v4_header[] =
+ " Network Next Hop Metric LocPrf Weight Path%s";
+ char v4_header_tag[] =
+ " Network Next Hop In tag/Out tag%s";
+ char v4_header_overlay[] =
+ " Network Next Hop EthTag Overlay Index RouterMac%s";
+
+ unsigned long output_count = 0;
+ unsigned long total_count = 0;
+ json_object *json = NULL;
+ json_object *json_nroute = NULL;
+ json_object *json_array = NULL;
+ json_object *json_scode = NULL;
+ json_object *json_ocode = NULL;
+
+ bgp = bgp_get_default();
+ if (bgp == NULL) {
+ if (!use_json)
+ vty_out(vty, "No BGP process is configured%s",
+ VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (use_json) {
+ json_scode = json_object_new_object();
+ json_ocode = json_object_new_object();
+ json = json_object_new_object();
+ json_nroute = json_object_new_object();
+
+ json_object_string_add(json_scode, "suppressed", "s");
+ json_object_string_add(json_scode, "damped", "d");
+ json_object_string_add(json_scode, "history", "h");
+ json_object_string_add(json_scode, "valid", "*");
+ json_object_string_add(json_scode, "best", ">");
+ json_object_string_add(json_scode, "internal", "i");
+
+ json_object_string_add(json_ocode, "igp", "i");
+ json_object_string_add(json_ocode, "egp", "e");
+ json_object_string_add(json_ocode, "incomplete", "?");
+ }
+
+ for (rn = bgp_table_top(bgp->rib[afi][SAFI_EVPN]); rn;
+ rn = bgp_route_next(rn)) {
+ if (use_json)
+ continue; /* XXX json TODO */
+
+ if (prd && memcmp(rn->p.u.val, prd->val, 8) != 0)
+ continue;
+
+ if ((table = rn->info) != NULL) {
+ rd_header = 1;
+
+ for (rm = bgp_table_top(table); rm;
+ rm = bgp_route_next(rm))
+ for (ri = rm->info; ri; ri = ri->next) {
+ total_count++;
+ if (type == bgp_show_type_neighbor) {
+ union sockunion *su =
+ output_arg;
+
+ if (ri->peer->su_remote == NULL
+ || !sockunion_same(ri->
+ peer->
+ su_remote,
+ su))
+ continue;
+ }
+ if (header == 0) {
+ if (use_json) {
+ if (option ==
+ SHOW_DISPLAY_TAGS) {
+ json_object_int_add
+ (json,
+ "bgpTableVersion",
+ 0);
+ json_object_string_add
+ (json,
+ "bgpLocalRouterId",
+ inet_ntoa
+ (bgp->
+ router_id));
+ json_object_object_add
+ (json,
+ "bgpStatusCodes",
+ json_scode);
+ json_object_object_add
+ (json,
+ "bgpOriginCodes",
+ json_ocode);
+ }
+ } else {
+ if (option ==
+ SHOW_DISPLAY_TAGS)
+ vty_out(vty,
+ v4_header_tag,
+ VTY_NEWLINE);
+ else if (option ==
+ SHOW_DISPLAY_OVERLAY)
+ vty_out(vty,
+ v4_header_overlay,
+ VTY_NEWLINE);
+ else {
+ vty_out(vty,
+ "BGP table version is 0, local router ID is %s%s",
+ inet_ntoa
+ (bgp->
+ router_id),
+ VTY_NEWLINE);
+ vty_out(vty,
+ "Status codes: s suppressed, d damped, h history, * valid, > best, i - internal%s",
+ VTY_NEWLINE);
+ vty_out(vty,
+ "Origin codes: i - IGP, e - EGP, ? - incomplete%s%s",
+ VTY_NEWLINE,
+ VTY_NEWLINE);
+ vty_out(vty,
+ v4_header,
+ VTY_NEWLINE);
+ }
+ }
+ header = 0;
+ }
+ if (rd_header) {
+ u_int16_t type;
+ struct rd_as rd_as;
+ struct rd_ip rd_ip;
+ u_char *pnt;
+
+ pnt = rn->p.u.val;
+
+ /* Decode RD type. */
+ type = decode_rd_type(pnt);
+ /* Decode RD value. */
+ if (type == RD_TYPE_AS)
+ decode_rd_as(pnt + 2,
+ &rd_as);
+ else if (type == RD_TYPE_AS4)
+ decode_rd_as4(pnt + 2,
+ &rd_as);
+ else if (type == RD_TYPE_IP)
+ decode_rd_ip(pnt + 2,
+ &rd_ip);
+ if (use_json) {
+ char buffer[BUFSIZ];
+ if (type == RD_TYPE_AS
+ || type ==
+ RD_TYPE_AS4)
+ sprintf(buffer,
+ "%u:%d",
+ rd_as.
+ as,
+ rd_as.
+ val);
+ else if (type ==
+ RD_TYPE_IP)
+ sprintf(buffer,
+ "%s:%d",
+ inet_ntoa
+ (rd_ip.
+ ip),
+ rd_ip.
+ val);
+ json_object_string_add
+ (json_nroute,
+ "routeDistinguisher",
+ buffer);
+ } else {
+ vty_out(vty,
+ "Route Distinguisher: ");
+ if (type == RD_TYPE_AS)
+ vty_out(vty,
+ "as2 %u:%d",
+ rd_as.
+ as,
+ rd_as.
+ val);
+ else if (type ==
+ RD_TYPE_AS4)
+ vty_out(vty,
+ "as4 %u:%d",
+ rd_as.
+ as,
+ rd_as.
+ val);
+ else if (type ==
+ RD_TYPE_IP)
+ vty_out(vty,
+ "ip %s:%d",
+ inet_ntoa
+ (rd_ip.
+ ip),
+ rd_ip.
+ val);
+ vty_out(vty, "%s",
+ VTY_NEWLINE);
+ }
+ rd_header = 0;
+ }
+ if (use_json)
+ json_array =
+ json_object_new_array();
+ else
+ json_array = NULL;
+ if (option == SHOW_DISPLAY_TAGS)
+ route_vty_out_tag(vty, &rm->p,
+ ri, 0,
+ SAFI_EVPN,
+ json_array);
+ else if (option == SHOW_DISPLAY_OVERLAY)
+ route_vty_out_overlay(vty,
+ &rm->p,
+ ri, 0,
+ json_array);
+ else
+ route_vty_out(vty, &rm->p, ri,
+ 0, SAFI_EVPN,
+ json_array);
+ output_count++;
+ }
+ /* XXX json */
+ }
+ }
+ if (output_count == 0)
+ vty_out(vty, "No prefixes displayed, %ld exist%s", total_count,
+ VTY_NEWLINE);
+ else
+ vty_out(vty, "%sDisplayed %ld out of %ld total prefixes%s",
+ VTY_NEWLINE, output_count, total_count, VTY_NEWLINE);
+ return CMD_SUCCESS;
+}
+
+DEFUN(show_ip_bgp_l2vpn_evpn,
+ show_ip_bgp_l2vpn_evpn_cmd,
+ "show [ip] bgp l2vpn evpn [json]",
+ SHOW_STR IP_STR BGP_STR L2VPN_HELP_STR EVPN_HELP_STR JSON_STR)
+{
+ return bgp_show_ethernet_vpn(vty, NULL, bgp_show_type_normal, NULL, 0,
+ use_json(argc, argv));
+}
+
+DEFUN(show_ip_bgp_l2vpn_evpn_rd,
+ show_ip_bgp_l2vpn_evpn_rd_cmd,
+ "show [ip] bgp l2vpn evpn rd ASN:nn_or_IP-address:nn [json]",
+ SHOW_STR
+ IP_STR
+ BGP_STR
+ L2VPN_HELP_STR
+ EVPN_HELP_STR
+ "Display information for a route distinguisher\n"
+ "VPN Route Distinguisher\n" JSON_STR)
+{
+ int idx_ext_community = 6;
+ int ret;
+ struct prefix_rd prd;
+
+ ret = str2prefix_rd(argv[idx_ext_community]->arg, &prd);
+ if (!ret) {
+ vty_out(vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ return bgp_show_ethernet_vpn(vty, &prd, bgp_show_type_normal, NULL, 0,
+ use_json(argc, argv));
+}
+
+DEFUN(show_ip_bgp_l2vpn_evpn_all_tags,
+ show_ip_bgp_l2vpn_evpn_all_tags_cmd,
+ "show [ip] bgp l2vpn evpn all tags",
+ SHOW_STR
+ IP_STR
+ BGP_STR
+ L2VPN_HELP_STR
+ EVPN_HELP_STR
+ "Display information about all EVPN NLRIs\n"
+ "Display BGP tags for prefixes\n")
+{
+ return bgp_show_ethernet_vpn(vty, NULL, bgp_show_type_normal, NULL, 1,
+ 0);
+}
+
+DEFUN(show_ip_bgp_l2vpn_evpn_rd_tags,
+ show_ip_bgp_l2vpn_evpn_rd_tags_cmd,
+ "show [ip] bgp l2vpn evpn rd ASN:nn_or_IP-address:nn tags",
+ SHOW_STR
+ IP_STR
+ BGP_STR
+ L2VPN_HELP_STR
+ EVPN_HELP_STR
+ "Display information for a route distinguisher\n"
+ "VPN Route Distinguisher\n" "Display BGP tags for prefixes\n")
+{
+ int idx_ext_community = 6;
+ int ret;
+ struct prefix_rd prd;
+
+ ret = str2prefix_rd(argv[idx_ext_community]->arg, &prd);
+ if (!ret) {
+ vty_out(vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ return bgp_show_ethernet_vpn(vty, &prd, bgp_show_type_normal, NULL, 1,
+ 0);
+}
+
+DEFUN(show_ip_bgp_l2vpn_evpn_all_neighbor_routes,
+ show_ip_bgp_l2vpn_evpn_all_neighbor_routes_cmd,
+ "show [ip] bgp l2vpn evpn all neighbors A.B.C.D routes [json]",
+ SHOW_STR
+ IP_STR
+ BGP_STR
+ L2VPN_HELP_STR
+ EVPN_HELP_STR
+ "Display information about all EVPN NLRIs\n"
+ "Detailed information on TCP and BGP neighbor connections\n"
+ "Neighbor to display information about\n"
+ "Display routes learned from neighbor\n" JSON_STR)
+{
+ int idx_ipv4 = 6;
+ union sockunion su;
+ struct peer *peer;
+ int ret;
+ u_char uj = use_json(argc, argv);
+
+ ret = str2sockunion(argv[idx_ipv4]->arg, &su);
+ if (ret < 0) {
+ if (uj) {
+ json_object *json_no = NULL;
+ json_no = json_object_new_object();
+ json_object_string_add(json_no, "warning",
+ "Malformed address");
+ vty_out(vty, "%s%s",
+ json_object_to_json_string(json_no),
+ VTY_NEWLINE);
+ json_object_free(json_no);
+ } else
+ vty_out(vty, "Malformed address: %s%s",
+ argv[idx_ipv4]->arg, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ peer = peer_lookup(NULL, &su);
+ if (!peer || !peer->afc[AFI_L2VPN][SAFI_EVPN]) {
+ if (uj) {
+ json_object *json_no = NULL;
+ json_no = json_object_new_object();
+ json_object_string_add(json_no, "warning",
+ "No such neighbor or address family");
+ vty_out(vty, "%s%s",
+ json_object_to_json_string(json_no),
+ VTY_NEWLINE);
+ json_object_free(json_no);
+ } else
+ vty_out(vty, "%% No such neighbor or address family%s",
+ VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ return bgp_show_ethernet_vpn(vty, NULL, bgp_show_type_neighbor, &su, 0,
+ uj);
+}
+
+DEFUN(show_ip_bgp_l2vpn_evpn_rd_neighbor_routes,
+ show_ip_bgp_l2vpn_evpn_rd_neighbor_routes_cmd,
+ "show [ip] bgp l2vpn evpn rd ASN:nn_or_IP-address:nn neighbors A.B.C.D routes [json]",
+ SHOW_STR
+ IP_STR
+ BGP_STR
+ L2VPN_HELP_STR
+ EVPN_HELP_STR
+ "Display information for a route distinguisher\n"
+ "VPN Route Distinguisher\n"
+ "Detailed information on TCP and BGP neighbor connections\n"
+ "Neighbor to display information about\n"
+ "Display routes learned from neighbor\n" JSON_STR)
+{
+ int idx_ext_community = 6;
+ int idx_ipv4 = 8;
+ int ret;
+ union sockunion su;
+ struct peer *peer;
+ struct prefix_rd prd;
+ u_char uj = use_json(argc, argv);
+
+ ret = str2prefix_rd(argv[idx_ext_community]->arg, &prd);
+ if (!ret) {
+ if (uj) {
+ json_object *json_no = NULL;
+ json_no = json_object_new_object();
+ json_object_string_add(json_no, "warning",
+ "Malformed Route Distinguisher");
+ vty_out(vty, "%s%s",
+ json_object_to_json_string(json_no),
+ VTY_NEWLINE);
+ json_object_free(json_no);
+ } else
+ vty_out(vty, "%% Malformed Route Distinguisher%s",
+ VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ ret = str2sockunion(argv[idx_ipv4]->arg, &su);
+ if (ret < 0) {
+ if (uj) {
+ json_object *json_no = NULL;
+ json_no = json_object_new_object();
+ json_object_string_add(json_no, "warning",
+ "Malformed address");
+ vty_out(vty, "%s%s",
+ json_object_to_json_string(json_no),
+ VTY_NEWLINE);
+ json_object_free(json_no);
+ } else
+ vty_out(vty, "Malformed address: %s%s",
+ argv[idx_ext_community]->arg, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ peer = peer_lookup(NULL, &su);
+ if (!peer || !peer->afc[AFI_L2VPN][SAFI_EVPN]) {
+ if (uj) {
+ json_object *json_no = NULL;
+ json_no = json_object_new_object();
+ json_object_string_add(json_no, "warning",
+ "No such neighbor or address family");
+ vty_out(vty, "%s%s",
+ json_object_to_json_string(json_no),
+ VTY_NEWLINE);
+ json_object_free(json_no);
+ } else
+ vty_out(vty, "%% No such neighbor or address family%s",
+ VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ return bgp_show_ethernet_vpn(vty, &prd, bgp_show_type_neighbor, &su, 0,
+ uj);
+}
+
+DEFUN(show_ip_bgp_l2vpn_evpn_all_neighbor_advertised_routes,
+ show_ip_bgp_l2vpn_evpn_all_neighbor_advertised_routes_cmd,
+ "show [ip] bgp l2vpn evpn all neighbors A.B.C.D advertised-routes [json]",
+ SHOW_STR
+ IP_STR
+ BGP_STR
+ L2VPN_HELP_STR
+ EVPN_HELP_STR
+ "Display information about all EVPN NLRIs\n"
+ "Detailed information on TCP and BGP neighbor connections\n"
+ "Neighbor to display information about\n"
+ "Display the routes advertised to a BGP neighbor\n" JSON_STR)
+{
+ int idx_ipv4 = 7;
+ int ret;
+ struct peer *peer;
+ union sockunion su;
+ u_char uj = use_json(argc, argv);
+
+ ret = str2sockunion(argv[idx_ipv4]->arg, &su);
+ if (ret < 0) {
+ if (uj) {
+ json_object *json_no = NULL;
+ json_no = json_object_new_object();
+ json_object_string_add(json_no, "warning",
+ "Malformed address");
+ vty_out(vty, "%s%s",
+ json_object_to_json_string(json_no),
+ VTY_NEWLINE);
+ json_object_free(json_no);
+ } else
+ vty_out(vty, "Malformed address: %s%s",
+ argv[idx_ipv4]->arg, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ peer = peer_lookup(NULL, &su);
+ if (!peer || !peer->afc[AFI_L2VPN][SAFI_EVPN]) {
+ if (uj) {
+ json_object *json_no = NULL;
+ json_no = json_object_new_object();
+ json_object_string_add(json_no, "warning",
+ "No such neighbor or address family");
+ vty_out(vty, "%s%s",
+ json_object_to_json_string(json_no),
+ VTY_NEWLINE);
+ json_object_free(json_no);
+ } else
+ vty_out(vty, "%% No such neighbor or address family%s",
+ VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ return show_adj_route_vpn(vty, peer, NULL, AFI_L2VPN, SAFI_EVPN, uj);
+}
+
+DEFUN(show_ip_bgp_l2vpn_evpn_rd_neighbor_advertised_routes,
+ show_ip_bgp_l2vpn_evpn_rd_neighbor_advertised_routes_cmd,
+ "show [ip] bgp l2vpn evpn rd ASN:nn_or_IP-address:nn neighbors A.B.C.D advertised-routes [json]",
+ SHOW_STR
+ IP_STR
+ BGP_STR
+ L2VPN_HELP_STR
+ EVPN_HELP_STR
+ "Display information for a route distinguisher\n"
+ "VPN Route Distinguisher\n"
+ "Detailed information on TCP and BGP neighbor connections\n"
+ "Neighbor to display information about\n"
+ "Display the routes advertised to a BGP neighbor\n" JSON_STR)
+{
+ int idx_ext_community = 6;
+ int idx_ipv4 = 8;
+ int ret;
+ struct peer *peer;
+ struct prefix_rd prd;
+ union sockunion su;
+ u_char uj = use_json(argc, argv);
+
+ ret = str2sockunion(argv[idx_ipv4]->arg, &su);
+ if (ret < 0) {
+ if (uj) {
+ json_object *json_no = NULL;
+ json_no = json_object_new_object();
+ json_object_string_add(json_no, "warning",
+ "Malformed address");
+ vty_out(vty, "%s%s",
+ json_object_to_json_string(json_no),
+ VTY_NEWLINE);
+ json_object_free(json_no);
+ } else
+ vty_out(vty, "Malformed address: %s%s",
+ argv[idx_ext_community]->arg, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ peer = peer_lookup(NULL, &su);
+ if (!peer || !peer->afc[AFI_L2VPN][SAFI_EVPN]) {
+ if (uj) {
+ json_object *json_no = NULL;
+ json_no = json_object_new_object();
+ json_object_string_add(json_no, "warning",
+ "No such neighbor or address family");
+ vty_out(vty, "%s%s",
+ json_object_to_json_string(json_no),
+ VTY_NEWLINE);
+ json_object_free(json_no);
+ } else
+ vty_out(vty, "%% No such neighbor or address family%s",
+ VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ ret = str2prefix_rd(argv[idx_ext_community]->arg, &prd);
+ if (!ret) {
+ if (uj) {
+ json_object *json_no = NULL;
+ json_no = json_object_new_object();
+ json_object_string_add(json_no, "warning",
+ "Malformed Route Distinguisher");
+ vty_out(vty, "%s%s",
+ json_object_to_json_string(json_no),
+ VTY_NEWLINE);
+ json_object_free(json_no);
+ } else
+ vty_out(vty, "%% Malformed Route Distinguisher%s",
+ VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ return show_adj_route_vpn(vty, peer, &prd, AFI_L2VPN, SAFI_EVPN, uj);
+}
+
+DEFUN(show_ip_bgp_l2vpn_evpn_all_overlay,
+ show_ip_bgp_l2vpn_evpn_all_overlay_cmd,
+ "show [ip] bgp l2vpn evpn all overlay",
+ SHOW_STR
+ IP_STR
+ BGP_STR
+ L2VPN_HELP_STR
+ EVPN_HELP_STR
+ "Display information about all EVPN NLRIs\n"
+ "Display BGP Overlay Information for prefixes\n")
+{
+ return bgp_show_ethernet_vpn(vty, NULL, bgp_show_type_normal, NULL,
+ SHOW_DISPLAY_OVERLAY, use_json(argc,
+ argv));
+}
+
+DEFUN(show_ip_bgp_evpn_rd_overlay,
+ show_ip_bgp_evpn_rd_overlay_cmd,
+ "show [ip] bgp l2vpn evpn rd ASN:nn_or_IP-address:nn overlay",
+ SHOW_STR
+ IP_STR
+ BGP_STR
+ L2VPN_HELP_STR
+ EVPN_HELP_STR
+ "Display information for a route distinguisher\n"
+ "VPN Route Distinguisher\n"
+ "Display BGP Overlay Information for prefixes\n")
+{
+ int idx_ext_community = 6;
+ int ret;
+ struct prefix_rd prd;
+
+ ret = str2prefix_rd(argv[idx_ext_community]->arg, &prd);
+ if (!ret) {
+ vty_out(vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ return bgp_show_ethernet_vpn(vty, &prd, bgp_show_type_normal, NULL,
+ SHOW_DISPLAY_OVERLAY, use_json(argc,
+ argv));
+}
+
+/* For testing purpose, static route of MPLS-VPN. */
+DEFUN(evpnrt5_network,
+ evpnrt5_network_cmd,
+ "network <A.B.C.D/M|X:X::X:X/M> rd ASN:nn_or_IP-address:nn ethtag WORD label WORD esi WORD gwip <A.B.C.D|X:X::X:X> routermac WORD [route-map WORD]",
+ "Specify a network to announce via BGP\n"
+ "IP prefix\n"
+ "IPv6 prefix\n"
+ "Specify Route Distinguisher\n"
+ "VPN Route Distinguisher\n"
+ "Ethernet Tag\n"
+ "Ethernet Tag Value\n"
+ "BGP label\n"
+ "label value\n"
+ "Ethernet Segment Identifier\n"
+ "ESI value ( 00:11:22:33:44:55:66:77:88:99 format) \n"
+ "Gateway IP\n"
+ "Gateway IP ( A.B.C.D )\n"
+ "Gateway IPv6 ( X:X::X:X )\n"
+ "Router Mac Ext Comm\n"
+ "Router Mac address Value ( aa:bb:cc:dd:ee:ff format)\n")
+{
+ int idx_ipv4_prefixlen = 1;
+ int idx_ext_community = 3;
+ int idx_word = 7;
+ int idx_esi = 9;
+ int idx_gwip = 11;
+ int idx_ethtag = 5;
+ int idx_routermac = 13;
+ int idx_rmap = 15;
+ return bgp_static_set_safi(SAFI_EVPN, vty,
+ argv[idx_ipv4_prefixlen]->arg,
+ argv[idx_ext_community]->arg,
+ argv[idx_word]->arg,
+ argv[idx_rmap] ? argv[idx_gwip]->arg : NULL,
+ EVPN_IP_PREFIX, argv[idx_esi]->arg,
+ argv[idx_gwip]->arg, argv[idx_ethtag]->arg,
+ argv[idx_routermac]->arg);
+}
+
+/* For testing purpose, static route of MPLS-VPN. */
+DEFUN(no_evpnrt5_network,
+ no_evpnrt5_network_cmd,
+ "no network <A.B.C.D/M|X:X::X:X/M> rd ASN:nn_or_IP-address:nn ethtag WORD label WORD esi WORD gwip <A.B.C.D|X:X::X:X>",
+ NO_STR
+ "Specify a network to announce via BGP\n"
+ "IP prefix\n"
+ "IPv6 prefix\n"
+ "Specify Route Distinguisher\n"
+ "VPN Route Distinguisher\n"
+ "Ethernet Tag\n"
+ "Ethernet Tag Value\n"
+ "BGP label\n"
+ "label value\n"
+ "Ethernet Segment Identifier\n"
+ "ESI value ( 00:11:22:33:44:55:66:77:88:99 format) \n"
+ "Gateway IP\n" "Gateway IP ( A.B.C.D )\n" "Gateway IPv6 ( X:X::X:X )\n")
+{
+ int idx_ipv4_prefixlen = 2;
+ int idx_ext_community = 4;
+ int idx_label = 8;
+ int idx_ethtag = 6;
+ int idx_esi = 10;
+ int idx_gwip = 12;
+ return bgp_static_unset_safi(SAFI_EVPN, vty,
+ argv[idx_ipv4_prefixlen]->arg,
+ argv[idx_ext_community]->arg,
+ argv[idx_label]->arg, EVPN_IP_PREFIX,
+ argv[idx_esi]->arg, argv[idx_gwip]->arg,
+ argv[idx_ethtag]->arg);
+}
+
+void bgp_ethernetvpn_init(void)
+{
+ install_element(VIEW_NODE, &show_ip_bgp_l2vpn_evpn_cmd);
+ install_element(VIEW_NODE, &show_ip_bgp_l2vpn_evpn_rd_cmd);
+ install_element(VIEW_NODE, &show_ip_bgp_l2vpn_evpn_all_tags_cmd);
+ install_element(VIEW_NODE, &show_ip_bgp_l2vpn_evpn_rd_tags_cmd);
+ install_element(VIEW_NODE,
+ &show_ip_bgp_l2vpn_evpn_all_neighbor_routes_cmd);
+ install_element(VIEW_NODE,
+ &show_ip_bgp_l2vpn_evpn_rd_neighbor_routes_cmd);
+ install_element(VIEW_NODE,
+ &show_ip_bgp_l2vpn_evpn_all_neighbor_advertised_routes_cmd);
+ install_element(VIEW_NODE,
+ &show_ip_bgp_l2vpn_evpn_rd_neighbor_advertised_routes_cmd);
+ install_element(VIEW_NODE, &show_ip_bgp_evpn_rd_overlay_cmd);
+ install_element(VIEW_NODE, &show_ip_bgp_l2vpn_evpn_all_overlay_cmd);
+ install_element(BGP_EVPN_NODE, &no_evpnrt5_network_cmd);
+ install_element(BGP_EVPN_NODE, &evpnrt5_network_cmd);
+}
diff --git a/bgpd/bgp_evpn_vty.h b/bgpd/bgp_evpn_vty.h
new file mode 100644
index 0000000000..11e93a5281
--- /dev/null
+++ b/bgpd/bgp_evpn_vty.h
@@ -0,0 +1,29 @@
+/* EVPN VTY functions to EVPN
+ Copyright (C) 2017 6WIND
+
+This file is part of Free Range Routing.
+
+Free Range Routing 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.
+
+Free Range Routing 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 Free Range Routing; see the file COPYING. If not, write to the Free
+Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA. */
+
+#ifndef _FRR_BGP_EVPN_VTY_H
+#define _FRR_BGP_EVPN_VTY_H
+
+extern void bgp_ethernetvpn_init(void);
+
+#define L2VPN_HELP_STR "Layer 2 Virtual Private Network\n"
+#define EVPN_HELP_STR "Ethernet Virtual Private Network\n"
+
+#endif /* _QUAGGA_BGP_EVPN_VTY_H */
diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c
index cfdb9f3ce6..d29fb26030 100644
--- a/bgpd/bgp_mplsvpn.c
+++ b/bgpd/bgp_mplsvpn.c
@@ -36,6 +36,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "bgpd/bgp_mplsvpn.h"
#include "bgpd/bgp_packet.h"
#include "bgpd/bgp_vty.h"
+#include "bgpd/bgp_vpn.h"
#if ENABLE_BGP_VNC
#include "bgpd/rfapi/rfapi_backend.h"
@@ -146,7 +147,7 @@ decode_rd_ip (u_char *pnt, struct rd_ip *rd_ip)
#if ENABLE_BGP_VNC
/* type == RD_TYPE_VNC_ETH */
-static void
+void
decode_rd_vnc_eth (u_char *pnt, struct rd_vnc_eth *rd_vnc_eth)
{
rd_vnc_eth->type = RD_TYPE_VNC_ETH;
@@ -288,12 +289,12 @@ bgp_nlri_parse_vpn (struct peer *peer, struct attr *attr,
if (attr)
{
bgp_update (peer, &p, addpath_id, attr, packet->afi, SAFI_MPLS_VPN,
- ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, tagpnt, 0);
+ ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, tagpnt, 0, NULL);
}
else
{
bgp_withdraw (peer, &p, addpath_id, attr, packet->afi, SAFI_MPLS_VPN,
- ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, tagpnt);
+ ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, tagpnt, NULL);
}
}
/* Packet length consistency check. */
@@ -470,7 +471,8 @@ DEFUN (vpnv4_network,
int idx_ipv4_prefixlen = 1;
int idx_ext_community = 3;
int idx_word = 5;
- return bgp_static_set_safi (SAFI_MPLS_VPN, vty, argv[idx_ipv4_prefixlen]->arg, argv[idx_ext_community]->arg, argv[idx_word]->arg, NULL);
+ return bgp_static_set_safi (SAFI_MPLS_VPN, vty, argv[idx_ipv4_prefixlen]->arg, argv[idx_ext_community]->arg,
+ argv[idx_word]->arg, NULL, 0, NULL, NULL, NULL, NULL);
}
DEFUN (vpnv4_network_route_map,
@@ -489,7 +491,8 @@ DEFUN (vpnv4_network_route_map,
int idx_ext_community = 3;
int idx_word = 5;
int idx_word_2 = 7;
- return bgp_static_set_safi (SAFI_MPLS_VPN, vty, argv[idx_ipv4_prefixlen]->arg, argv[idx_ext_community]->arg, argv[idx_word]->arg, argv[idx_word_2]->arg);
+ return bgp_static_set_safi (SAFI_MPLS_VPN, vty, argv[idx_ipv4_prefixlen]->arg, argv[idx_ext_community]->arg, argv[idx_word]->arg,
+ argv[idx_word_2]->arg, 0, NULL, NULL, NULL, NULL);
}
/* For testing purpose, static route of MPLS-VPN. */
@@ -507,7 +510,9 @@ DEFUN (no_vpnv4_network,
int idx_ipv4_prefixlen = 2;
int idx_ext_community = 4;
int idx_word = 6;
- return bgp_static_unset_safi (SAFI_MPLS_VPN, vty, argv[idx_ipv4_prefixlen]->arg, argv[idx_ext_community]->arg, argv[idx_word]->arg);
+ return bgp_static_unset_safi (SAFI_MPLS_VPN, vty, argv[idx_ipv4_prefixlen]->arg,
+ argv[idx_ext_community]->arg, argv[idx_word]->arg,
+ 0, NULL, NULL, NULL);
}
DEFUN (vpnv6_network,
@@ -527,9 +532,9 @@ DEFUN (vpnv6_network,
int idx_word = 5;
int idx_word_2 = 7;
if (argv[idx_word_2])
- return bgp_static_set_safi (SAFI_MPLS_VPN, vty, argv[idx_ipv6_prefix]->arg, argv[idx_ext_community]->arg, argv[idx_word]->arg, argv[idx_word_2]->arg);
+ return bgp_static_set_safi (SAFI_MPLS_VPN, vty, argv[idx_ipv6_prefix]->arg, argv[idx_ext_community]->arg, argv[idx_word]->arg, argv[idx_word_2]->arg, 0, NULL, NULL, NULL, NULL);
else
- return bgp_static_set_safi (SAFI_MPLS_VPN, vty, argv[idx_ipv6_prefix]->arg, argv[idx_ext_community]->arg, argv[idx_word]->arg, NULL);
+ return bgp_static_set_safi (SAFI_MPLS_VPN, vty, argv[idx_ipv6_prefix]->arg, argv[idx_ext_community]->arg, argv[idx_word]->arg, NULL, 0, NULL, NULL, NULL, NULL);
}
/* For testing purpose, static route of MPLS-VPN. */
@@ -547,178 +552,9 @@ DEFUN (no_vpnv6_network,
int idx_ipv6_prefix = 2;
int idx_ext_community = 4;
int idx_word = 6;
- return bgp_static_unset_safi (SAFI_MPLS_VPN, vty, argv[idx_ipv6_prefix]->arg, argv[idx_ext_community]->arg, argv[idx_word]->arg);
+ return bgp_static_unset_safi (SAFI_MPLS_VPN, vty, argv[idx_ipv6_prefix]->arg, argv[idx_ext_community]->arg, argv[idx_word]->arg, 0, NULL, NULL, NULL);
}
-#if defined(KEEP_OLD_VPN_COMMANDS)
-static int
-show_adj_route_vpn (struct vty *vty, struct peer *peer, struct prefix_rd *prd, u_char use_json, afi_t afi)
-{
- struct bgp *bgp;
- struct bgp_table *table;
- struct bgp_node *rn;
- struct bgp_node *rm;
- struct attr *attr;
- int rd_header;
- int header = 1;
- char v4_header[] = " Network Next Hop Metric LocPrf Weight Path%s";
- json_object *json = NULL;
- json_object *json_scode = NULL;
- json_object *json_ocode = NULL;
- json_object *json_routes = NULL;
- json_object *json_array = NULL;
-
- bgp = bgp_get_default ();
- if (bgp == NULL)
- {
- if (!use_json)
- vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- if (use_json)
- {
- json_scode = json_object_new_object();
- json_ocode = json_object_new_object();
- json_routes = json_object_new_object();
- json = json_object_new_object();
-
- json_object_string_add(json_scode, "suppressed", "s");
- json_object_string_add(json_scode, "damped", "d");
- json_object_string_add(json_scode, "history", "h");
- json_object_string_add(json_scode, "valid", "*");
- json_object_string_add(json_scode, "best", ">");
- json_object_string_add(json_scode, "internal", "i");
-
- json_object_string_add(json_ocode, "igp", "i");
- json_object_string_add(json_ocode, "egp", "e");
- json_object_string_add(json_ocode, "incomplete", "?");
- }
-
- for (rn = bgp_table_top (bgp->rib[afi][SAFI_MPLS_VPN]); rn;
- rn = bgp_route_next (rn))
- {
- if (prd && memcmp (rn->p.u.val, prd->val, 8) != 0)
- continue;
-
- if ((table = rn->info) != NULL)
- {
- if (use_json)
- json_array = json_object_new_array();
- else
- json_array = NULL;
-
- rd_header = 1;
-
- for (rm = bgp_table_top (table); rm; rm = bgp_route_next (rm))
- {
- if ((attr = rm->info) != NULL)
- {
- if (header)
- {
- if (use_json)
- {
- json_object_int_add(json, "bgpTableVersion", 0);
- json_object_string_add(json, "bgpLocalRouterId", inet_ntoa (bgp->router_id));
- json_object_object_add(json, "bgpStatusCodes", json_scode);
- json_object_object_add(json, "bgpOriginCodes", json_ocode);
- }
- else
- {
- vty_out (vty, "BGP table version is 0, local router ID is %s%s",
- inet_ntoa (bgp->router_id), VTY_NEWLINE);
- vty_out (vty, "Status codes: s suppressed, d damped, h history, * valid, > best, i - internal%s",
- VTY_NEWLINE);
- vty_out (vty, "Origin codes: i - IGP, e - EGP, ? - incomplete%s%s",
- VTY_NEWLINE, VTY_NEWLINE);
- vty_out (vty, v4_header, VTY_NEWLINE);
- }
- header = 0;
- }
-
- if (rd_header)
- {
- u_int16_t type;
- struct rd_as rd_as;
- struct rd_ip rd_ip = {0};
-#if ENABLE_BGP_VNC
- struct rd_vnc_eth rd_vnc_eth = {0};
-#endif
- u_char *pnt;
-
- pnt = rn->p.u.val;
-
- /* Decode RD type. */
- type = decode_rd_type (pnt);
- /* Decode RD value. */
- if (type == RD_TYPE_AS)
- decode_rd_as (pnt + 2, &rd_as);
- else if (type == RD_TYPE_AS4)
- decode_rd_as4 (pnt + 2, &rd_as);
- else if (type == RD_TYPE_IP)
- decode_rd_ip (pnt + 2, &rd_ip);
-#if ENABLE_BGP_VNC
- else if (type == RD_TYPE_VNC_ETH)
- decode_rd_vnc_eth (pnt, &rd_vnc_eth);
-#endif
-
- if (use_json)
- {
- char buffer[BUFSIZ];
- if (type == RD_TYPE_AS || type == RD_TYPE_AS4)
- sprintf (buffer, "%u:%d", rd_as.as, rd_as.val);
- else if (type == RD_TYPE_IP)
- sprintf (buffer, "%s:%d", inet_ntoa (rd_ip.ip), rd_ip.val);
- json_object_string_add(json_routes, "routeDistinguisher", buffer);
- }
- else
- {
- vty_out (vty, "Route Distinguisher: ");
-
- if (type == RD_TYPE_AS || type == RD_TYPE_AS4)
- vty_out (vty, "%u:%d", rd_as.as, rd_as.val);
- else if (type == RD_TYPE_IP)
- vty_out (vty, "%s:%d", inet_ntoa (rd_ip.ip), rd_ip.val);
-#if ENABLE_BGP_VNC
- else if (type == RD_TYPE_VNC_ETH)
- vty_out (vty, "%u:%02x:%02x:%02x:%02x:%02x:%02x",
- rd_vnc_eth.local_nve_id,
- rd_vnc_eth.macaddr.octet[0],
- rd_vnc_eth.macaddr.octet[1],
- rd_vnc_eth.macaddr.octet[2],
- rd_vnc_eth.macaddr.octet[3],
- rd_vnc_eth.macaddr.octet[4],
- rd_vnc_eth.macaddr.octet[5]);
-#endif
-
- vty_out (vty, "%s", VTY_NEWLINE);
- }
- rd_header = 0;
- }
- route_vty_out_tmp (vty, &rm->p, attr, SAFI_MPLS_VPN, use_json, json_array);
- }
- }
- if (use_json)
- {
- struct prefix *p;
- char buf_a[BUFSIZ];
- char buf_b[BUFSIZ];
- p = &rm->p;
- sprintf(buf_a, "%s/%d", inet_ntop (p->family, &p->u.prefix, buf_b, BUFSIZ), p->prefixlen);
- json_object_object_add(json_routes, buf_a, json_array);
- }
- }
- }
- if (use_json)
- {
- json_object_object_add(json, "routes", json_routes);
- vty_out (vty, "%s%s", json_object_to_json_string_ext(json, JSON_C_TO_STRING_PRETTY), VTY_NEWLINE);
- json_object_free(json);
- }
- return CMD_SUCCESS;
-}
-#endif
-
int
bgp_show_mpls_vpn (struct vty *vty, afi_t afi, struct prefix_rd *prd,
enum bgp_show_type type, void *output_arg, int tags, u_char use_json)
@@ -1281,8 +1117,7 @@ DEFUN (show_ip_bgp_vpn_all_neighbor_advertised_routes,
vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE);
return CMD_WARNING;
}
-
- return show_adj_route_vpn (vty, peer, NULL, uj, afi);
+ return show_adj_route_vpn (vty, peer, NULL, AFI_IP, SAFI_MPLS_VPN, uj);
}
return CMD_SUCCESS;
}
@@ -1360,7 +1195,7 @@ DEFUN (show_ip_bgp_vpn_rd_neighbor_advertised_routes,
return CMD_WARNING;
}
- return show_adj_route_vpn (vty, peer, &prd, uj, afi);
+ return show_adj_route_vpn (vty, peer, &prd, AFI_IP, SAFI_MPLS_VPN, uj);
}
return CMD_SUCCESS;
}
diff --git a/bgpd/bgp_mplsvpn.h b/bgpd/bgp_mplsvpn.h
index 148e5946f1..518bf6143f 100644
--- a/bgpd/bgp_mplsvpn.h
+++ b/bgpd/bgp_mplsvpn.h
@@ -100,7 +100,8 @@ extern void decode_rd_as (u_char *, struct rd_as *);
extern void decode_rd_as4 (u_char *, struct rd_as *);
extern void decode_rd_ip (u_char *, struct rd_ip *);
#if ENABLE_BGP_VNC
-extern void decode_vnc_eth (u_char *, struct rd_vnc_eth *);
+extern void
+decode_rd_vnc_eth (u_char *pnt, struct rd_vnc_eth *rd_vnc_eth);
#endif
extern int str2prefix_rd (const char *, struct prefix_rd *);
extern int str2tag (const char *, u_char *);
diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c
index 7dbb439be1..51079f31e0 100644
--- a/bgpd/bgp_open.c
+++ b/bgpd/bgp_open.c
@@ -93,6 +93,9 @@ bgp_capability_vty_out (struct vty *vty, struct peer *peer, u_char use_json, jso
case AFI_IP6:
json_object_string_add(json_cap, "capabilityErrorMultiProtocolAfi", "IPv6");
break;
+ case AFI_L2VPN:
+ json_object_string_add(json_cap, "capabilityErrorMultiProtocolAfi", "L2VPN");
+ break;
default:
json_object_int_add(json_cap, "capabilityErrorMultiProtocolAfiUnknown", ntohs (mpc.afi));
break;
@@ -111,6 +114,9 @@ bgp_capability_vty_out (struct vty *vty, struct peer *peer, u_char use_json, jso
case SAFI_ENCAP:
json_object_string_add(json_cap, "capabilityErrorMultiProtocolSafi", "encap");
break;
+ case SAFI_EVPN:
+ json_object_string_add(json_cap, "capabilityErrorMultiProtocolSafi", "EVPN");
+ break;
default:
json_object_int_add(json_cap, "capabilityErrorMultiProtocolSafiUnknown", mpc.safi);
break;
@@ -127,6 +133,9 @@ bgp_capability_vty_out (struct vty *vty, struct peer *peer, u_char use_json, jso
case AFI_IP6:
vty_out (vty, "AFI IPv6, ");
break;
+ case AFI_L2VPN:
+ vty_out (vty, "AFI L2VPN, ");
+ break;
default:
vty_out (vty, "AFI Unknown %d, ", ntohs (mpc.afi));
break;
@@ -145,6 +154,9 @@ bgp_capability_vty_out (struct vty *vty, struct peer *peer, u_char use_json, jso
case SAFI_ENCAP:
vty_out (vty, "SAFI ENCAP");
break;
+ case SAFI_EVPN:
+ vty_out (vty, "SAFI EVPN");
+ break;
default:
vty_out (vty, "SAFI Unknown %d ", mpc.safi);
break;
@@ -1136,7 +1148,8 @@ bgp_open_option_parse (struct peer *peer, u_char length, int *mp_capability)
&& ! peer->afc_nego[AFI_IP6][SAFI_UNICAST]
&& ! peer->afc_nego[AFI_IP6][SAFI_MULTICAST]
&& ! peer->afc_nego[AFI_IP6][SAFI_MPLS_VPN]
- && ! peer->afc_nego[AFI_IP6][SAFI_ENCAP])
+ && ! peer->afc_nego[AFI_IP6][SAFI_ENCAP]
+ && ! peer->afc_nego[AFI_L2VPN][SAFI_EVPN])
{
zlog_err ("%s [Error] Configured AFI/SAFIs do not "
"overlap with received MP capabilities",
diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c
index 2df22ab568..0dbf41a4a1 100644
--- a/bgpd/bgp_packet.c
+++ b/bgpd/bgp_packet.c
@@ -49,7 +49,9 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "bgpd/bgp_lcommunity.h"
#include "bgpd/bgp_network.h"
#include "bgpd/bgp_mplsvpn.h"
+#include "bgpd/bgp_evpn.h"
#include "bgpd/bgp_encap.h"
+#include "bgpd/bgp_evpn.h"
#include "bgpd/bgp_advertise.h"
#include "bgpd/bgp_vty.h"
#include "bgpd/bgp_updgrp.h"
@@ -246,13 +248,13 @@ bgp_write_packet (struct peer *peer)
if (!(PAF_SUBGRP(paf))->t_coalesce &&
peer->afc_nego[afi][safi] && peer->synctime
&& ! CHECK_FLAG (peer->af_sflags[afi][safi],
- PEER_STATUS_EOR_SEND))
+ PEER_STATUS_EOR_SEND)
+ && safi != SAFI_EVPN)
{
SET_FLAG (peer->af_sflags[afi][safi],
PEER_STATUS_EOR_SEND);
return bgp_update_packet_eor (peer, afi, safi);
}
-
}
continue;
}
@@ -1327,19 +1329,24 @@ bgp_update_explicit_eors (struct peer *peer)
bgp_check_update_delay(peer->bgp);
}
-/* Frontend for NLRI parsing, to fan-out to AFI/SAFI specific parsers */
+/* Frontend for NLRI parsing, to fan-out to AFI/SAFI specific parsers
+ * mp_withdraw, if set, is used to nullify attr structure on most of the calling safi function
+ * and for evpn, passed as parameter
+ */
int
-bgp_nlri_parse (struct peer *peer, struct attr *attr, struct bgp_nlri *packet)
+bgp_nlri_parse (struct peer *peer, struct attr *attr, struct bgp_nlri *packet, int mp_withdraw)
{
switch (packet->safi)
{
case SAFI_UNICAST:
case SAFI_MULTICAST:
- return bgp_nlri_parse_ip (peer, attr, packet);
+ return bgp_nlri_parse_ip (peer, mp_withdraw?NULL:attr, packet);
case SAFI_MPLS_VPN:
- return bgp_nlri_parse_vpn (peer, attr, packet);
+ return bgp_nlri_parse_vpn (peer, mp_withdraw?NULL:attr, packet);
case SAFI_ENCAP:
- return bgp_nlri_parse_encap (peer, attr, packet);
+ return bgp_nlri_parse_encap (peer, mp_withdraw?NULL:attr, packet);
+ case SAFI_EVPN:
+ return bgp_nlri_parse_evpn (peer, attr, packet, mp_withdraw);
}
return -1;
}
@@ -1531,11 +1538,11 @@ bgp_update_receive (struct peer *peer, bgp_size_t size)
{
case NLRI_UPDATE:
case NLRI_MP_UPDATE:
- nlri_ret = bgp_nlri_parse (peer, NLRI_ATTR_ARG, &nlris[i]);
+ nlri_ret = bgp_nlri_parse (peer, NLRI_ATTR_ARG, &nlris[i], 0);
break;
case NLRI_WITHDRAW:
case NLRI_MP_WITHDRAW:
- nlri_ret = bgp_nlri_parse (peer, NULL, &nlris[i]);
+ nlri_ret = bgp_nlri_parse (peer, &attr, &nlris[i], 1);
break;
default:
nlri_ret = -1;
diff --git a/bgpd/bgp_packet.h b/bgpd/bgp_packet.h
index 78855c3425..ea5c7a8998 100644
--- a/bgpd/bgp_packet.h
+++ b/bgpd/bgp_packet.h
@@ -55,7 +55,7 @@ extern void bgp_default_withdraw_send (struct peer *, afi_t, safi_t);
extern int bgp_capability_receive (struct peer *, bgp_size_t);
-extern int bgp_nlri_parse (struct peer *, struct attr *, struct bgp_nlri *);
+extern int bgp_nlri_parse (struct peer *, struct attr *, struct bgp_nlri *, int mp_withdraw);
extern void bgp_update_restarted_peers (struct peer *);
extern void bgp_update_implicit_eors (struct peer *);
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index 0123ed17ea..55823a272f 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -68,6 +68,11 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "bgpd/rfapi/vnc_import_bgp.h"
#include "bgpd/rfapi/vnc_export_bgp.h"
#endif
+#include "bgpd/bgp_encap_types.h"
+#include "bgpd/bgp_encap_tlv.h"
+#include "bgpd/bgp_evpn.h"
+#include "bgpd/bgp_evpn_vty.h"
+
/* Extern from bgp_dump.c */
extern const char *bgp_origin_str[];
@@ -84,7 +89,8 @@ bgp_afi_node_get (struct bgp_table *table, afi_t afi, safi_t safi, struct prefix
if (!table)
return NULL;
- if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP))
+ if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP) ||
+ (safi == SAFI_EVPN))
{
prn = bgp_node_get (table, (struct prefix *) prd);
@@ -97,7 +103,8 @@ bgp_afi_node_get (struct bgp_table *table, afi_t afi, safi_t safi, struct prefix
rn = bgp_node_get (table, p);
- if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP))
+ if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP) ||
+ (safi == SAFI_EVPN))
rn->prn = prn;
return rn;
@@ -1190,7 +1197,7 @@ subgroup_announce_check (struct bgp_info *ri, struct update_subgroup *subgrp,
struct bgp *bgp;
struct attr *riattr;
struct peer_af *paf;
- char buf[SU_ADDRSTRLEN];
+ char buf[PREFIX_STRLEN];
int ret;
int transparent;
int reflect;
@@ -1222,8 +1229,7 @@ subgroup_announce_check (struct bgp_info *ri, struct update_subgroup *subgrp,
* direct and direct_ext type routes originate internally even
* though they can have peer pointers that reference other systems
*/
- char buf[BUFSIZ];
- prefix2str(p, buf, BUFSIZ);
+ prefix2str(p, buf, PREFIX_STRLEN);
zlog_debug("%s: pfx %s bgp_direct->vpn route peer safe", __func__, buf);
samepeer_safe = 1;
}
@@ -1293,11 +1299,9 @@ subgroup_announce_check (struct bgp_info *ri, struct update_subgroup *subgrp,
(IPV4_ADDR_SAME (&onlypeer->remote_id, &riattr->extra->originator_id)))
{
if (bgp_debug_update(NULL, p, subgrp->update_group, 0))
- zlog_debug ("%s [Update:SEND] %s/%d originator-id is same as "
+ zlog_debug ("%s [Update:SEND] %s originator-id is same as "
"remote router-id",
- onlypeer->host,
- inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
- p->prefixlen);
+ onlypeer->host, prefix2str (p, buf, sizeof (buf)));
return 0;
}
@@ -1311,10 +1315,8 @@ subgroup_announce_check (struct bgp_info *ri, struct update_subgroup *subgrp,
if (prefix_list_apply (peer->orf_plist[afi][safi], p) == PREFIX_DENY)
{
if (bgp_debug_update(NULL, p, subgrp->update_group, 0))
- zlog_debug ("%s [Update:SEND] %s/%d is filtered via ORF",
- peer->host,
- inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
- p->prefixlen);
+ zlog_debug ("%s [Update:SEND] %s is filtered via ORF",
+ peer->host, prefix2str (p, buf, sizeof (buf)));
return 0;
}
}
@@ -1323,10 +1325,8 @@ subgroup_announce_check (struct bgp_info *ri, struct update_subgroup *subgrp,
if (bgp_output_filter (peer, p, riattr, afi, safi) == FILTER_DENY)
{
if (bgp_debug_update(NULL, p, subgrp->update_group, 0))
- zlog_debug ("%s [Update:SEND] %s/%d is filtered",
- peer->host,
- inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
- p->prefixlen);
+ zlog_debug ("%s [Update:SEND] %s is filtered",
+ peer->host, prefix2str (p, buf, sizeof (buf)));
return 0;
}
@@ -2276,12 +2276,66 @@ info_make (int type, int sub_type, u_short instance, struct peer *peer, struct a
}
static void
-bgp_info_addpath_rx_str(u_int32_t addpath_id, char *buf)
+overlay_index_update(struct attr *attr, struct eth_segment_id *eth_s_id, union gw_addr *gw_ip)
{
- if (addpath_id)
- sprintf(buf, " with addpath ID %d", addpath_id);
+ struct attr_extra *extra;
+
+ if(!attr)
+ return;
+ extra = bgp_attr_extra_get(attr);
+
+ if(eth_s_id == NULL)
+ {
+ memset(&(extra->evpn_overlay.eth_s_id),0, sizeof(struct eth_segment_id));
+ }
+ else
+ {
+ memcpy(&(extra->evpn_overlay.eth_s_id), eth_s_id, sizeof(struct eth_segment_id));
+ }
+ if(gw_ip == NULL)
+ {
+ memset(&(extra->evpn_overlay.gw_ip), 0, sizeof(union gw_addr));
+ }
+ else
+ {
+ memcpy(&(extra->evpn_overlay.gw_ip),gw_ip, sizeof(union gw_addr));
+ }
}
+static bool
+overlay_index_equal(afi_t afi, struct bgp_info *info, struct eth_segment_id *eth_s_id, union gw_addr *gw_ip)
+{
+ struct eth_segment_id *info_eth_s_id, *info_eth_s_id_remote;
+ union gw_addr *info_gw_ip, *info_gw_ip_remote;
+ char temp[16];
+
+ if(afi != AFI_L2VPN)
+ return true;
+ if (!info->attr || !info->attr->extra)
+ {
+ memset(&temp, 0, 16);
+ info_eth_s_id = (struct eth_segment_id *)&temp;
+ info_gw_ip = (union gw_addr *)&temp;
+ if(eth_s_id == NULL && gw_ip == NULL)
+ return true;
+ }
+ else
+ {
+ info_eth_s_id = &(info->attr->extra->evpn_overlay.eth_s_id);
+ info_gw_ip = &(info->attr->extra->evpn_overlay.gw_ip);
+ }
+ if(gw_ip == NULL)
+ info_gw_ip_remote = (union gw_addr *)&temp;
+ else
+ info_gw_ip_remote = gw_ip;
+ if(eth_s_id == NULL)
+ info_eth_s_id_remote = (struct eth_segment_id *)&temp;
+ else
+ info_eth_s_id_remote = eth_s_id;
+ if(!memcmp(info_gw_ip, info_gw_ip_remote, sizeof(union gw_addr)))
+ return false;
+ return !memcmp(info_eth_s_id, info_eth_s_id_remote, sizeof(struct eth_segment_id));
+}
/* Check if received nexthop is valid or not. */
static int
@@ -2339,7 +2393,7 @@ int
bgp_update (struct peer *peer, struct prefix *p, u_int32_t addpath_id,
struct attr *attr, afi_t afi, safi_t safi, int type,
int sub_type, struct prefix_rd *prd, u_char *tag,
- int soft_reconfig)
+ int soft_reconfig, struct bgp_route_evpn* evpn)
{
int ret;
int aspath_loop_count = 0;
@@ -2351,8 +2405,7 @@ bgp_update (struct peer *peer, struct prefix *p, u_int32_t addpath_id,
struct bgp_info *ri;
struct bgp_info *new;
const char *reason;
- char buf[SU_ADDRSTRLEN];
- char buf2[30];
+ char pfx_buf[BGP_PRD_PATH_STRLEN];
int connected = 0;
int do_loop_check = 1;
#if ENABLE_BGP_VNC
@@ -2462,20 +2515,18 @@ bgp_update (struct peer *peer, struct prefix *p, u_int32_t addpath_id,
/* Same attribute comes in. */
if (!CHECK_FLAG (ri->flags, BGP_INFO_REMOVED)
- && attrhash_cmp (ri->attr, attr_new))
+ && attrhash_cmp (ri->attr, attr_new)
+ && (overlay_index_equal(afi, ri, evpn==NULL?NULL:&evpn->eth_s_id,
+ evpn==NULL?NULL:&evpn->gw_ip)))
{
if (CHECK_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING)
&& peer->sort == BGP_PEER_EBGP
&& CHECK_FLAG (ri->flags, BGP_INFO_HISTORY))
{
if (bgp_debug_update(peer, p, NULL, 1))
- {
- bgp_info_addpath_rx_str(addpath_id, buf2);
- zlog_debug ("%s rcvd %s/%d%s",
- peer->host,
- inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
- p->prefixlen, buf2);
- }
+ zlog_debug ("%s rcvd %s", peer->host,
+ bgp_debug_rdpfxpath2str (prd, p, addpath_id ? 1 : 0,
+ addpath_id, pfx_buf, sizeof (pfx_buf)));
if (bgp_damp_update (ri, rn, afi, safi) != BGP_DAMP_SUPPRESSED)
{
@@ -2493,11 +2544,10 @@ bgp_update (struct peer *peer, struct prefix *p, u_int32_t addpath_id,
peer->rcvd_attr_printed = 1;
}
- bgp_info_addpath_rx_str(addpath_id, buf2);
- zlog_debug ("%s rcvd %s/%d%s...duplicate ignored",
+ zlog_debug ("%s rcvd %s...duplicate ignored",
peer->host,
- inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
- p->prefixlen, buf2);
+ bgp_debug_rdpfxpath2str (prd, p, addpath_id ?
+ 1 : 0, addpath_id, pfx_buf, sizeof (pfx_buf)));
}
/* graceful restart STALE flag unset. */
@@ -2518,25 +2568,18 @@ bgp_update (struct peer *peer, struct prefix *p, u_int32_t addpath_id,
if (CHECK_FLAG(ri->flags, BGP_INFO_REMOVED))
{
if (bgp_debug_update(peer, p, NULL, 1))
- {
- bgp_info_addpath_rx_str(addpath_id, buf2);
- zlog_debug ("%s rcvd %s/%d%s, flapped quicker than processing",
- peer->host,
- inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
- p->prefixlen, buf2);
- }
+ zlog_debug ("%s rcvd %s, flapped quicker than processing",
+ peer->host,
+ bgp_debug_rdpfxpath2str (prd, p, addpath_id ? 1 : 0,
+ addpath_id, pfx_buf, sizeof (pfx_buf)));
bgp_info_restore (rn, ri);
}
/* Received Logging. */
if (bgp_debug_update(peer, p, NULL, 1))
- {
- bgp_info_addpath_rx_str(addpath_id, buf2);
- zlog_debug ("%s rcvd %s/%d%s",
- peer->host,
- inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
- p->prefixlen, buf2);
- }
+ zlog_debug ("%s rcvd %s", peer->host,
+ bgp_debug_rdpfxpath2str (prd, p, addpath_id ? 1 : 0,
+ addpath_id, pfx_buf, sizeof (pfx_buf)));
/* graceful restart STALE flag unset. */
if (CHECK_FLAG (ri->flags, BGP_INFO_STALE))
@@ -2594,7 +2637,7 @@ bgp_update (struct peer *peer, struct prefix *p, u_int32_t addpath_id,
ri->attr = attr_new;
/* Update MPLS tag. */
- if (safi == SAFI_MPLS_VPN)
+ if (safi == SAFI_MPLS_VPN || safi == SAFI_EVPN)
memcpy ((bgp_info_extra_get (ri))->tag, tag, 3);
#if ENABLE_BGP_VNC
@@ -2615,6 +2658,12 @@ bgp_update (struct peer *peer, struct prefix *p, u_int32_t addpath_id,
}
}
#endif
+ /* Update Overlay Index */
+ if(afi == AFI_L2VPN)
+ {
+ overlay_index_update(ri->attr, evpn==NULL?NULL:&evpn->eth_s_id,
+ evpn==NULL?NULL:&evpn->gw_ip);
+ }
/* Update bgp route dampening information. */
if (CHECK_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING)
@@ -2710,20 +2759,24 @@ bgp_update (struct peer *peer, struct prefix *p, u_int32_t addpath_id,
peer->rcvd_attr_printed = 1;
}
- bgp_info_addpath_rx_str(addpath_id, buf2);
- zlog_debug ("%s rcvd %s/%d%s",
- peer->host,
- inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
- p->prefixlen, buf2);
+ zlog_debug ("%s rcvd %s", peer->host,
+ bgp_debug_rdpfxpath2str (prd, p, addpath_id ? 1 : 0,
+ addpath_id, pfx_buf, sizeof (pfx_buf)));
}
/* Make new BGP info. */
new = info_make(type, sub_type, 0, peer, attr_new, rn);
/* Update MPLS tag. */
- if (safi == SAFI_MPLS_VPN)
+ if (safi == SAFI_MPLS_VPN || safi == SAFI_EVPN)
memcpy ((bgp_info_extra_get (new))->tag, tag, 3);
+ /* Update Overlay Index */
+ if(afi == AFI_L2VPN)
+ {
+ overlay_index_update(new->attr, evpn==NULL?NULL:&evpn->eth_s_id,
+ evpn==NULL?NULL:&evpn->gw_ip);
+ }
/* Nexthop reachability check. */
if ((afi == AFI_IP || afi == AFI_IP6) && safi == SAFI_UNICAST)
{
@@ -2820,11 +2873,10 @@ bgp_update (struct peer *peer, struct prefix *p, u_int32_t addpath_id,
peer->rcvd_attr_printed = 1;
}
- bgp_info_addpath_rx_str(addpath_id, buf2);
- zlog_debug ("%s rcvd UPDATE about %s/%d%s -- DENIED due to: %s",
+ zlog_debug ("%s rcvd UPDATE about %s -- DENIED due to: %s",
peer->host,
- inet_ntop (p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
- p->prefixlen, buf2, reason);
+ bgp_debug_rdpfxpath2str (prd, p, addpath_id ? 1 : 0,
+ addpath_id, pfx_buf, sizeof (pfx_buf)), reason);
}
if (ri)
@@ -2849,11 +2901,10 @@ bgp_update (struct peer *peer, struct prefix *p, u_int32_t addpath_id,
int
bgp_withdraw (struct peer *peer, struct prefix *p, u_int32_t addpath_id,
struct attr *attr, afi_t afi, safi_t safi, int type, int sub_type,
- struct prefix_rd *prd, u_char *tag)
+ struct prefix_rd *prd, u_char *tag, struct bgp_route_evpn *evpn)
{
struct bgp *bgp;
- char buf[SU_ADDRSTRLEN];
- char buf2[30];
+ char pfx_buf[BGP_PRD_PATH_STRLEN];
struct bgp_node *rn;
struct bgp_info *ri;
@@ -2883,10 +2934,10 @@ bgp_withdraw (struct peer *peer, struct prefix *p, u_int32_t addpath_id,
if (!bgp_adj_in_unset (rn, peer, addpath_id))
{
if (bgp_debug_update (peer, p, NULL, 1))
- zlog_debug ("%s withdrawing route %s/%d "
- "not in adj-in", peer->host,
- inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
- p->prefixlen);
+ zlog_debug ("%s withdrawing route %s not in adj-in",
+ peer->host,
+ bgp_debug_rdpfxpath2str (prd, p, addpath_id ? 1 : 0,
+ addpath_id, pfx_buf, sizeof (pfx_buf)));
bgp_unlock_node (rn);
return 0;
}
@@ -2900,20 +2951,20 @@ bgp_withdraw (struct peer *peer, struct prefix *p, u_int32_t addpath_id,
/* Logging. */
if (bgp_debug_update(peer, p, NULL, 1))
{
- bgp_info_addpath_rx_str(addpath_id, buf2);
- zlog_debug ("%s rcvd UPDATE about %s/%d%s -- withdrawn",
- peer->host,
- inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
- p->prefixlen, buf2);
+ zlog_debug ("%s rcvd UPDATE about %s -- withdrawn",
+ peer->host,
+ bgp_debug_rdpfxpath2str (prd, p, addpath_id ? 1 : 0,
+ addpath_id, pfx_buf, sizeof (pfx_buf)));
}
/* Withdraw specified route from routing table. */
if (ri && ! CHECK_FLAG (ri->flags, BGP_INFO_HISTORY))
bgp_rib_withdraw (rn, ri, peer, afi, safi, prd);
else if (bgp_debug_update(peer, p, NULL, 1))
- zlog_debug ("%s Can't find the route %s/%d", peer->host,
- inet_ntop (p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
- p->prefixlen);
+ zlog_debug ("%s Can't find the route %s",
+ peer->host,
+ bgp_debug_rdpfxpath2str (prd, p, addpath_id ? 1 : 0,
+ addpath_id, pfx_buf, sizeof (pfx_buf)));
/* Unlock bgp_node_get() lock. */
bgp_unlock_node (rn);
@@ -3047,7 +3098,7 @@ bgp_soft_reconfig_table (struct peer *peer, afi_t afi, safi_t safi,
ret = bgp_update (peer, &rn->p, ain->addpath_rx_id, ain->attr,
afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL,
- prd, tag, 1);
+ prd, tag, 1, NULL);
if (ret < 0)
{
@@ -3067,7 +3118,7 @@ bgp_soft_reconfig_in (struct peer *peer, afi_t afi, safi_t safi)
if (peer->status != Established)
return;
- if ((safi != SAFI_MPLS_VPN) && (safi != SAFI_ENCAP))
+ if ((safi != SAFI_MPLS_VPN) && (safi != SAFI_ENCAP) && (safi != SAFI_EVPN))
bgp_soft_reconfig_table (peer, afi, safi, NULL, NULL);
else
for (rn = bgp_table_top (peer->bgp->rib[afi][safi]); rn;
@@ -3288,7 +3339,7 @@ bgp_clear_route (struct peer *peer, afi_t afi, safi_t safi)
if (!peer->clear_node_queue->thread)
peer_lock (peer);
- if (safi != SAFI_MPLS_VPN && safi != SAFI_ENCAP)
+ if (safi != SAFI_MPLS_VPN && safi != SAFI_ENCAP && safi != SAFI_EVPN)
bgp_clear_route_table (peer, afi, safi, NULL);
else
for (rn = bgp_table_top (peer->bgp->rib[afi][safi]); rn;
@@ -3421,40 +3472,56 @@ void
bgp_cleanup_routes (struct bgp *bgp)
{
afi_t afi;
+ struct bgp_node *rn;
for (afi = AFI_IP; afi < AFI_MAX; ++afi)
{
- struct bgp_node *rn;
-
+ if (afi == AFI_L2VPN)
+ continue;
bgp_cleanup_table(bgp->rib[afi][SAFI_UNICAST], SAFI_UNICAST);
-
/*
- * VPN and ENCAP tables are two-level (RD is top level)
+ * VPN and ENCAP and EVPN tables are two-level (RD is top level)
*/
- for (rn = bgp_table_top(bgp->rib[afi][SAFI_MPLS_VPN]); rn;
- rn = bgp_route_next (rn))
- {
- if (rn->info)
- {
- bgp_cleanup_table((struct bgp_table *)(rn->info), SAFI_MPLS_VPN);
- bgp_table_finish ((struct bgp_table **)&(rn->info));
- rn->info = NULL;
- bgp_unlock_node(rn);
- }
- }
-
- for (rn = bgp_table_top(bgp->rib[afi][SAFI_ENCAP]); rn;
- rn = bgp_route_next (rn))
- {
- if (rn->info)
- {
- bgp_cleanup_table((struct bgp_table *)(rn->info), SAFI_ENCAP);
- bgp_table_finish ((struct bgp_table **)&(rn->info));
- rn->info = NULL;
- bgp_unlock_node(rn);
- }
+ if (afi != AFI_L2VPN)
+ {
+ safi_t safi;
+ safi = SAFI_MPLS_VPN;
+ for (rn = bgp_table_top(bgp->rib[afi][safi]); rn;
+ rn = bgp_route_next (rn))
+ {
+ if (rn->info)
+ {
+ bgp_cleanup_table((struct bgp_table *)(rn->info), safi);
+ bgp_table_finish ((struct bgp_table **)&(rn->info));
+ rn->info = NULL;
+ bgp_unlock_node(rn);
+ }
+ }
+ safi = SAFI_ENCAP;
+ for (rn = bgp_table_top(bgp->rib[afi][safi]); rn;
+ rn = bgp_route_next (rn))
+ {
+ if (rn->info)
+ {
+ bgp_cleanup_table((struct bgp_table *)(rn->info), safi);
+ bgp_table_finish ((struct bgp_table **)&(rn->info));
+ rn->info = NULL;
+ bgp_unlock_node(rn);
+ }
+ }
}
}
+ for (rn = bgp_table_top(bgp->rib[AFI_L2VPN][SAFI_EVPN]); rn;
+ rn = bgp_route_next (rn))
+ {
+ if (rn->info)
+ {
+ bgp_cleanup_table((struct bgp_table *)(rn->info), SAFI_EVPN);
+ bgp_table_finish ((struct bgp_table **)&(rn->info));
+ rn->info = NULL;
+ bgp_unlock_node(rn);
+ }
+ }
}
void
@@ -3597,10 +3664,10 @@ bgp_nlri_parse_ip (struct peer *peer, struct attr *attr,
/* Normal process. */
if (attr)
ret = bgp_update (peer, &p, addpath_id, attr, afi, safi,
- ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, NULL, NULL, 0);
+ ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, NULL, NULL, 0, NULL);
else
ret = bgp_withdraw (peer, &p, addpath_id, attr, afi, safi,
- ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, NULL, NULL);
+ ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, NULL, NULL, NULL);
/* Address family configuration mismatch or maximum-prefix count
overflow. */
@@ -3630,6 +3697,8 @@ bgp_static_free (struct bgp_static *bgp_static)
{
if (bgp_static->rmap.name)
XFREE(MTYPE_ROUTE_MAP_NAME, bgp_static->rmap.name);
+ if(bgp_static->eth_s_id)
+ XFREE(MTYPE_ATTR, bgp_static->eth_s_id);
XFREE (MTYPE_BGP_STATIC, bgp_static);
}
@@ -3925,6 +3994,7 @@ bgp_static_update_safi (struct bgp *bgp, struct prefix *p,
#if ENABLE_BGP_VNC
u_int32_t label = 0;
#endif
+ union gw_addr add;
assert (bgp_static);
@@ -3936,6 +4006,33 @@ bgp_static_update_safi (struct bgp *bgp, struct prefix *p,
attr.med = bgp_static->igpmetric;
attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC);
+ if ((safi == SAFI_EVPN) || (safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP))
+ {
+ if (bgp_static->igpnexthop.s_addr)
+ {
+ bgp_attr_extra_get (&attr)->mp_nexthop_global_in = bgp_static->igpnexthop;
+ bgp_attr_extra_get (&attr)->mp_nexthop_len = IPV4_MAX_BYTELEN;
+ }
+ }
+ if(afi == AFI_L2VPN)
+ {
+ if (bgp_static->gatewayIp.family == AF_INET)
+ add.ipv4.s_addr = bgp_static->gatewayIp.u.prefix4.s_addr;
+ else if (bgp_static->gatewayIp.family == AF_INET6)
+ memcpy( &(add.ipv6), &(bgp_static->gatewayIp.u.prefix6), sizeof (struct in6_addr));
+ overlay_index_update(&attr, bgp_static->eth_s_id, &add);
+ if (bgp_static->encap_tunneltype == BGP_ENCAP_TYPE_VXLAN)
+ {
+ struct bgp_encap_type_vxlan bet;
+ memset(&bet, 0, sizeof(struct bgp_encap_type_vxlan));
+ bet.vnid = p->u.prefix_evpn.eth_tag;
+ bgp_encap_type_vxlan_to_tlv(&bet, &attr);
+ }
+ if (bgp_static->router_mac)
+ {
+ bgp_add_routermac_ecom (&attr, bgp_static->router_mac);
+ }
+ }
/* Apply route-map. */
if (bgp_static->rmap.name)
{
@@ -3979,7 +4076,10 @@ bgp_static_update_safi (struct bgp *bgp, struct prefix *p,
if (ri)
{
+ union gw_addr add;
+ memset(&add, 0, sizeof(union gw_addr));
if (attrhash_cmp (ri->attr, attr_new) &&
+ overlay_index_equal(afi, ri, bgp_static->eth_s_id, &add) &&
!CHECK_FLAG(ri->flags, BGP_INFO_REMOVED))
{
bgp_unlock_node (rn);
@@ -4037,7 +4137,6 @@ bgp_static_update_safi (struct bgp *bgp, struct prefix *p,
/* Register new BGP information. */
bgp_info_add (rn, new);
-
/* route_node_get lock */
bgp_unlock_node (rn);
@@ -4209,7 +4308,7 @@ bgp_static_add (struct bgp *bgp)
for (rn = bgp_table_top (bgp->route[afi][safi]); rn; rn = bgp_route_next (rn))
if (rn->info != NULL)
{
- if (safi == SAFI_MPLS_VPN)
+ if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP) || (safi == SAFI_EVPN))
{
table = rn->info;
@@ -4243,7 +4342,7 @@ bgp_static_delete (struct bgp *bgp)
for (rn = bgp_table_top (bgp->route[afi][safi]); rn; rn = bgp_route_next (rn))
if (rn->info != NULL)
{
- if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP))
+ if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP) || (safi == SAFI_EVPN))
{
table = rn->info;
@@ -4341,7 +4440,8 @@ bgp_purge_static_redist_routes (struct bgp *bgp)
int
bgp_static_set_safi (safi_t safi, struct vty *vty, const char *ip_str,
const char *rd_str, const char *tag_str,
- const char *rmap_str)
+ const char *rmap_str, int evpn_type, const char *esi, const char *gwip,
+ const char *ethtag, const char *routermac)
{
VTY_DECLVAR_CONTEXT(bgp, bgp);
int ret;
@@ -4353,7 +4453,14 @@ bgp_static_set_safi (safi_t safi, struct vty *vty, const char *ip_str,
struct bgp_static *bgp_static;
u_char tag[3];
afi_t afi;
+ struct prefix gw_ip;
+
+ if(safi == SAFI_EVPN)
+ afi = AFI_L2VPN;
+ else
+ afi = AFI_IP;
+ /* validate ip prefix */
ret = str2prefix (ip_str, &p);
if (! ret)
{
@@ -4361,6 +4468,12 @@ bgp_static_set_safi (safi_t safi, struct vty *vty, const char *ip_str,
return CMD_WARNING;
}
apply_mask (&p);
+ if ( (afi == AFI_L2VPN) &&
+ (bgp_build_evpn_prefix ( evpn_type, ethtag!=NULL?atol(ethtag):0, &p)))
+ {
+ vty_out (vty, "%% L2VPN prefix could not be forged%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
ret = str2prefix_rd (rd_str, &prd);
if (! ret)
@@ -4369,20 +4482,47 @@ bgp_static_set_safi (safi_t safi, struct vty *vty, const char *ip_str,
return CMD_WARNING;
}
- ret = str2tag (tag_str, tag);
- if (! ret)
+ if (tag_str)
{
- vty_out (vty, "%% Malformed tag%s", VTY_NEWLINE);
- return CMD_WARNING;
+ ret = str2tag (tag_str, tag);
+ if (! ret)
+ {
+ vty_out (vty, "%% Malformed tag%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
}
- if (p.family == AF_INET)
- afi = AFI_IP;
- else if (p.family == AF_INET6)
- afi = AFI_IP6;
else
{
- vty_out (vty, "%% Non Supported prefix%s", VTY_NEWLINE);
- return CMD_WARNING;
+ encode_label (0, tag);
+ }
+ if (safi == SAFI_EVPN)
+ {
+ if( esi && str2esi (esi, NULL) == 0)
+ {
+ vty_out (vty, "%% Malformed ESI%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ if( routermac && prefix_str2mac (routermac, NULL) == 0)
+ {
+ vty_out (vty, "%% Malformed Router MAC%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ if (gwip)
+ {
+ memset (&gw_ip, 0, sizeof (struct prefix));
+ ret = str2prefix (gwip, &gw_ip);
+ if (! ret)
+ {
+ vty_out (vty, "%% Malformed GatewayIp%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ if((gw_ip.family == AF_INET && (p.u.prefix_evpn.flags & IP_PREFIX_V6))
+ || (gw_ip.family == AF_INET6 && (p.u.prefix_evpn.flags & IP_PREFIX_V4)))
+ {
+ vty_out (vty, "%% GatewayIp family differs with IP prefix%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ }
}
prn = bgp_node_get (bgp->route[afi][safi],
(struct prefix *)&prd);
@@ -4417,6 +4557,22 @@ bgp_static_set_safi (safi_t safi, struct vty *vty, const char *ip_str,
bgp_static->rmap.name = strdup (rmap_str);
bgp_static->rmap.map = route_map_lookup_by_name (rmap_str);
}
+
+ if (safi == SAFI_EVPN)
+ {
+ if(esi)
+ {
+ bgp_static->eth_s_id = XCALLOC (MTYPE_ATTR, sizeof(struct eth_segment_id));
+ str2esi (esi, bgp_static->eth_s_id);
+ }
+ if( routermac)
+ {
+ bgp_static->router_mac = XCALLOC (MTYPE_ATTR, ETHER_ADDR_LEN+1);
+ prefix_str2mac (routermac, bgp_static->router_mac);
+ }
+ if (gwip)
+ prefix_copy (&bgp_static->gatewayIp, &gw_ip);
+ }
rn->info = bgp_static;
bgp_static->valid = 1;
@@ -4429,7 +4585,8 @@ bgp_static_set_safi (safi_t safi, struct vty *vty, const char *ip_str,
/* Configure static BGP network. */
int
bgp_static_unset_safi(safi_t safi, struct vty *vty, const char *ip_str,
- const char *rd_str, const char *tag_str)
+ const char *rd_str, const char *tag_str,
+ int evpn_type, const char *esi, const char *gwip, const char *ethtag)
{
VTY_DECLVAR_CONTEXT(bgp, bgp);
int ret;
@@ -4440,6 +4597,12 @@ bgp_static_unset_safi(safi_t safi, struct vty *vty, const char *ip_str,
struct bgp_table *table;
struct bgp_static *bgp_static;
u_char tag[3];
+ afi_t afi;
+
+ if(safi == SAFI_EVPN)
+ afi = AFI_L2VPN;
+ else
+ afi = AFI_IP;
/* Convert IP prefix string to struct prefix. */
ret = str2prefix (ip_str, &p);
@@ -4449,7 +4612,12 @@ bgp_static_unset_safi(safi_t safi, struct vty *vty, const char *ip_str,
return CMD_WARNING;
}
apply_mask (&p);
-
+ if ( (afi == AFI_L2VPN) &&
+ (bgp_build_evpn_prefix ( evpn_type, ethtag!=NULL?atol(ethtag):0, &p)))
+ {
+ vty_out (vty, "%% L2VPN prefix could not be forged%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
ret = str2prefix_rd (rd_str, &prd);
if (! ret)
{
@@ -4464,10 +4632,10 @@ bgp_static_unset_safi(safi_t safi, struct vty *vty, const char *ip_str,
return CMD_WARNING;
}
- prn = bgp_node_get (bgp->route[AFI_IP][safi],
+ prn = bgp_node_get (bgp->route[afi][safi],
(struct prefix *)&prd);
if (prn->info == NULL)
- prn->info = bgp_table_init (AFI_IP, safi);
+ prn->info = bgp_table_init (afi, safi);
else
bgp_unlock_node (prn);
table = prn->info;
@@ -4476,7 +4644,7 @@ bgp_static_unset_safi(safi_t safi, struct vty *vty, const char *ip_str,
if (rn)
{
- bgp_static_withdraw_safi (bgp, &p, AFI_IP, safi, &prd, tag);
+ bgp_static_withdraw_safi (bgp, &p, afi, safi, &prd, tag);
bgp_static = rn->info;
bgp_static_free (bgp_static);
@@ -5099,7 +5267,7 @@ bgp_aggregate_increment (struct bgp *bgp, struct prefix *p,
struct bgp_table *table;
/* MPLS-VPN aggregation is not yet supported. */
- if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP))
+ if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP) || (safi = SAFI_EVPN))
return;
table = bgp->aggregate[afi][safi];
@@ -5136,7 +5304,7 @@ bgp_aggregate_decrement (struct bgp *bgp, struct prefix *p,
struct bgp_table *table;
/* MPLS-VPN aggregation is not yet supported. */
- if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP))
+ if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP) || (safi = SAFI_EVPN))
return;
table = bgp->aggregate[afi][safi];
@@ -5795,6 +5963,11 @@ route_vty_out_route (struct prefix *p, struct vty *vty)
else
len += vty_out (vty, "/%d", p->prefixlen);
}
+ else if (p->family == AF_ETHERNET)
+ {
+ prefix2str(p, buf, PREFIX_STRLEN);
+ len = vty_out (vty, "%s", buf);
+ }
else
len = vty_out (vty, "%s/%d", inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ),
p->prefixlen);
@@ -5924,7 +6097,7 @@ route_vty_out (struct vty *vty, struct prefix *p,
* neccessarily the same as the prefix address family.
* Both SAFI_MPLS_VPN and SAFI_ENCAP use the MP nexthop field
*/
- if ((safi == SAFI_ENCAP) || (safi == SAFI_MPLS_VPN))
+ if ((safi == SAFI_ENCAP) || (safi == SAFI_MPLS_VPN) || (safi = SAFI_EVPN))
{
if (attr->extra)
{
@@ -5956,7 +6129,7 @@ route_vty_out (struct vty *vty, struct prefix *p,
{
json_nexthop_global = json_object_new_object();
- if (safi == SAFI_MPLS_VPN)
+ if ((safi == SAFI_MPLS_VPN) || (safi = SAFI_EVPN))
json_object_string_add(json_nexthop_global, "ip", inet_ntoa (attr->extra->mp_nexthop_global_in));
else
json_object_string_add(json_nexthop_global, "ip", inet_ntoa (attr->nexthop));
@@ -5966,7 +6139,7 @@ route_vty_out (struct vty *vty, struct prefix *p,
}
else
{
- if (safi == SAFI_MPLS_VPN)
+ if ((safi == SAFI_MPLS_VPN) || (safi = SAFI_EVPN))
vty_out (vty, "%-16s",
inet_ntoa (attr->extra->mp_nexthop_global_in));
else
@@ -6180,9 +6353,10 @@ route_vty_out_tmp (struct vty *vty, struct prefix *p, struct attr *attr, safi_t
if (p->family == AF_INET &&
(safi == SAFI_MPLS_VPN ||
safi == SAFI_ENCAP ||
+ safi == SAFI_EVPN ||
!BGP_ATTR_NEXTHOP_AFI_IP6(attr)))
{
- if (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP)
+ if (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP || safi == SAFI_EVPN)
json_object_string_add(json_net, "nextHop", inet_ntoa (attr->extra->mp_nexthop_global_in));
else
json_object_string_add(json_net, "nextHop", inet_ntoa (attr->nexthop));
@@ -6218,9 +6392,10 @@ route_vty_out_tmp (struct vty *vty, struct prefix *p, struct attr *attr, safi_t
if (p->family == AF_INET &&
(safi == SAFI_MPLS_VPN ||
safi == SAFI_ENCAP ||
+ safi == SAFI_EVPN ||
!BGP_ATTR_NEXTHOP_AFI_IP6(attr)))
{
- if (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP)
+ if (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP || safi == SAFI_EVPN)
vty_out (vty, "%-16s",
inet_ntoa (attr->extra->mp_nexthop_global_in));
else
@@ -6281,7 +6456,7 @@ route_vty_out_tag (struct vty *vty, struct prefix *p,
json_object *json_out = NULL;
struct attr *attr;
u_int32_t label = 0;
-
+
if (!binfo->extra)
return;
@@ -6304,10 +6479,11 @@ route_vty_out_tag (struct vty *vty, struct prefix *p,
attr = binfo->attr;
if (attr)
{
- if (p->family == AF_INET
- && (safi == SAFI_MPLS_VPN || !BGP_ATTR_NEXTHOP_AFI_IP6(attr)))
+ if (((p->family == AF_INET) && ((safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP)))
+ || (safi == SAFI_EVPN && p->family == AF_ETHERNET && !BGP_ATTR_NEXTHOP_AFI_IP6(attr))
+ || (!BGP_ATTR_NEXTHOP_AFI_IP6(attr)))
{
- if (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP)
+ if (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP || safi == SAFI_EVPN)
{
if (json)
json_object_string_add(json_out, "mpNexthopGlobalIn", inet_ntoa (attr->extra->mp_nexthop_global_in));
@@ -6322,7 +6498,9 @@ route_vty_out_tag (struct vty *vty, struct prefix *p,
vty_out (vty, "%-16s", inet_ntoa (attr->nexthop));
}
}
- else if (p->family == AF_INET6 || BGP_ATTR_NEXTHOP_AFI_IP6(attr))
+ else if (((p->family == AF_INET6) && ((safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP)))
+ || (safi == SAFI_EVPN && p->family == AF_ETHERNET && BGP_ATTR_NEXTHOP_AFI_IP6(attr))
+ || (BGP_ATTR_NEXTHOP_AFI_IP6(attr)))
{
assert (attr->extra);
char buf_a[BUFSIZ];
@@ -6371,10 +6549,97 @@ route_vty_out_tag (struct vty *vty, struct prefix *p,
else
{
vty_out (vty, "notag/%d", label);
+
vty_out (vty, "%s", VTY_NEWLINE);
}
}
+void
+route_vty_out_overlay (struct vty *vty, struct prefix *p,
+ struct bgp_info *binfo, int display, json_object *json_paths)
+{
+ struct attr *attr;
+ char buf[BUFSIZ];
+ json_object *json_path = NULL;
+
+ if (json_paths)
+ json_path = json_object_new_object();
+
+ if (!binfo->extra)
+ return;
+
+ /* short status lead text */
+ route_vty_short_status_out (vty, binfo, json_path);
+
+ /* print prefix and mask */
+ if (! display)
+ route_vty_out_route (p, vty);
+ else
+ vty_out (vty, "%*s", 17, " ");
+
+ /* Print attribute */
+ attr = binfo->attr;
+ if (attr)
+ {
+ if (attr->extra)
+ {
+ char buf1[BUFSIZ];
+ int af = NEXTHOP_FAMILY(attr->extra->mp_nexthop_len);
+
+ switch (af) {
+ case AF_INET:
+ vty_out (vty, "%-16s", inet_ntop(af,
+ &attr->extra->mp_nexthop_global_in, buf, BUFSIZ));
+ break;
+ case AF_INET6:
+ vty_out (vty, "%s(%s)",
+ inet_ntop (af,
+ &attr->extra->mp_nexthop_global, buf, BUFSIZ),
+ inet_ntop (af,
+ &attr->extra->mp_nexthop_local, buf1, BUFSIZ));
+ break;
+ default:
+ vty_out(vty, "?");
+ }
+ } else {
+ vty_out(vty, "?");
+ }
+ }
+
+ if(attr->extra)
+ {
+ struct eth_segment_id *id = &(attr->extra->evpn_overlay.eth_s_id);
+ char *str = esi2str(id);
+ vty_out (vty, "%s", str);
+ XFREE (MTYPE_TMP, str);
+ if (p->u.prefix_evpn.flags & IP_PREFIX_V4)
+ {
+ vty_out (vty, "/%s", inet_ntoa (attr->extra->evpn_overlay.gw_ip.ipv4));
+ }
+ else if (p->u.prefix_evpn.flags & IP_PREFIX_V6)
+ {
+ vty_out (vty, "/%s",
+ inet_ntop (AF_INET6, &(attr->extra->evpn_overlay.gw_ip.ipv6),
+ buf, BUFSIZ));
+ }
+ if(attr->extra->ecommunity)
+ {
+ char *mac = NULL;
+ struct ecommunity_val *routermac = ecommunity_lookup (attr->extra->ecommunity,
+ ECOMMUNITY_ENCODE_EVPN,
+ ECOMMUNITY_EVPN_SUBTYPE_ROUTERMAC);
+ if(routermac)
+ mac = ecom_mac2str((char *)routermac->val);
+ if(mac)
+ {
+ vty_out (vty, "/%s",(char *)mac);
+ XFREE(MTYPE_TMP, mac);
+ }
+ }
+ }
+ vty_out (vty, "%s", VTY_NEWLINE);
+}
+
/* dampening route */
static void
damp_route_vty_out (struct vty *vty, struct prefix *p, struct bgp_info *binfo,
@@ -6717,9 +6982,10 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p,
if (p->family == AF_INET &&
(safi == SAFI_MPLS_VPN ||
safi == SAFI_ENCAP ||
+ safi == SAFI_EVPN ||
!BGP_ATTR_NEXTHOP_AFI_IP6(attr)))
{
- if (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP)
+ if (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP || safi == SAFI_EVPN)
{
if (json_paths)
json_object_string_add(json_nexthop_global, "ip", inet_ntoa (attr->extra->mp_nexthop_global_in));
@@ -7656,11 +7922,15 @@ route_vty_out_detail_header (struct vty *vty, struct bgp *bgp,
}
else
{
+ if (p->family == AF_ETHERNET)
+ prefix2str (p, buf2, INET6_ADDRSTRLEN);
+ else
+ inet_ntop (p->family, &p->u.prefix, buf2, INET6_ADDRSTRLEN);
vty_out (vty, "BGP routing table entry for %s%s%s/%d%s",
- ((safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP) ?
+ ((safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP || safi == SAFI_EVPN) ?
prefix_rd2str (prd, buf1, RD_ADDRSTRLEN) : ""),
- safi == SAFI_MPLS_VPN ? ":" : "",
- inet_ntop (p->family, &p->u.prefix, buf2, INET6_ADDRSTRLEN),
+ ((safi == SAFI_MPLS_VPN) || (safi == SAFI_EVPN)) ? ":" : "",
+ buf2,
p->prefixlen, VTY_NEWLINE);
}
@@ -7779,7 +8049,7 @@ bgp_show_route_in_table (struct vty *vty, struct bgp *bgp,
json_paths = json_object_new_array();
}
- if (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP)
+ if (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP || safi == SAFI_EVPN)
{
for (rn = bgp_table_top (rib); rn; rn = bgp_route_next (rn))
{
@@ -9079,7 +9349,27 @@ DEFUN (show_ip_bgp_vpn_all_route_prefix,
}
#endif /* KEEP_OLD_VPN_COMMANDS */
-static void
+DEFUN (show_ip_bgp_l2vpn_evpn_all_route_prefix,
+ show_ip_bgp_l2vpn_evpn_all_route_prefix_cmd,
+ "show [ip] bgp l2vpn evpn all <A.B.C.D|A.B.C.D/M> [json]",
+ SHOW_STR
+ IP_STR
+ BGP_STR
+ L2VPN_HELP_STR
+ EVPN_HELP_STR
+ "Display information about all EVPN NLRIs\n"
+ "Network in the BGP routing table to display\n"
+ "Network in the BGP routing table to display\n"
+ JSON_STR)
+{
+ int idx = 0;
+ char *network = NULL;
+ network = argv_find (argv, argc, "A.B.C.D", &idx) ? argv[idx]->arg : NULL;
+ network = argv_find (argv, argc, "A.B.C.D/M", &idx) ? argv[idx]->arg : NULL;
+ return bgp_show_route (vty, NULL, network, AFI_L2VPN, SAFI_EVPN, NULL, 0, BGP_PATH_ALL, use_json(argc, argv));
+}
+
+ static void
show_adj_route (struct vty *vty, struct peer *peer, afi_t afi, safi_t safi,
int in, const char *rmap_name, u_char use_json, json_object *json)
{
@@ -10054,7 +10344,7 @@ bgp_clear_damp_route (struct vty *vty, const char *view_name,
match.family = afi2family (afi);
- if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP))
+ if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP) || (safi == SAFI_EVPN))
{
for (rn = bgp_table_top (bgp->rib[AFI_IP][safi]); rn; rn = bgp_route_next (rn))
{
@@ -10217,6 +10507,57 @@ bgp_config_write_network_vpn (struct vty *vty, struct bgp *bgp,
return 0;
}
+static int
+bgp_config_write_network_evpn (struct vty *vty, struct bgp *bgp,
+ afi_t afi, safi_t safi, int *write)
+{
+ struct bgp_node *prn;
+ struct bgp_node *rn;
+ struct bgp_table *table;
+ struct prefix *p;
+ struct prefix_rd *prd;
+ struct bgp_static *bgp_static;
+ char buf[PREFIX_STRLEN];
+ char buf2[SU_ADDRSTRLEN];
+ char rdbuf[RD_ADDRSTRLEN];
+
+ /* Network configuration. */
+ for (prn = bgp_table_top (bgp->route[afi][safi]); prn; prn = bgp_route_next (prn))
+ if ((table = prn->info) != NULL)
+ for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn))
+ if ((bgp_static = rn->info) != NULL)
+ {
+ char *macrouter = NULL;
+ char *esi = NULL;
+
+ if(bgp_static->router_mac)
+ macrouter = prefix_mac2str(bgp_static->router_mac, NULL, 0);
+ if(bgp_static->eth_s_id)
+ esi = esi2str(bgp_static->eth_s_id);
+ p = &rn->p;
+ prd = (struct prefix_rd *) &prn->p;
+
+ /* "address-family" display. */
+ bgp_config_write_family_header (vty, afi, safi, write);
+
+ /* "network" configuration display. */
+ prefix_rd2str (prd, rdbuf, RD_ADDRSTRLEN);
+
+ inet_ntop (AF_INET, &bgp_static->igpnexthop, buf2, SU_ADDRSTRLEN);
+
+ prefix2str (p, buf, sizeof (buf)),
+ vty_out (vty, " network %s rd %s ethtag %u tag %u esi %s gwip %s routermac %s",
+ buf, rdbuf, p->u.prefix_evpn.eth_tag,
+ decode_label (bgp_static->tag), esi, buf2 , macrouter);
+ vty_out (vty, "%s", VTY_NEWLINE);
+ if (macrouter)
+ XFREE (MTYPE_TMP, macrouter);
+ if (esi)
+ XFREE (MTYPE_TMP, esi);
+ }
+ return 0;
+}
+
/* Configuration of static route announcement and aggregate
information. */
int
@@ -10232,6 +10573,9 @@ bgp_config_write_network (struct vty *vty, struct bgp *bgp,
if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP))
return bgp_config_write_network_vpn (vty, bgp, afi, safi, write);
+ if (afi == AFI_L2VPN && safi == SAFI_EVPN)
+ return bgp_config_write_network_evpn (vty, bgp, afi, safi, write);
+
/* Network configuration. */
for (rn = bgp_table_top (bgp->route[afi][safi]); rn; rn = bgp_route_next (rn))
if ((bgp_static = rn->info) != NULL)
@@ -10434,7 +10778,8 @@ bgp_route_init (void)
install_element (VIEW_NODE, &show_ip_bgp_vpn_all_route_prefix_cmd);
#endif /* KEEP_OLD_VPN_COMMANDS */
install_element (VIEW_NODE, &show_bgp_afi_vpn_rd_route_cmd);
-
+ install_element (VIEW_NODE, &show_ip_bgp_l2vpn_evpn_all_route_prefix_cmd);
+
/* BGP dampening clear commands */
install_element (ENABLE_NODE, &clear_ip_bgp_dampening_cmd);
install_element (ENABLE_NODE, &clear_ip_bgp_dampening_prefix_cmd);
diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h
index 2103338b7d..e75978d003 100644
--- a/bgpd/bgp_route.h
+++ b/bgpd/bgp_route.h
@@ -25,6 +25,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "bgp_table.h"
struct bgp_nexthop_cache;
+struct bgp_route_evpn;
enum bgp_show_type
{
@@ -93,7 +94,7 @@ struct bgp_info_extra
struct in6_addr addr6;
} un; /* cached un address */
time_t create_time;
- struct prefix aux_prefix; /* AFI_ETHER: the IP addr, if family set */
+ struct prefix aux_prefix; /* AFI_L2VPN: the IP addr, if family set */
} import;
} vnc;
@@ -202,6 +203,12 @@ struct bgp_static
/* MPLS label. */
u_char tag[3];
+
+ /* EVPN */
+ struct eth_segment_id *eth_s_id;
+ struct ethaddr *router_mac;
+ uint16_t encap_tunneltype;
+ struct prefix gatewayIp;
};
#define BGP_NEXTHOP_AFI_FROM_NHLEN(nhlen) \
@@ -312,17 +319,20 @@ extern void bgp_static_update (struct bgp *, struct prefix *, struct bgp_static
extern void bgp_static_withdraw (struct bgp *, struct prefix *, afi_t, safi_t);
extern int bgp_static_set_safi (safi_t safi, struct vty *vty, const char *,
- const char *, const char *, const char *);
+ const char *, const char *, const char *,
+ int, const char *, const char *, const char *, const char *);
extern int bgp_static_unset_safi (safi_t safi, struct vty *, const char *,
- const char *, const char *);
+ const char *, const char *,
+ int, const char *, const char *, const char *);
/* this is primarily for MPLS-VPN */
extern int bgp_update (struct peer *, struct prefix *, u_int32_t, struct attr *,
- afi_t, safi_t, int, int, struct prefix_rd *,
- u_char *, int);
+ afi_t, safi_t, int, int, struct prefix_rd *,
+ u_char *, int, struct bgp_route_evpn *);
extern int bgp_withdraw (struct peer *, struct prefix *, u_int32_t, struct attr *,
- afi_t, safi_t, int, int, struct prefix_rd *, u_char *);
+ afi_t, safi_t, int, int, struct prefix_rd *, u_char *,
+ struct bgp_route_evpn *);
/* for bgp_nexthop and bgp_damp */
extern void bgp_process (struct bgp *, struct bgp_node *, afi_t, safi_t);
@@ -350,6 +360,9 @@ extern safi_t bgp_node_safi (struct vty *);
extern void route_vty_out (struct vty *, struct prefix *, struct bgp_info *, int, safi_t, json_object *);
extern void route_vty_out_tag (struct vty *, struct prefix *, struct bgp_info *, int, safi_t, json_object *);
extern void route_vty_out_tmp (struct vty *, struct prefix *, struct attr *, safi_t, u_char, json_object *);
+extern void
+route_vty_out_overlay (struct vty *vty, struct prefix *p,
+ struct bgp_info *binfo, int display, json_object *json);
extern int
subgroup_process_announce_selected (struct update_subgroup *subgrp,
diff --git a/bgpd/bgp_updgrp_adv.c b/bgpd/bgp_updgrp_adv.c
index 48f56a29b2..efb2046e12 100644
--- a/bgpd/bgp_updgrp_adv.c
+++ b/bgpd/bgp_updgrp_adv.c
@@ -605,6 +605,7 @@ subgroup_announce_table (struct update_subgroup *subgrp,
if (safi != SAFI_MPLS_VPN
&& safi != SAFI_ENCAP
+ && safi != SAFI_EVPN
&& CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_DEFAULT_ORIGINATE))
subgroup_default_originate (subgrp, 0);
@@ -668,7 +669,8 @@ subgroup_announce_route (struct update_subgroup *subgrp)
return;
if (SUBGRP_SAFI (subgrp) != SAFI_MPLS_VPN &&
- SUBGRP_SAFI (subgrp) != SAFI_ENCAP)
+ SUBGRP_SAFI (subgrp) != SAFI_ENCAP &&
+ SUBGRP_SAFI (subgrp) != SAFI_EVPN)
subgroup_announce_table (subgrp, NULL);
else
for (rn = bgp_table_top (update_subgroup_rib (subgrp)); rn;
diff --git a/bgpd/bgp_updgrp_packet.c b/bgpd/bgp_updgrp_packet.c
index 79c11358fe..02979602bf 100644
--- a/bgpd/bgp_updgrp_packet.c
+++ b/bgpd/bgp_updgrp_packet.c
@@ -53,6 +53,7 @@
#include "bgpd/bgp_updgrp.h"
#include "bgpd/bgp_nexthop.h"
#include "bgpd/bgp_nht.h"
+#include "bgpd/bgp_mplsvpn.h"
/********************
* PRIVATE FUNCTIONS
@@ -617,6 +618,7 @@ static void
bgp_info_addpath_tx_str (int addpath_encode, u_int32_t addpath_tx_id,
char *buf)
{
+ buf[0] = '\0';
if (addpath_encode)
sprintf(buf, " with addpath ID %d", addpath_tx_id);
}
@@ -648,6 +650,7 @@ subgroup_update_packet (struct update_subgroup *subgrp)
int num_pfx = 0;
int addpath_encode = 0;
u_int32_t addpath_tx_id = 0;
+ struct prefix_rd *prd = NULL;
if (!subgrp)
return NULL;
@@ -751,7 +754,6 @@ subgroup_update_packet (struct update_subgroup *subgrp)
else
{
/* Encode the prefix in MP_REACH_NLRI attribute */
- struct prefix_rd *prd = NULL;
u_char *tag = NULL;
if (rn->prn)
@@ -764,16 +766,16 @@ subgroup_update_packet (struct update_subgroup *subgrp)
(peer_cap_enhe(peer) ? AFI_IP6 :
AFI_MAX), /* get from NH */
&vecarr, adv->baa->attr);
- bgp_packet_mpattr_prefix (snlri, afi, safi, &rn->p, prd, tag,
- addpath_encode, addpath_tx_id);
+
+ bgp_packet_mpattr_prefix (snlri, afi, safi, &rn->p, prd,
+ tag, addpath_encode, addpath_tx_id, adv->baa->attr);
}
num_pfx++;
if (bgp_debug_update(NULL, &rn->p, subgrp->update_group, 0))
{
- char buf[INET6_BUFSIZ];
- char tx_id_buf[30];
+ char pfx_buf[BGP_PRD_PATH_STRLEN];
if (!send_attr_printed)
{
@@ -782,11 +784,11 @@ subgroup_update_packet (struct update_subgroup *subgrp)
send_attr_printed = 1;
}
- bgp_info_addpath_tx_str (addpath_encode, addpath_tx_id, tx_id_buf);
- zlog_debug ("u%" PRIu64 ":s%" PRIu64 " send UPDATE %s/%d%s",
+ zlog_debug ("u%" PRIu64 ":s%" PRIu64 " send UPDATE %s",
subgrp->update_group->id, subgrp->id,
- inet_ntop (rn->p.family, &(rn->p.u.prefix), buf, INET6_BUFSIZ),
- rn->p.prefixlen, tx_id_buf);
+ bgp_debug_rdpfxpath2str (prd, &rn->p, addpath_encode,
+ addpath_tx_id,
+ pfx_buf, sizeof (pfx_buf)));
}
/* Synchnorize attribute. */
@@ -863,6 +865,8 @@ subgroup_withdraw_packet (struct update_subgroup *subgrp)
int num_pfx = 0;
int addpath_encode = 0;
u_int32_t addpath_tx_id = 0;
+ struct prefix_rd *prd = NULL;
+
if (!subgrp)
return NULL;
@@ -905,8 +909,6 @@ subgroup_withdraw_packet (struct update_subgroup *subgrp)
stream_put_prefix_addpath (s, &rn->p, addpath_encode, addpath_tx_id);
else
{
- struct prefix_rd *prd = NULL;
-
if (rn->prn)
prd = (struct prefix_rd *) &rn->prn->p;
@@ -921,20 +923,20 @@ subgroup_withdraw_packet (struct update_subgroup *subgrp)
}
bgp_packet_mpunreach_prefix (s, &rn->p, afi, safi, prd, NULL,
- addpath_encode, addpath_tx_id);
+ addpath_encode, addpath_tx_id, NULL);
}
num_pfx++;
if (bgp_debug_update(NULL, &rn->p, subgrp->update_group, 0))
{
- char buf[INET6_BUFSIZ];
- char tx_id_buf[30];
- bgp_info_addpath_tx_str (addpath_encode, addpath_tx_id, tx_id_buf);
- zlog_debug ("u%" PRIu64 ":s%" PRIu64 " send UPDATE %s/%d%s -- unreachable",
+ char pfx_buf[BGP_PRD_PATH_STRLEN];
+
+ zlog_debug ("u%" PRIu64 ":s%" PRIu64 " send UPDATE %s -- unreachable",
subgrp->update_group->id, subgrp->id,
- inet_ntop (rn->p.family, &(rn->p.u.prefix), buf, INET6_BUFSIZ),
- rn->p.prefixlen, tx_id_buf);
+ bgp_debug_rdpfxpath2str (prd, &rn->p,
+ addpath_encode, addpath_tx_id,
+ pfx_buf, sizeof (pfx_buf)));
}
subgrp->scount--;
@@ -1010,16 +1012,16 @@ subgroup_default_update_packet (struct update_subgroup *subgrp,
if (bgp_debug_update(NULL, &p, subgrp->update_group, 0))
{
char attrstr[BUFSIZ];
- char buf[INET6_BUFSIZ];
+ char buf[PREFIX_STRLEN];
char tx_id_buf[30];
attrstr[0] = '\0';
bgp_dump_attr (peer, attr, attrstr, BUFSIZ);
bgp_info_addpath_tx_str (addpath_encode, BGP_ADDPATH_TX_ID_FOR_DEFAULT_ORIGINATE, tx_id_buf);
- zlog_debug ("u%" PRIu64 ":s%" PRIu64 " send UPDATE %s/%d%s %s",
+ zlog_debug ("u%" PRIu64 ":s%" PRIu64 " send UPDATE %s%s %s",
(SUBGRP_UPDGRP (subgrp))->id, subgrp->id,
- inet_ntop (p.family, &(p.u.prefix), buf, INET6_BUFSIZ),
- p.prefixlen, tx_id_buf, attrstr);
+ prefix2str (&p, buf, sizeof (buf)),
+ tx_id_buf, attrstr);
}
s = stream_new (BGP_MAX_PACKET_SIZE);
@@ -1084,14 +1086,13 @@ subgroup_default_withdraw_packet (struct update_subgroup *subgrp)
if (bgp_debug_update(NULL, &p, subgrp->update_group, 0))
{
- char buf[INET6_BUFSIZ];
+ char buf[PREFIX_STRLEN];
char tx_id_buf[INET6_BUFSIZ];
bgp_info_addpath_tx_str (addpath_encode, BGP_ADDPATH_TX_ID_FOR_DEFAULT_ORIGINATE, tx_id_buf);
- zlog_debug ("u%" PRIu64 ":s%" PRIu64 " send UPDATE %s/%d%s -- unreachable",
+ zlog_debug ("u%" PRIu64 ":s%" PRIu64 " send UPDATE %s%s -- unreachable",
(SUBGRP_UPDGRP (subgrp))->id, subgrp->id,
- inet_ntop (p.family, &(p.u.prefix), buf, INET6_BUFSIZ),
- p.prefixlen, tx_id_buf);
+ prefix2str (&p, buf, sizeof (buf)), tx_id_buf);
}
s = stream_new (BGP_MAX_PACKET_SIZE);
@@ -1126,7 +1127,7 @@ subgroup_default_withdraw_packet (struct update_subgroup *subgrp)
mplen_pos = bgp_packet_mpunreach_start (s, afi, safi);
bgp_packet_mpunreach_prefix (s, &p, afi, safi, NULL, NULL,
addpath_encode,
- BGP_ADDPATH_TX_ID_FOR_DEFAULT_ORIGINATE);
+ BGP_ADDPATH_TX_ID_FOR_DEFAULT_ORIGINATE, NULL);
/* Set the mp_unreach attr's length */
bgp_packet_mpunreach_end (s, mplen_pos);
diff --git a/bgpd/bgp_vpn.c b/bgpd/bgp_vpn.c
new file mode 100644
index 0000000000..edc5891d22
--- /dev/null
+++ b/bgpd/bgp_vpn.c
@@ -0,0 +1,200 @@
+/* VPN Related functions
+ Copyright (C) 2017 6WIND
+
+This file is part of Free Range Routing
+
+Free Range Routing 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.
+
+Free Range Routing 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 Free Range Routing; see the file COPYING. If not, write to the Free
+Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA. */
+
+#include <zebra.h>
+#include "command.h"
+#include "prefix.h"
+#include "lib/json.h"
+
+#include "bgpd/bgpd.h"
+#include "bgpd/bgp_route.h"
+#include "bgpd/bgp_table.h"
+#include "bgpd/bgp_attr.h"
+#include "bgpd/bgp_mplsvpn.h"
+#include "bgpd/bgp_vpn.h"
+
+int
+show_adj_route_vpn (struct vty *vty, struct peer *peer, struct prefix_rd *prd,
+ afi_t afi, safi_t safi, u_char use_json)
+{
+ struct bgp *bgp;
+ struct bgp_table *table;
+ struct bgp_node *rn;
+ struct bgp_node *rm;
+ struct attr *attr;
+ int rd_header;
+ int header = 1;
+ char v4_header[] = " Network Next Hop Metric LocPrf Weight Path%s";
+ json_object *json = NULL;
+ json_object *json_scode = NULL;
+ json_object *json_ocode = NULL;
+ json_object *json_routes = NULL;
+ json_object *json_array = NULL;
+
+ bgp = bgp_get_default ();
+ if (bgp == NULL)
+ {
+ if (!use_json)
+ vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (use_json)
+ {
+ json_scode = json_object_new_object();
+ json_ocode = json_object_new_object();
+ json_routes = json_object_new_object();
+ json = json_object_new_object();
+
+ json_object_string_add(json_scode, "suppressed", "s");
+ json_object_string_add(json_scode, "damped", "d");
+ json_object_string_add(json_scode, "history", "h");
+ json_object_string_add(json_scode, "valid", "*");
+ json_object_string_add(json_scode, "best", ">");
+ json_object_string_add(json_scode, "internal", "i");
+
+ json_object_string_add(json_ocode, "igp", "i");
+ json_object_string_add(json_ocode, "egp", "e");
+ json_object_string_add(json_ocode, "incomplete", "?");
+ }
+
+ for (rn = bgp_table_top (bgp->rib[afi][SAFI_MPLS_VPN]); rn;
+ rn = bgp_route_next (rn))
+ {
+ if (prd && memcmp (rn->p.u.val, prd->val, 8) != 0)
+ continue;
+
+ if ((table = rn->info) != NULL)
+ {
+ if (use_json)
+ json_array = json_object_new_array();
+ else
+ json_array = NULL;
+
+ rd_header = 1;
+
+ for (rm = bgp_table_top (table); rm; rm = bgp_route_next (rm))
+ {
+ if ((attr = rm->info) != NULL)
+ {
+ if (header)
+ {
+ if (use_json)
+ {
+ json_object_int_add(json, "bgpTableVersion", 0);
+ json_object_string_add(json, "bgpLocalRouterId", inet_ntoa (bgp->router_id));
+ json_object_object_add(json, "bgpStatusCodes", json_scode);
+ json_object_object_add(json, "bgpOriginCodes", json_ocode);
+ }
+ else
+ {
+ vty_out (vty, "BGP table version is 0, local router ID is %s%s",
+ inet_ntoa (bgp->router_id), VTY_NEWLINE);
+ vty_out (vty, "Status codes: s suppressed, d damped, h history, * valid, > best, i - internal%s",
+ VTY_NEWLINE);
+ vty_out (vty, "Origin codes: i - IGP, e - EGP, ? - incomplete%s%s",
+ VTY_NEWLINE, VTY_NEWLINE);
+ vty_out (vty, v4_header, VTY_NEWLINE);
+ }
+ header = 0;
+ }
+
+ if (rd_header)
+ {
+ u_int16_t type;
+ struct rd_as rd_as;
+ struct rd_ip rd_ip = {0};
+#if ENABLE_BGP_VNC
+ struct rd_vnc_eth rd_vnc_eth = {0};
+#endif
+ u_char *pnt;
+
+ pnt = rn->p.u.val;
+
+ /* Decode RD type. */
+ type = decode_rd_type (pnt);
+ /* Decode RD value. */
+ if (type == RD_TYPE_AS)
+ decode_rd_as (pnt + 2, &rd_as);
+ else if (type == RD_TYPE_AS4)
+ decode_rd_as4 (pnt + 2, &rd_as);
+ else if (type == RD_TYPE_IP)
+ decode_rd_ip (pnt + 2, &rd_ip);
+#if ENABLE_BGP_VNC
+ else if (type == RD_TYPE_VNC_ETH)
+ decode_rd_vnc_eth (pnt, &rd_vnc_eth);
+#endif
+
+ if (use_json)
+ {
+ char buffer[BUFSIZ];
+ if (type == RD_TYPE_AS || type == RD_TYPE_AS4)
+ sprintf (buffer, "%u:%d", rd_as.as, rd_as.val);
+ else if (type == RD_TYPE_IP)
+ sprintf (buffer, "%s:%d", inet_ntoa (rd_ip.ip), rd_ip.val);
+ json_object_string_add(json_routes, "routeDistinguisher", buffer);
+ }
+ else
+ {
+ vty_out (vty, "Route Distinguisher: ");
+
+ if (type == RD_TYPE_AS || type == RD_TYPE_AS4)
+ vty_out (vty, "%u:%d", rd_as.as, rd_as.val);
+ else if (type == RD_TYPE_IP)
+ vty_out (vty, "%s:%d", inet_ntoa (rd_ip.ip), rd_ip.val);
+#if ENABLE_BGP_VNC
+ else if (type == RD_TYPE_VNC_ETH)
+ vty_out (vty, "%u:%02x:%02x:%02x:%02x:%02x:%02x",
+ rd_vnc_eth.local_nve_id,
+ rd_vnc_eth.macaddr.octet[0],
+ rd_vnc_eth.macaddr.octet[1],
+ rd_vnc_eth.macaddr.octet[2],
+ rd_vnc_eth.macaddr.octet[3],
+ rd_vnc_eth.macaddr.octet[4],
+ rd_vnc_eth.macaddr.octet[5]);
+#endif
+
+ vty_out (vty, "%s", VTY_NEWLINE);
+ }
+ rd_header = 0;
+ }
+ route_vty_out_tmp (vty, &rm->p, attr, SAFI_MPLS_VPN, use_json, json_array);
+ }
+ }
+ if (use_json)
+ {
+ struct prefix *p;
+ char buf_a[BUFSIZ];
+ char buf_b[BUFSIZ];
+ p = &rm->p;
+ sprintf(buf_a, "%s/%d", inet_ntop (p->family, &p->u.prefix, buf_b, BUFSIZ), p->prefixlen);
+ json_object_object_add(json_routes, buf_a, json_array);
+ }
+ }
+ }
+ if (use_json)
+ {
+ json_object_object_add(json, "routes", json_routes);
+ vty_out (vty, "%s%s", json_object_to_json_string_ext(json, JSON_C_TO_STRING_PRETTY), VTY_NEWLINE);
+ json_object_free(json);
+ }
+ return CMD_SUCCESS;
+}
+
diff --git a/bgpd/bgp_vpn.h b/bgpd/bgp_vpn.h
new file mode 100644
index 0000000000..a16914b65e
--- /dev/null
+++ b/bgpd/bgp_vpn.h
@@ -0,0 +1,30 @@
+/* VPN common functions to MP-BGP
+ Copyright (C) 2017 6WIND
+
+This file is part of Free Range Routing.
+
+Free Range Routing 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.
+
+Free Range Routing 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 Free Range Routing; see the file COPYING. If not, write to the Free
+Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA. */
+
+#ifndef _FRR_BGP_VPN_H
+#define _FRR_BGP_VPN_H
+
+#include <zebra.h>
+
+extern int
+show_adj_route_vpn (struct vty *vty, struct peer *peer, struct prefix_rd *prd,
+ afi_t afi, safi_t safi, u_char use_json);
+
+#endif /* _QUAGGA_BGP_VPN_H */
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
index b4425297b3..aa8c3145f9 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -74,6 +74,9 @@ bgp_node_afi (struct vty *vty)
case BGP_ENCAPV6_NODE:
afi = AFI_IP6;
break;
+ case BGP_EVPN_NODE:
+ afi = AFI_L2VPN;
+ break;
default:
afi = AFI_IP;
break;
@@ -101,6 +104,9 @@ bgp_node_safi (struct vty *vty)
case BGP_IPV6M_NODE:
safi = SAFI_MULTICAST;
break;
+ case BGP_EVPN_NODE:
+ safi = SAFI_EVPN;
+ break;
default:
safi = SAFI_UNICAST;
break;
@@ -119,6 +125,9 @@ bgp_vty_afi_from_arg(const char *afi_str)
else if (!strcmp(afi_str, "ipv6")) {
afi = AFI_IP6;
}
+ else if (!strcmp(afi_str, "l2vpn")) {
+ afi = AFI_L2VPN;
+ }
return afi;
}
@@ -195,6 +204,12 @@ argv_find_and_parse_safi (struct cmd_token **argv, int argc, int *index, safi_t
if (safi)
*safi = SAFI_ENCAP;
}
+ else if (argv_find (argv, argc, "evpn", index))
+ {
+ ret = 1;
+ if (safi)
+ *safi = SAFI_EVPN;
+ }
return ret;
}
@@ -5695,6 +5710,18 @@ DEFUN (address_family_encapv6,
return CMD_SUCCESS;
}
+DEFUN (address_family_evpn,
+ address_family_evpn_cmd,
+ "address-family <l2vpn evpn>",
+ "Enter Address Family command mode\n"
+ "EVPN Address family\n"
+ "Layer2 VPN Address family\n"
+ "Ethernet Virtual Private Network Subsequent Address Family\n")
+{
+ vty->node = BGP_EVPN_NODE;
+ return CMD_SUCCESS;
+}
+
DEFUN (exit_address_family,
exit_address_family_cmd,
"exit-address-family",
@@ -5707,7 +5734,8 @@ DEFUN (exit_address_family,
|| vty->node == BGP_IPV6M_NODE
|| vty->node == BGP_VPNV6_NODE
|| vty->node == BGP_ENCAP_NODE
- || vty->node == BGP_ENCAPV6_NODE)
+ || vty->node == BGP_ENCAPV6_NODE
+ || vty->node == BGP_EVPN_NODE)
vty->node = BGP_NODE;
return CMD_SUCCESS;
}
@@ -6662,7 +6690,7 @@ bgp_show_summary_afi_safi (struct vty *vty, struct bgp *bgp, int afi, int safi,
}
afi++;
if (! afi_wildcard ||
- afi == AFI_ETHER) /* special case, not handled yet */
+ afi == AFI_L2VPN) /* special case, not handled yet */
afi = AFI_MAX;
}
@@ -6806,6 +6834,8 @@ afi_safi_print (afi_t afi, safi_t safi)
return "IPv6 VPN";
else if (afi == AFI_IP6 && safi == SAFI_ENCAP)
return "IPv6 Encap";
+ else if (afi == AFI_L2VPN && safi == SAFI_EVPN)
+ return "L2VPN EVPN";
else
return "Unknown";
}
@@ -6829,6 +6859,8 @@ afi_safi_json (afi_t afi, safi_t safi)
return "IPv6VPN";
else if (afi == AFI_IP6 && safi == SAFI_ENCAP)
return "IPv6Encap";
+ else if (afi == AFI_L2VPN && safi == SAFI_EVPN)
+ return "L2VPN EVPN";
else
return "Unknown";
}
@@ -9966,6 +9998,13 @@ static struct cmd_node bgp_encapv6_node =
1
};
+static struct cmd_node bgp_evpn_node =
+{
+ BGP_EVPN_NODE,
+ "%s(config-router-evpn)# ",
+ 1
+};
+
static void community_list_vty (void);
void
@@ -9981,6 +10020,7 @@ bgp_vty_init (void)
install_node (&bgp_vpnv6_node, NULL);
install_node (&bgp_encap_node, NULL);
install_node (&bgp_encapv6_node, NULL);
+ install_node (&bgp_evpn_node, NULL);
/* Install default VTY commands to new nodes. */
install_default (BGP_NODE);
@@ -9992,6 +10032,7 @@ bgp_vty_init (void)
install_default (BGP_VPNV6_NODE);
install_default (BGP_ENCAP_NODE);
install_default (BGP_ENCAPV6_NODE);
+ install_default (BGP_EVPN_NODE);
/* "bgp multiple-instance" commands. */
install_element (CONFIG_NODE, &bgp_multiple_instance_cmd);
@@ -10205,6 +10246,7 @@ bgp_vty_init (void)
install_element (BGP_VPNV6_NODE, &neighbor_activate_cmd);
install_element (BGP_ENCAP_NODE, &neighbor_activate_cmd);
install_element (BGP_ENCAPV6_NODE, &neighbor_activate_cmd);
+ install_element (BGP_EVPN_NODE, &neighbor_activate_cmd);
/* "no neighbor activate" commands. */
install_element (BGP_NODE, &no_neighbor_activate_cmd);
@@ -10216,6 +10258,7 @@ bgp_vty_init (void)
install_element (BGP_VPNV6_NODE, &no_neighbor_activate_cmd);
install_element (BGP_ENCAP_NODE, &no_neighbor_activate_cmd);
install_element (BGP_ENCAPV6_NODE, &no_neighbor_activate_cmd);
+ install_element (BGP_EVPN_NODE, &no_neighbor_activate_cmd);
/* "neighbor peer-group" set commands.
* Long term we should only accept this command under BGP_NODE and not all of
@@ -10286,6 +10329,9 @@ bgp_vty_init (void)
install_element (BGP_ENCAPV6_NODE, &neighbor_attr_unchanged_cmd);
install_element (BGP_ENCAPV6_NODE, &no_neighbor_attr_unchanged_cmd);
+ install_element (BGP_EVPN_NODE, &neighbor_attr_unchanged_cmd);
+ install_element (BGP_EVPN_NODE, &no_neighbor_attr_unchanged_cmd);
+
/* "nexthop-local unchanged" commands */
install_element (BGP_IPV6_NODE, &neighbor_nexthop_local_unchanged_cmd);
install_element (BGP_IPV6_NODE, &no_neighbor_nexthop_local_unchanged_cmd);
@@ -10828,6 +10874,8 @@ bgp_vty_init (void)
install_element (BGP_NODE, &address_family_encap_cmd);
install_element (BGP_NODE, &address_family_encapv6_cmd);
+ install_element (BGP_NODE, &address_family_evpn_cmd);
+
/* "exit-address-family" command. */
install_element (BGP_IPV4_NODE, &exit_address_family_cmd);
install_element (BGP_IPV4M_NODE, &exit_address_family_cmd);
@@ -10837,6 +10885,7 @@ bgp_vty_init (void)
install_element (BGP_VPNV6_NODE, &exit_address_family_cmd);
install_element (BGP_ENCAP_NODE, &exit_address_family_cmd);
install_element (BGP_ENCAPV6_NODE, &exit_address_family_cmd);
+ install_element (BGP_EVPN_NODE, &exit_address_family_cmd);
/* "clear ip bgp commands" */
install_element (ENABLE_NODE, &clear_ip_bgp_all_cmd);
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index fc6968e9d9..3512167b02 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -66,6 +66,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "bgpd/rfapi/bgp_rfapi_cfg.h"
#include "bgpd/rfapi/rfapi_backend.h"
#endif
+#include "bgpd/bgp_evpn.h"
#include "bgpd/bgp_advertise.h"
#include "bgpd/bgp_network.h"
#include "bgpd/bgp_vty.h"
@@ -77,6 +78,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "bgpd/bgp_updgrp.h"
#include "bgpd/bgp_bfd.h"
#include "bgpd/bgp_memory.h"
+#include "bgpd/bgp_evpn_vty.h"
DEFINE_QOBJ_TYPE(bgp_master)
DEFINE_QOBJ_TYPE(bgp)
@@ -1643,6 +1645,8 @@ peer_as_change (struct peer *peer, as_t as, int as_specified)
PEER_FLAG_REFLECTOR_CLIENT);
UNSET_FLAG (peer->af_flags[AFI_IP6][SAFI_ENCAP],
PEER_FLAG_REFLECTOR_CLIENT);
+ UNSET_FLAG (peer->af_flags[AFI_L2VPN][SAFI_EVPN],
+ PEER_FLAG_REFLECTOR_CLIENT);
}
/* local-as reset */
@@ -7217,7 +7221,11 @@ bgp_config_write_family_header (struct vty *vty, afi_t afi, safi_t safi,
else if (safi == SAFI_ENCAP)
vty_out (vty, "ipv6 encap");
}
-
+ else if (afi == AFI_L2VPN)
+ {
+ if (safi == SAFI_EVPN)
+ vty_out (vty, "l2vpn evpn");
+ }
vty_out (vty, "%s", VTY_NEWLINE);
*write = 1;
@@ -7518,6 +7526,9 @@ bgp_config_write (struct vty *vty)
/* ENCAPv6 configuration. */
write += bgp_config_write_family (vty, bgp, AFI_IP6, SAFI_ENCAP);
+ /* EVPN configuration. */
+ write += bgp_config_write_family (vty, bgp, AFI_L2VPN, SAFI_EVPN);
+
#if ENABLE_BGP_VNC
write += bgp_rfapi_cfg_write(vty, bgp);
#endif
@@ -7615,6 +7626,7 @@ bgp_init (void)
#if ENABLE_BGP_VNC
rfapi_init ();
#endif
+ bgp_ethernetvpn_init ();
/* Access list initialize. */
access_list_init ();
diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h
index 2eef04e1d1..09c64aa331 100644
--- a/bgpd/bgpd.h
+++ b/bgpd/bgpd.h
@@ -73,6 +73,7 @@ enum bgp_af_index
BGP_AF_IPV6_VPN,
BGP_AF_IPV4_ENCAP,
BGP_AF_IPV6_ENCAP,
+ BGP_AF_L2VPN_EVPN,
BGP_AF_MAX
};
@@ -1414,6 +1415,16 @@ afindex (afi_t afi, safi_t safi)
break;
}
break;
+ case AFI_L2VPN:
+ switch (safi)
+ {
+ case SAFI_EVPN:
+ return BGP_AF_L2VPN_EVPN;
+ break;
+ default:
+ return BGP_AF_MAX;
+ break;
+ }
default:
return BGP_AF_MAX;
break;
diff --git a/bgpd/rfapi/bgp_rfapi_cfg.c b/bgpd/rfapi/bgp_rfapi_cfg.c
index 50693659b6..71086c8758 100644
--- a/bgpd/rfapi/bgp_rfapi_cfg.c
+++ b/bgpd/rfapi/bgp_rfapi_cfg.c
@@ -4352,7 +4352,7 @@ bgp_rfapi_cfg_write (struct vty *vty, struct bgp *bgp)
ecommunity_cmp (rfg->rt_import_list, rfg->rt_export_list))
{
char *b = ecommunity_ecom2str (rfg->rt_import_list,
- ECOMMUNITY_FORMAT_ROUTE_MAP);
+ ECOMMUNITY_FORMAT_ROUTE_MAP, ECOMMUNITY_ROUTE_TARGET);
vty_out (vty, " rt both %s%s", b, VTY_NEWLINE);
XFREE (MTYPE_ECOMMUNITY_STR, b);
}
@@ -4361,14 +4361,14 @@ bgp_rfapi_cfg_write (struct vty *vty, struct bgp *bgp)
if (rfg->rt_import_list)
{
char *b = ecommunity_ecom2str (rfg->rt_import_list,
- ECOMMUNITY_FORMAT_ROUTE_MAP);
+ ECOMMUNITY_FORMAT_ROUTE_MAP, ECOMMUNITY_ROUTE_TARGET);
vty_out (vty, " rt import %s%s", b, VTY_NEWLINE);
XFREE (MTYPE_ECOMMUNITY_STR, b);
}
if (rfg->rt_export_list)
{
char *b = ecommunity_ecom2str (rfg->rt_export_list,
- ECOMMUNITY_FORMAT_ROUTE_MAP);
+ ECOMMUNITY_FORMAT_ROUTE_MAP, ECOMMUNITY_ROUTE_TARGET);
vty_out (vty, " rt export %s%s", b, VTY_NEWLINE);
XFREE (MTYPE_ECOMMUNITY_STR, b);
}
@@ -4483,7 +4483,7 @@ bgp_rfapi_cfg_write (struct vty *vty, struct bgp *bgp)
ecommunity_cmp (rfg->rt_import_list, rfg->rt_export_list))
{
char *b = ecommunity_ecom2str (rfg->rt_import_list,
- ECOMMUNITY_FORMAT_ROUTE_MAP);
+ ECOMMUNITY_FORMAT_ROUTE_MAP, ECOMMUNITY_ROUTE_TARGET);
vty_out (vty, " rt both %s%s", b, VTY_NEWLINE);
XFREE (MTYPE_ECOMMUNITY_STR, b);
}
@@ -4492,14 +4492,14 @@ bgp_rfapi_cfg_write (struct vty *vty, struct bgp *bgp)
if (rfg->rt_import_list)
{
char *b = ecommunity_ecom2str (rfg->rt_import_list,
- ECOMMUNITY_FORMAT_ROUTE_MAP);
+ ECOMMUNITY_FORMAT_ROUTE_MAP, ECOMMUNITY_ROUTE_TARGET);
vty_out (vty, " rt import %s%s", b, VTY_NEWLINE);
XFREE (MTYPE_ECOMMUNITY_STR, b);
}
if (rfg->rt_export_list)
{
char *b = ecommunity_ecom2str (rfg->rt_export_list,
- ECOMMUNITY_FORMAT_ROUTE_MAP);
+ ECOMMUNITY_FORMAT_ROUTE_MAP, ECOMMUNITY_ROUTE_TARGET);
vty_out (vty, " rt export %s%s", b, VTY_NEWLINE);
XFREE (MTYPE_ECOMMUNITY_STR, b);
}
@@ -4570,7 +4570,7 @@ bgp_rfapi_cfg_write (struct vty *vty, struct bgp *bgp)
hc->default_rt_export_list))
{
char *b = ecommunity_ecom2str (hc->default_rt_import_list,
- ECOMMUNITY_FORMAT_ROUTE_MAP);
+ ECOMMUNITY_FORMAT_ROUTE_MAP, ECOMMUNITY_ROUTE_TARGET);
vty_out (vty, " rt both %s%s", b, VTY_NEWLINE);
XFREE (MTYPE_ECOMMUNITY_STR, b);
}
@@ -4579,14 +4579,14 @@ bgp_rfapi_cfg_write (struct vty *vty, struct bgp *bgp)
if (hc->default_rt_import_list)
{
char *b = ecommunity_ecom2str (hc->default_rt_import_list,
- ECOMMUNITY_FORMAT_ROUTE_MAP);
+ ECOMMUNITY_FORMAT_ROUTE_MAP, ECOMMUNITY_ROUTE_TARGET);
vty_out (vty, " rt import %s%s", b, VTY_NEWLINE);
XFREE (MTYPE_ECOMMUNITY_STR, b);
}
if (hc->default_rt_export_list)
{
char *b = ecommunity_ecom2str (hc->default_rt_export_list,
- ECOMMUNITY_FORMAT_ROUTE_MAP);
+ ECOMMUNITY_FORMAT_ROUTE_MAP, ECOMMUNITY_ROUTE_TARGET);
vty_out (vty, " rt export %s%s", b, VTY_NEWLINE);
XFREE (MTYPE_ECOMMUNITY_STR, b);
}
@@ -4685,7 +4685,8 @@ bgp_rfapi_cfg_write (struct vty *vty, struct bgp *bgp)
ecommunity_cmp (rfg->rt_import_list, rfg->rt_export_list))
{
char *b = ecommunity_ecom2str (rfg->rt_import_list,
- ECOMMUNITY_FORMAT_ROUTE_MAP);
+ ECOMMUNITY_FORMAT_ROUTE_MAP,
+ ECOMMUNITY_ROUTE_TARGET);
vty_out (vty, " rt both %s%s", b, VTY_NEWLINE);
XFREE (MTYPE_ECOMMUNITY_STR, b);
}
@@ -4694,14 +4695,15 @@ bgp_rfapi_cfg_write (struct vty *vty, struct bgp *bgp)
if (rfg->rt_import_list)
{
char *b = ecommunity_ecom2str (rfg->rt_import_list,
- ECOMMUNITY_FORMAT_ROUTE_MAP);
+ ECOMMUNITY_FORMAT_ROUTE_MAP,
+ ECOMMUNITY_ROUTE_TARGET);
vty_out (vty, " rt import %s%s", b, VTY_NEWLINE);
XFREE (MTYPE_ECOMMUNITY_STR, b);
}
if (rfg->rt_export_list)
{
char *b = ecommunity_ecom2str (rfg->rt_export_list,
- ECOMMUNITY_FORMAT_ROUTE_MAP);
+ ECOMMUNITY_FORMAT_ROUTE_MAP, ECOMMUNITY_ROUTE_TARGET);
vty_out (vty, " rt export %s%s", b, VTY_NEWLINE);
XFREE (MTYPE_ECOMMUNITY_STR, b);
}
diff --git a/bgpd/rfapi/rfapi.c b/bgpd/rfapi/rfapi.c
index 3cf09e240e..99d26cf13c 100644
--- a/bgpd/rfapi/rfapi.c
+++ b/bgpd/rfapi/rfapi.c
@@ -1451,7 +1451,7 @@ rfapi_open_inner (
#define RFD_RTINIT(rh, ary) do {\
RFD_RTINIT_AFI(rh, ary, AFI_IP);\
RFD_RTINIT_AFI(rh, ary, AFI_IP6);\
- RFD_RTINIT_AFI(rh, ary, AFI_ETHER);\
+ RFD_RTINIT_AFI(rh, ary, AFI_L2VPN);\
} while(0)
RFD_RTINIT(rfd, rfd->rib);
@@ -1733,7 +1733,7 @@ rfapi_query_inner (
__func__, rfd, buf, ppNextHopEntry);
s = ecommunity_ecom2str(rfd->import_table->rt_import_list,
- ECOMMUNITY_FORMAT_ROUTE_MAP);
+ ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
vnc_zlog_debug_verbose("%s rfd->import_table=%p, rfd->import_table->rt_import_list: %s",
__func__, rfd->import_table, s); XFREE (MTYPE_ECOMMUNITY_STR, s);
}
@@ -3809,7 +3809,7 @@ DEFUN (debug_rfapi_show_import,
for (it = h->imports; it; it = it->next)
{
s = ecommunity_ecom2str (it->rt_import_list,
- ECOMMUNITY_FORMAT_ROUTE_MAP);
+ ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
vty_out (vty, "Import Table %p, RTs: %s%s", it, s, VTY_NEWLINE);
XFREE (MTYPE_ECOMMUNITY_STR, s);
@@ -3835,7 +3835,7 @@ DEFUN (debug_rfapi_show_import,
&cursor))
{
- if (it->imported_vpn[AFI_ETHER])
+ if (it->imported_vpn[AFI_L2VPN])
{
lni = lni_as_ptr;
if (first_l2)
@@ -3845,7 +3845,7 @@ DEFUN (debug_rfapi_show_import,
first_l2 = 0;
}
snprintf (buf, BUFSIZ, "L2VPN LNI=%u", lni);
- rfapiShowImportTable (vty, buf, it->imported_vpn[AFI_ETHER], 1);
+ rfapiShowImportTable (vty, buf, it->imported_vpn[AFI_L2VPN], 1);
}
}
}
diff --git a/bgpd/rfapi/rfapi_import.c b/bgpd/rfapi/rfapi_import.c
index 9ae3311e15..4a05018d23 100644
--- a/bgpd/rfapi/rfapi_import.c
+++ b/bgpd/rfapi/rfapi_import.c
@@ -1091,8 +1091,8 @@ rfapiEcommunitiesIntersect (struct ecommunity *e1, struct ecommunity *e2)
{
char *s1, *s2;
- s1 = ecommunity_ecom2str (e1, ECOMMUNITY_FORMAT_DISPLAY);
- s2 = ecommunity_ecom2str (e2, ECOMMUNITY_FORMAT_DISPLAY);
+ s1 = ecommunity_ecom2str (e1, ECOMMUNITY_FORMAT_DISPLAY, 0);
+ s2 = ecommunity_ecom2str (e2, ECOMMUNITY_FORMAT_DISPLAY, 0);
vnc_zlog_debug_verbose ("%s: e1[%s], e2[%s]", __func__, s1, s2);
XFREE (MTYPE_ECOMMUNITY_STR, s1);
XFREE (MTYPE_ECOMMUNITY_STR, s2);
@@ -2077,7 +2077,7 @@ rfapiEthRouteTable2NextHopList (
it = rfapiMacImportTableGet (bgp, logical_net_id);
- rt = it->imported_vpn[AFI_ETHER];
+ rt = it->imported_vpn[AFI_L2VPN];
for (rn = route_top (rt); rn; rn = route_next (rn))
{
@@ -3607,7 +3607,7 @@ rfapiBgpInfoFilteredImportVPN (
struct peer *peer,
void *rfd, /* set for looped back routes */
struct prefix *p,
- struct prefix *aux_prefix, /* AFI_ETHER: optional IP */
+ struct prefix *aux_prefix, /* AFI_L2VPN: optional IP */
afi_t afi,
struct prefix_rd *prd,
struct attr *attr, /* part of bgp_info */
@@ -3702,7 +3702,7 @@ rfapiBgpInfoFilteredImportVPN (
{
case AFI_IP:
case AFI_IP6:
- case AFI_ETHER:
+ case AFI_L2VPN:
rt = import_table->imported_vpn[afi];
break;
@@ -3909,7 +3909,7 @@ rfapiBgpInfoFilteredImportVPN (
* For ethernet routes, if there is an accompanying IP address,
* save it in the bi
*/
- if ((AFI_ETHER == afi) && aux_prefix)
+ if ((AFI_L2VPN == afi) && aux_prefix)
{
vnc_zlog_debug_verbose ("%s: setting BI's aux_prefix", __func__);
@@ -4178,7 +4178,7 @@ rfapiProcessUpdate (
rfd,
&pfx_mac_buf, /* prefix */
p, /* aux prefix: IP addr */
- AFI_ETHER,
+ AFI_L2VPN,
prd,
attr,
type,
@@ -4291,7 +4291,7 @@ rfapiProcessWithdraw (
#if DEBUG_L2_EXTRA
vnc_zlog_debug_verbose
- ("%s: calling rfapiBgpInfoFilteredImportVPN(it=%p, afi=AFI_ETHER)",
+ ("%s: calling rfapiBgpInfoFilteredImportVPN(it=%p, afi=AFI_L2VPN)",
__func__, it);
#endif
@@ -4302,7 +4302,7 @@ rfapiProcessWithdraw (
rfd,
&pfx_mac_buf, /* prefix */
p, /* aux_prefix: IP */
- AFI_ETHER,
+ AFI_L2VPN,
prd,
attr,
type,
@@ -4808,7 +4808,7 @@ rfapiDeleteRemotePrefixesIt (
vnc_zlog_debug_verbose ("%s: rn pfx=%s", __func__, buf_pfx);
}
- /* TBD is this valid for afi == AFI_ETHER? */
+ /* TBD is this valid for afi == AFI_L2VPN? */
RFAPI_CHECK_REFCOUNT (rn, SAFI_MPLS_VPN, 1);
for (bi = rn->info; bi; bi = next)
@@ -5166,10 +5166,10 @@ rfapiCountAllItRoutes (int *pALRcount, /* active local routes */
rc = skiplist_next (h->import_mac, NULL, (void **) &it, &cursor))
{
- total_active_local += it->local_count[AFI_ETHER];
- total_active_remote += it->remote_count[AFI_ETHER];
- total_holddown += it->holddown_count[AFI_ETHER];
- total_imported += it->imported_count[AFI_ETHER];
+ total_active_local += it->local_count[AFI_L2VPN];
+ total_active_remote += it->remote_count[AFI_L2VPN];
+ total_holddown += it->holddown_count[AFI_L2VPN];
+ total_imported += it->imported_count[AFI_L2VPN];
}
}
diff --git a/bgpd/rfapi/rfapi_monitor.c b/bgpd/rfapi/rfapi_monitor.c
index c051b9b3e0..a9e6e4f934 100644
--- a/bgpd/rfapi/rfapi_monitor.c
+++ b/bgpd/rfapi/rfapi_monitor.c
@@ -941,7 +941,7 @@ rfapiMonitorItNodeChanged (
__func__, import_table, it_node, buf_prefix);
#endif
- if (AFI_ETHER == afi)
+ if (AFI_L2VPN == afi)
{
struct rfapi_monitor_eth *m;
struct skiplist *sl;
@@ -1044,7 +1044,7 @@ rfapiMonitorItNodeChanged (
/*
* All-routes L2 monitors
*/
- if (AFI_ETHER == afi)
+ if (AFI_L2VPN == afi)
{
struct rfapi_monitor_eth *e;
@@ -1305,7 +1305,7 @@ rfapiMonitorEthAttachImportHd (struct bgp *bgp, struct rfapi_descriptor *rfd)
pfx_mac_buf.prefixlen = 48;
pfx_mac_buf.u.prefix_eth = mon->macaddr;
- rn = route_node_get (it->imported_vpn[AFI_ETHER], &pfx_mac_buf);
+ rn = route_node_get (it->imported_vpn[AFI_L2VPN], &pfx_mac_buf);
assert (rn);
(void) rfapiMonitorEthAttachImport (it, rn, mon);
@@ -1361,7 +1361,7 @@ rfapiMonitorEthDetachImport (
pfx_mac_buf.prefixlen = 48;
pfx_mac_buf.u.prefix_eth = mon->macaddr;
- rn = route_node_get (it->imported_vpn[AFI_ETHER], &pfx_mac_buf);
+ rn = route_node_get (it->imported_vpn[AFI_L2VPN], &pfx_mac_buf);
assert (rn);
#if DEBUG_L2_EXTRA
@@ -1423,7 +1423,7 @@ rfapiMonitorEthAdd (
if (!RFAPI_0_ETHERADDR (macaddr))
{
- rn = route_node_get (it->imported_vpn[AFI_ETHER], &pfx_mac_buf);
+ rn = route_node_get (it->imported_vpn[AFI_L2VPN], &pfx_mac_buf);
assert (rn);
}
@@ -1635,7 +1635,7 @@ rfapiMonitorCallbacksOff (struct bgp *bgp)
/*
* The actual route table
*/
- rt = it->imported_vpn[AFI_ETHER];
+ rt = it->imported_vpn[AFI_L2VPN];
/*
* Find non-0 monitors (i.e., actual addresses, not FTD monitors)
diff --git a/bgpd/rfapi/rfapi_private.h b/bgpd/rfapi/rfapi_private.h
index 8ac2966bfe..a5e3970549 100644
--- a/bgpd/rfapi/rfapi_private.h
+++ b/bgpd/rfapi/rfapi_private.h
@@ -133,7 +133,7 @@ struct rfapi_descriptor
uint32_t flags;
#define RFAPI_HD_FLAG_CALLBACK_SCHEDULED_AFI_IP 0x00000001
#define RFAPI_HD_FLAG_CALLBACK_SCHEDULED_AFI_IP6 0x00000002
-#define RFAPI_HD_FLAG_CALLBACK_SCHEDULED_AFI_ETHER 0x00000004
+#define RFAPI_HD_FLAG_CALLBACK_SCHEDULED_AFI_L2VPN 0x00000004
#define RFAPI_HD_FLAG_PROVISIONAL 0x00000008
#define RFAPI_HD_FLAG_CLOSING_ADMINISTRATIVELY 0x00000010
#define RFAPI_HD_FLAG_IS_VRF 0x00000012
@@ -142,7 +142,7 @@ struct rfapi_descriptor
#define RFAPI_QUEUED_FLAG(afi) ( \
((afi) == AFI_IP)? RFAPI_HD_FLAG_CALLBACK_SCHEDULED_AFI_IP: \
(((afi) == AFI_IP6)? RFAPI_HD_FLAG_CALLBACK_SCHEDULED_AFI_IP6: \
- (((afi) == AFI_ETHER)? RFAPI_HD_FLAG_CALLBACK_SCHEDULED_AFI_ETHER: \
+ (((afi) == AFI_L2VPN)? RFAPI_HD_FLAG_CALLBACK_SCHEDULED_AFI_L2VPN: \
(assert(0), 0) )))
diff --git a/bgpd/rfapi/rfapi_rib.c b/bgpd/rfapi/rfapi_rib.c
index 8e5d47415f..d633023dcf 100644
--- a/bgpd/rfapi/rfapi_rib.c
+++ b/bgpd/rfapi/rfapi_rib.c
@@ -916,7 +916,7 @@ process_pending_node (
vnc_zlog_debug_verbose ("%s: afi=%d, %s pn->info=%p",
__func__, afi, buf_prefix, pn->info);
- if (AFI_ETHER != afi)
+ if (AFI_L2VPN != afi)
{
rfapiQprefix2Rprefix (&pn->p, &hp);
}
@@ -1246,7 +1246,7 @@ callback:
else
{
new->prefix = hp;
- if (AFI_ETHER == afi)
+ if (AFI_L2VPN == afi)
{
/* hp is 0; need to set length to match AF of vn */
new->prefix.length =
@@ -1334,7 +1334,7 @@ callback:
else
{
new->prefix = hp;
- if (AFI_ETHER == afi)
+ if (AFI_L2VPN == afi)
{
/* hp is 0; need to set length to match AF of vn */
new->prefix.length =
@@ -1976,7 +1976,7 @@ rfapiRibPreload (
continue;
}
- afi = AFI_ETHER;
+ afi = AFI_L2VPN;
rfapiL2o2Qprefix (pL2o, &pfx);
}
else
@@ -2181,7 +2181,7 @@ rfapiRibPendingDeleteRoute (
vnc_zlog_debug_verbose ("%s: entry, it=%p, afi=%d, it_node=%p, pfx=%s",
__func__, it, afi, it_node, buf);
- if (AFI_ETHER == afi)
+ if (AFI_L2VPN == afi)
{
/*
* ethernet import tables are per-LNI and each ethernet monitor
diff --git a/bgpd/rfapi/rfapi_vty.c b/bgpd/rfapi/rfapi_vty.c
index 8ddb724f52..1f3066b5c5 100644
--- a/bgpd/rfapi/rfapi_vty.c
+++ b/bgpd/rfapi/rfapi_vty.c
@@ -472,7 +472,7 @@ rfapi_vty_out_vncinfo (
if (bi->attr && bi->attr->extra && bi->attr->extra->ecommunity)
{
s = ecommunity_ecom2str (bi->attr->extra->ecommunity,
- ECOMMUNITY_FORMAT_ROUTE_MAP);
+ ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
vty_out (vty, " EC{%s}", s);
XFREE (MTYPE_ECOMMUNITY_STR, s);
}
@@ -676,7 +676,7 @@ rfapiPrintBi (void *stream, struct bgp_info *bi)
if (bi->attr->extra->ecommunity)
{
s = ecommunity_ecom2str (bi->attr->extra->ecommunity,
- ECOMMUNITY_FORMAT_ROUTE_MAP);
+ ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
r = snprintf (p, REMAIN, " %s", s);
INCP;
XFREE (MTYPE_ECOMMUNITY_STR, s);
@@ -1329,7 +1329,7 @@ rfapiShowRemoteRegistrationsIt (
int show_local,
int show_remote,
int show_imported, /* either/or */
- uint32_t *pLni) /* AFI_ETHER only */
+ uint32_t *pLni) /* AFI_L2VPN only */
{
afi_t afi;
int printed_rtlist_hdr = 0;
@@ -1433,7 +1433,7 @@ rfapiShowRemoteRegistrationsIt (
}
s = ecommunity_ecom2str (it->rt_import_list,
- ECOMMUNITY_FORMAT_ROUTE_MAP);
+ ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
if (pLni)
{
@@ -1807,7 +1807,7 @@ rfapiPrintDescriptor (struct vty *vty, struct rfapi_descriptor *rfd)
{
s =
ecommunity_ecom2str (rfd->rt_export_list,
- ECOMMUNITY_FORMAT_ROUTE_MAP);
+ ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
vty_out (vty, " Export %s%s", s, HVTY_NEWLINE);
XFREE (MTYPE_ECOMMUNITY_STR, s);
}
@@ -1820,7 +1820,7 @@ rfapiPrintDescriptor (struct vty *vty, struct rfapi_descriptor *rfd)
if (rfd->import_table)
{
s = ecommunity_ecom2str (rfd->import_table->rt_import_list,
- ECOMMUNITY_FORMAT_ROUTE_MAP);
+ ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
vty_out (vty, " Import %s%s", s, HVTY_NEWLINE);
XFREE (MTYPE_ECOMMUNITY_STR, s);
}
diff --git a/bgpd/rfapi/vnc_export_bgp.c b/bgpd/rfapi/vnc_export_bgp.c
index f20e9ed674..9b2dc25823 100644
--- a/bgpd/rfapi/vnc_export_bgp.c
+++ b/bgpd/rfapi/vnc_export_bgp.c
@@ -340,7 +340,7 @@ vnc_direct_bgp_add_route_ce (
iattr, /* bgp_update copies this attr */
afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT, BGP_ROUTE_REDISTRIBUTE, NULL, /* RD not used for unicast */
NULL, /* tag not used for unicast */
- 0);
+ 0, NULL); /* EVPN not used */
bgp_attr_unintern (&iattr);
}
@@ -425,7 +425,7 @@ vnc_direct_bgp_del_route_ce (
0, /* addpath_id */
NULL, /* attr, ignored */
afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT, BGP_ROUTE_REDISTRIBUTE, NULL, /* RD not used for unicast */
- NULL); /* tag not used for unicast */
+ NULL, NULL); /* tag not used for unicast */
}
@@ -534,7 +534,7 @@ vnc_direct_bgp_vpn_disable_ce (struct bgp *bgp, afi_t afi)
0, /* addpath_id */
NULL, /* ignored */
AFI_IP, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT, BGP_ROUTE_REDISTRIBUTE, NULL, /* RD not used for unicast */
- NULL); /* tag not used for unicast */
+ NULL, NULL); /* tag not used for unicast */
}
}
}
@@ -911,7 +911,7 @@ vnc_direct_bgp_add_prefix (
iattr, /* bgp_update copies it */
afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT, BGP_ROUTE_REDISTRIBUTE, NULL, /* RD not used for unicast */
NULL, /* tag not used for unicast */
- 0);
+ 0, NULL); /* EVPN not used */
bgp_attr_unintern (&iattr);
}
@@ -1011,7 +1011,7 @@ vnc_direct_bgp_del_prefix (
0, /* addpath_id */
NULL, /* attr, ignored */
afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT, BGP_ROUTE_REDISTRIBUTE, NULL, /* RD not used for unicast */
- NULL); /* tag not used for unicast */
+ NULL, NULL); /* tag not used for unicast */
}
}
}
@@ -1150,7 +1150,7 @@ vnc_direct_bgp_add_nve (struct bgp *bgp, struct rfapi_descriptor *rfd)
iattr, /* bgp_update copies it */
afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT, BGP_ROUTE_REDISTRIBUTE, NULL, /* RD not used for unicast */
NULL, /* tag not used for unicast */
- 0);
+ 0, NULL); /* EVPN not used */
bgp_attr_unintern (&iattr);
@@ -1250,7 +1250,7 @@ vnc_direct_bgp_del_nve (struct bgp *bgp, struct rfapi_descriptor *rfd)
0, /* addpath_id */
NULL, /* attr, ignored */
afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT, BGP_ROUTE_REDISTRIBUTE, NULL, /* RD not used for unicast */
- NULL); /* tag not used for unicast */
+ NULL, NULL); /* tag not used for unicast */
}
}
@@ -1377,7 +1377,7 @@ vnc_direct_bgp_add_group_afi (
iattr, /* bgp_update copies it */
afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT, BGP_ROUTE_REDISTRIBUTE, NULL, /* RD not used for unicast */
NULL, /* tag not used for unicast */
- 0);
+ 0, NULL); /* EVPN not used */
bgp_attr_unintern (&iattr);
}
@@ -1462,7 +1462,7 @@ vnc_direct_bgp_del_group_afi (
0, /* addpath_id */
NULL, /* attr, ignored */
afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT, BGP_ROUTE_REDISTRIBUTE, NULL, /* RD not used for unicast */
- NULL); /* tag not used for unicast */
+ NULL, NULL); /* tag not used for unicast */
}
}
@@ -1540,7 +1540,7 @@ vnc_direct_bgp_unexport_table (
0, /* addpath_id */
NULL, /* attr, ignored */
afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT, BGP_ROUTE_REDISTRIBUTE, NULL, /* RD not used for unicast */
- NULL); /* tag not used for unicast */
+ NULL, NULL); /* tag not used for unicast, EVPN neither */
}
}
@@ -1777,8 +1777,8 @@ vnc_direct_bgp_rh_add_route (
0, /* addpath_id */
iattr, /* bgp_update copies this attr */
afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT_RH, BGP_ROUTE_REDISTRIBUTE, NULL, /* RD not used for unicast */
- NULL, /* tag not used for unicast */
- 0);
+ NULL, /* tag not used for unicast, EVPN neither */
+ 0, NULL); /* EVPN not used */
bgp_attr_unintern (&iattr);
}
@@ -1801,7 +1801,7 @@ vncExportWithdrawTimer (struct thread *t)
eti->type,
eti->subtype,
NULL, /* RD not used for unicast */
- NULL); /* tag not used for unicast */
+ NULL, NULL); /* tag not used for unicast, EVPN neither */
/*
* Free the eti
@@ -2019,8 +2019,8 @@ vnc_direct_bgp_rh_vpn_enable (struct bgp *bgp, afi_t afi)
0, /* addpath_id */
iattr, /* bgp_update copies it */
AFI_IP, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT_RH, BGP_ROUTE_REDISTRIBUTE, NULL, /* RD not used for unicast */
- NULL, /* tag not used for unicast */
- 0);
+ NULL, /* tag not used for unicast, EVPN neither */
+ 0, NULL); /* EVPN not used */
bgp_attr_unintern (&iattr);
}
}
@@ -2085,7 +2085,7 @@ vnc_direct_bgp_rh_vpn_disable (struct bgp *bgp, afi_t afi)
0, /* addpath_id */
NULL, /* ignored */
AFI_IP, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT_RH, BGP_ROUTE_REDISTRIBUTE, NULL, /* RD not used for unicast */
- NULL); /* tag not used for unicast */
+ NULL, NULL); /* tag not used for unicast, EVPN neither */
}
}
}
diff --git a/lib/command.c b/lib/command.c
index b166d8e0da..24272ccd1e 100644
--- a/lib/command.c
+++ b/lib/command.c
@@ -1055,6 +1055,7 @@ node_parent ( enum node_type node )
case BGP_IPV4M_NODE:
case BGP_IPV6_NODE:
case BGP_IPV6M_NODE:
+ case BGP_EVPN_NODE:
ret = BGP_NODE;
break;
case KEYCHAIN_KEY_NODE:
@@ -1421,6 +1422,7 @@ cmd_exit (struct vty *vty)
case BGP_VNC_L2_GROUP_NODE:
case BGP_IPV6_NODE:
case BGP_IPV6M_NODE:
+ case BGP_EVPN_NODE:
vty->node = BGP_NODE;
break;
case LDP_IPV4_NODE:
@@ -1489,6 +1491,7 @@ DEFUN (config_end,
case BGP_IPV4M_NODE:
case BGP_IPV6_NODE:
case BGP_IPV6M_NODE:
+ case BGP_EVPN_NODE:
case RMAP_NODE:
case OSPF_NODE:
case OSPF6_NODE:
diff --git a/lib/command.h b/lib/command.h
index 29283418ce..d62f7655ee 100644
--- a/lib/command.h
+++ b/lib/command.h
@@ -105,6 +105,7 @@ enum node_type
BGP_VNC_NVE_GROUP_NODE, /* BGP VNC nve group */
BGP_VNC_L2_GROUP_NODE, /* BGP VNC L2 group */
RFP_DEFAULTS_NODE, /* RFP defaults node */
+ BGP_EVPN_NODE, /* BGP EVPN node. */
OSPF_NODE, /* OSPF protocol mode */
OSPF6_NODE, /* OSPF protocol for IPv6 mode */
LDP_NODE, /* LDP protocol mode */
diff --git a/lib/plist.c b/lib/plist.c
index 4539d82972..9a2fc4af09 100644
--- a/lib/plist.c
+++ b/lib/plist.c
@@ -972,7 +972,7 @@ vty_prefix_list_install (struct vty *vty, afi_t afi, const char *name,
apply_mask_ipv6 ((struct prefix_ipv6 *) &p_tmp);
break;
- case AFI_ETHER:
+ case AFI_L2VPN:
default:
vty_out (vty, "%% Unrecognized AFI (%d)%s", afi, VTY_NEWLINE);
return CMD_WARNING;
diff --git a/lib/prefix.c b/lib/prefix.c
index 7231715a52..dec22a44a3 100644
--- a/lib/prefix.c
+++ b/lib/prefix.c
@@ -209,7 +209,7 @@ afi2family (afi_t afi)
return AF_INET;
else if (afi == AFI_IP6)
return AF_INET6;
- else if (afi == AFI_ETHER)
+ else if (afi == AFI_L2VPN)
return AF_ETHERNET;
return 0;
}
@@ -222,7 +222,7 @@ family2afi (int family)
else if (family == AF_INET6)
return AFI_IP6;
else if (family == AF_ETHERNET)
- return AFI_ETHER;
+ return AFI_L2VPN;
return 0;
}
@@ -234,8 +234,8 @@ afi2str(afi_t afi)
return "IPv4";
case AFI_IP6:
return "IPv6";
- case AFI_ETHER:
- return "ethernet";
+ case AFI_L2VPN:
+ return "l2vpn";
case AFI_MAX:
return "bad-value";
default:
@@ -256,6 +256,8 @@ safi2str(safi_t safi)
return "encap";
case SAFI_MPLS_VPN:
return "vpn";
+ case SAFI_EVPN:
+ return "evpn";
}
return NULL;
}
@@ -300,15 +302,15 @@ prefix_copy (struct prefix *dest, const struct prefix *src)
dest->u.prefix4 = src->u.prefix4;
else if (src->family == AF_INET6)
dest->u.prefix6 = src->u.prefix6;
+ else if (src->family == AF_ETHERNET)
+ {
+ memcpy (&dest->u.prefix_evpn, &src->u.prefix_evpn, sizeof (struct evpn_addr));
+ }
else if (src->family == AF_UNSPEC)
{
dest->u.lp.id = src->u.lp.id;
dest->u.lp.adv_router = src->u.lp.adv_router;
}
- else if (src->family == AF_ETHERNET)
- {
- dest->u.prefix_eth = src->u.prefix_eth;
- }
else
{
zlog (NULL, LOG_ERR, "prefix_copy(): Unknown address family %d",
@@ -342,10 +344,9 @@ prefix_same (const struct prefix *p1, const struct prefix *p2)
if (p1->family == AF_INET6 )
if (IPV6_ADDR_SAME (&p1->u.prefix6.s6_addr, &p2->u.prefix6.s6_addr))
return 1;
- if (p1->family == AF_ETHERNET) {
- if (!memcmp(p1->u.prefix_eth.octet, p2->u.prefix_eth.octet, ETHER_ADDR_LEN))
- return 1;
- }
+ if (p1->family == AF_ETHERNET )
+ if (!memcmp (&p1->u.prefix_evpn, &p2->u.prefix_evpn, sizeof (struct evpn_addr)))
+ return 1;
}
return 0;
}
@@ -408,6 +409,9 @@ prefix_common_bits (const struct prefix *p1, const struct prefix *p2)
length = IPV4_MAX_BYTELEN;
if (p1->family == AF_INET6)
length = IPV6_MAX_BYTELEN;
+ if (p1->family == AF_ETHERNET)
+ length = 8 * sizeof (struct evpn_addr);
+
if (p1->family != p2->family || !length)
return -1;
@@ -849,23 +853,46 @@ str2prefix (const char *str, struct prefix *p)
}
const char *
-prefix2str (union prefix46constptr pu, char *str, int size)
+prefix2str (union prefixconstptr pu, char *str, int size)
{
const struct prefix *p = pu.p;
+ char buf[PREFIX2STR_BUFFER];
- if (p->family == AF_ETHERNET)
- {
- snprintf(str, size, "%02x:%02x:%02x:%02x:%02x:%02x/%d",
- p->u.prefix_eth.octet[0], p->u.prefix_eth.octet[1],
- p->u.prefix_eth.octet[2], p->u.prefix_eth.octet[3],
- p->u.prefix_eth.octet[4], p->u.prefix_eth.octet[5],
- p->prefixlen);
- }
- else
+ switch (p->family)
{
- char buf[PREFIX2STR_BUFFER];
- inet_ntop(p->family, &p->u.prefix, buf, sizeof(buf));
- snprintf(str, size, "%s/%d", buf, p->prefixlen);
+ case AF_INET:
+ case AF_INET6:
+ snprintf (str, size, "%s/%d",
+ inet_ntop (p->family, &p->u.prefix, buf, PREFIX2STR_BUFFER),
+ p->prefixlen);
+ break;
+
+ case AF_ETHERNET:
+ if (p->u.prefix_evpn.route_type == 5)
+ {
+ u_char family;
+ family = (p->u.prefix_evpn.flags & (IP_ADDR_V4 | IP_PREFIX_V4)) ?
+ AF_INET : AF_INET6;
+ snprintf (str, size, "[%d]:[%u][%s]/%d",
+ p->u.prefix_evpn.route_type,
+ p->u.prefix_evpn.eth_tag,
+ inet_ntop (family, &p->u.prefix_evpn.ip.addr,
+ buf, PREFIX2STR_BUFFER),
+ p->prefixlen);
+ }
+ else
+ {
+ sprintf (str, "UNK AF_ETHER prefix");
+ snprintf(str, size, "%02x:%02x:%02x:%02x:%02x:%02x/%d",
+ p->u.prefix_eth.octet[0], p->u.prefix_eth.octet[1],
+ p->u.prefix_eth.octet[2], p->u.prefix_eth.octet[3],
+ p->u.prefix_eth.octet[4], p->u.prefix_eth.octet[5],
+ p->prefixlen);
+ }
+ break;
+ default:
+ sprintf (str, "UNK prefix");
+ break;
}
return str;
diff --git a/lib/prefix.h b/lib/prefix.h
index 56adce5eab..eb3ae3dafb 100644
--- a/lib/prefix.h
+++ b/lib/prefix.h
@@ -49,9 +49,45 @@
*/
struct ethaddr {
u_char octet[ETHER_ADDR_LEN];
-} __packed;
+} __attribute__ ((packed));
+/* length is the number of valuable bits of prefix structure
+* 18 bytes is current length in structure, if address is ipv4
+* 30 bytes is in case of ipv6
+*/
+#define PREFIX_LEN_ROUTE_TYPE_5_IPV4 (18*8)
+#define PREFIX_LEN_ROUTE_TYPE_5_IPV6 (30*8)
+
+/* EVPN address (RFC 7432) */
+struct evpn_addr
+{
+ u_char route_type;
+ u_char flags;
+#define IP_ADDR_NONE 0x0
+#define IP_ADDR_V4 0x1
+#define IP_ADDR_V6 0x2
+#define IP_PREFIX_V4 0x4
+#define IP_PREFIX_V6 0x8
+ struct ethaddr mac;
+ uint32_t eth_tag;
+ u_char ip_prefix_length;
+ union
+ {
+ u_char addr;
+ struct in_addr v4_addr;
+ struct in6_addr v6_addr;
+ } ip;
+};
+
+/* EVPN prefix structure. */
+struct prefix_evpn
+{
+ u_char family;
+ u_char prefixlen;
+ struct evpn_addr prefix __attribute__ ((aligned (8)));
+};
+
/*
* A struct prefix contains an address family, a prefix length, and an
* address. This can represent either a 'network prefix' as defined
@@ -88,6 +124,7 @@ struct prefix
struct ethaddr prefix_eth; /* AF_ETHERNET */
u_char val[8];
uintptr_t ptr;
+ struct evpn_addr prefix_evpn;
} u __attribute__ ((aligned (8)));
};
@@ -152,18 +189,20 @@ struct prefix_sg
* side, which strips type safety since the cast will accept any pointer
* type.)
*/
-union prefix46ptr
+union prefixptr
{
struct prefix *p;
struct prefix_ipv4 *p4;
struct prefix_ipv6 *p6;
+ struct prefix_evpn *evp;
} __attribute__ ((transparent_union));
-union prefix46constptr
+union prefixconstptr
{
const struct prefix *p;
const struct prefix_ipv4 *p4;
const struct prefix_ipv6 *p6;
+ const struct prefix_evpn *evp;
} __attribute__ ((transparent_union));
#ifndef INET_ADDRSTRLEN
@@ -237,7 +276,7 @@ extern int str2prefix (const char *, struct prefix *);
#define PREFIX2STR_BUFFER PREFIX_STRLEN
-extern const char *prefix2str (union prefix46constptr, char *, int);
+extern const char *prefix2str (union prefixconstptr, char *, int);
extern int prefix_match (const struct prefix *, const struct prefix *);
extern int prefix_same (const struct prefix *, const struct prefix *);
extern int prefix_cmp (const struct prefix *, const struct prefix *);
diff --git a/lib/srcdest_table.c b/lib/srcdest_table.c
index dd148fa41d..04c9eff79a 100644
--- a/lib/srcdest_table.c
+++ b/lib/srcdest_table.c
@@ -242,7 +242,7 @@ srcdest_route_next(struct route_node *rn)
}
struct route_node *
-srcdest_rnode_get (struct route_table *table, union prefix46ptr dst_pu,
+srcdest_rnode_get (struct route_table *table, union prefixptr dst_pu,
struct prefix_ipv6 *src_p)
{
struct prefix_ipv6 *dst_p = dst_pu.p6;
@@ -253,7 +253,7 @@ srcdest_rnode_get (struct route_table *table, union prefix46ptr dst_pu,
}
struct route_node *
-srcdest_rnode_lookup (struct route_table *table, union prefix46ptr dst_pu,
+srcdest_rnode_lookup (struct route_table *table, union prefixptr dst_pu,
struct prefix_ipv6 *src_p)
{
struct prefix_ipv6 *dst_p = dst_pu.p6;
diff --git a/lib/srcdest_table.h b/lib/srcdest_table.h
index 59111b5d17..207f5d121d 100644
--- a/lib/srcdest_table.h
+++ b/lib/srcdest_table.h
@@ -57,10 +57,10 @@ extern route_table_delegate_t _srcdest_srcnode_delegate;
extern struct route_table *srcdest_table_init(void);
extern struct route_node *srcdest_rnode_get(struct route_table *table,
- union prefix46ptr dst_pu,
+ union prefixptr dst_pu,
struct prefix_ipv6 *src_p);
extern struct route_node *srcdest_rnode_lookup(struct route_table *table,
- union prefix46ptr dst_pu,
+ union prefixptr dst_pu,
struct prefix_ipv6 *src_p);
extern void srcdest_rnode_prefixes (struct route_node *rn, struct prefix **p,
struct prefix **src_p);
diff --git a/lib/vty.c b/lib/vty.c
index ce6349bf77..3a3265f54d 100644
--- a/lib/vty.c
+++ b/lib/vty.c
@@ -750,6 +750,7 @@ vty_end_config (struct vty *vty)
case BGP_IPV4M_NODE:
case BGP_IPV6_NODE:
case BGP_IPV6M_NODE:
+ case BGP_EVPN_NODE:
case RMAP_NODE:
case OSPF_NODE:
case OSPF6_NODE:
diff --git a/lib/zebra.h b/lib/zebra.h
index 19a26b5230..760264d752 100644
--- a/lib/zebra.h
+++ b/lib/zebra.h
@@ -401,8 +401,8 @@ extern const char *zserv_command_string (unsigned int command);
typedef enum {
AFI_IP = 1,
AFI_IP6 = 2,
- AFI_ETHER = 3, /* RFC 1700 has "6" for 802.* */
- AFI_MAX = 4
+ AFI_L2VPN = 4,
+ AFI_MAX = 5
} afi_t;
/* Subsequent Address Family Identifier. */
@@ -412,7 +412,8 @@ typedef enum {
#define SAFI_RESERVED_4 4
#define SAFI_ENCAP 5
#define SAFI_RESERVED_5 5
-#define SAFI_MAX 6
+#define SAFI_EVPN 6
+#define SAFI_MAX 7
#define IANA_SAFI_RESERVED 0
#define IANA_SAFI_UNICAST 1
@@ -442,6 +443,7 @@ typedef enum {
#define IANA_SAFI_UNICAST 1
#define IANA_SAFI_MULTICAST 2
#define IANA_SAFI_ENCAP 7
+#define IANA_SAFI_EVPN 70
#define IANA_SAFI_MPLS_VPN 128
/* Default Administrative Distance of each protocol. */
@@ -482,6 +484,8 @@ static inline afi_t afi_iana2int (iana_afi_t afi)
return AFI_IP;
if (afi == IANA_AFI_IPV6)
return AFI_IP6;
+ if (afi == IANA_AFI_L2VPN)
+ return AFI_L2VPN;
return AFI_MAX;
}
@@ -491,6 +495,8 @@ static inline iana_afi_t afi_int2iana (afi_t afi)
return IANA_AFI_IPV4;
if (afi == AFI_IP6)
return IANA_AFI_IPV6;
+ if (afi == AFI_L2VPN)
+ return IANA_AFI_L2VPN;
return IANA_AFI_RESERVED;
}
@@ -504,6 +510,8 @@ static inline safi_t safi_iana2int (safi_t safi)
return SAFI_MPLS_VPN;
if (safi == IANA_SAFI_ENCAP)
return SAFI_ENCAP;
+ if (safi == IANA_SAFI_EVPN)
+ return SAFI_EVPN;
return SAFI_MAX;
}
@@ -517,6 +525,8 @@ static inline safi_t safi_int2iana (safi_t safi)
return IANA_SAFI_MPLS_VPN;
if (safi == SAFI_ENCAP)
return IANA_SAFI_ENCAP;
+ if (safi == SAFI_EVPN)
+ return IANA_SAFI_EVPN;
return IANA_SAFI_RESERVED;
}
diff --git a/tests/bgpd/test_ecommunity.c b/tests/bgpd/test_ecommunity.c
index 9166af6142..9174191cb3 100644
--- a/tests/bgpd/test_ecommunity.c
+++ b/tests/bgpd/test_ecommunity.c
@@ -97,10 +97,10 @@ validate (struct ecommunity *ecom, const struct test_spec *sp)
char *str1, *str2;
printf ("got:\n %s\n", ecommunity_str (ecom));
- str1 = ecommunity_ecom2str (ecom, ECOMMUNITY_FORMAT_COMMUNITY_LIST);
+ str1 = ecommunity_ecom2str (ecom, ECOMMUNITY_FORMAT_COMMUNITY_LIST, 0);
etmp = ecommunity_str2com (str1, 0, 1);
if (etmp)
- str2 = ecommunity_ecom2str (etmp, ECOMMUNITY_FORMAT_COMMUNITY_LIST);
+ str2 = ecommunity_ecom2str (etmp, ECOMMUNITY_FORMAT_COMMUNITY_LIST, 0);
else
str2 = NULL;
diff --git a/tests/bgpd/test_mp_attr.c b/tests/bgpd/test_mp_attr.c
index 397612c315..883cac0cc6 100644
--- a/tests/bgpd/test_mp_attr.c
+++ b/tests/bgpd/test_mp_attr.c
@@ -725,11 +725,10 @@ parse_test (struct peer *peer, struct test_segment *t, int type)
if (!parse_ret)
{
if (type == BGP_ATTR_MP_REACH_NLRI)
- nlri_ret = bgp_nlri_parse (peer, &attr, &nlri);
+ nlri_ret = bgp_nlri_parse (peer, &attr, &nlri, 0);
else
- nlri_ret = bgp_nlri_parse (peer, NULL, &nlri);
+ nlri_ret = bgp_nlri_parse (peer, &attr, &nlri, 1);
}
- zlog_err("xxxxxxxxxxxxxxxx nlri ret %u", nlri_ret);
handle_result (peer, t, parse_ret, nlri_ret);
}
diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c
index 6427b8c165..579c0fc590 100644
--- a/vtysh/vtysh.c
+++ b/vtysh/vtysh.c
@@ -307,7 +307,7 @@ vtysh_execute_func (const char *line, int pager)
|| saved_node == BGP_ENCAP_NODE || saved_node == BGP_ENCAPV6_NODE
|| saved_node == BGP_IPV4_NODE
|| saved_node == BGP_IPV6_NODE || saved_node == BGP_IPV4M_NODE
- || saved_node == BGP_IPV6M_NODE)
+ || saved_node == BGP_IPV6M_NODE || saved_node == BGP_EVPN_NODE)
&& (tried == 1))
{
vtysh_execute("exit-address-family");
@@ -561,7 +561,8 @@ vtysh_mark_file (const char *filename)
{
if ((prev_node == BGP_VPNV4_NODE || prev_node == BGP_IPV4_NODE
|| prev_node == BGP_IPV6_NODE || prev_node == BGP_IPV4M_NODE
- || prev_node == BGP_IPV6M_NODE || prev_node == BGP_VPNV6_NODE)
+ || prev_node == BGP_IPV6M_NODE || prev_node == BGP_VPNV6_NODE
+ || prev_node == BGP_EVPN_NODE)
&& (tried == 1))
{
fprintf(stdout, "exit-address-family\n");
@@ -956,6 +957,12 @@ static struct cmd_node bgp_ipv6m_node =
"%s(config-router-af)# "
};
+static struct cmd_node bgp_evpn_node =
+{
+ BGP_EVPN_NODE,
+ "%s(config-router-af)# "
+};
+
static struct cmd_node bgp_vnc_defaults_node =
{
BGP_VNC_DEFAULTS_NODE,
@@ -1203,6 +1210,21 @@ DEFUNSH (VTYSH_BGPD,
return CMD_SUCCESS;
}
+DEFUNSH (VTYSH_BGPD,
+ address_family_evpn,
+ address_family_evpn_cmd,
+ "address-family <l2vpn evpn>",
+ "Enter Address Family command mode\n"
+ "EVPN Address family\n"
+ "Layer2 VPN Address family\n"
+ "Ethernet Virtual Private Network Subsequent Address Family\n")
+{
+#if defined(HAVE_EVPN)
+ vty->node = BGP_EVPN_NODE;
+#endif /* HAVE_EVPN */
+ return CMD_SUCCESS;
+}
+
#if defined (ENABLE_BGP_VNC)
DEFUNSH (VTYSH_BGPD,
vnc_defaults,
@@ -1511,6 +1533,7 @@ vtysh_exit (struct vty *vty)
case BGP_IPV6_NODE:
case BGP_IPV6M_NODE:
case BGP_VRF_POLICY_NODE:
+ case BGP_EVPN_NODE:
case BGP_VNC_DEFAULTS_NODE:
case BGP_VNC_NVE_GROUP_NODE:
case BGP_VNC_L2_GROUP_NODE:
@@ -3114,6 +3137,7 @@ vtysh_init_vty (void)
install_node (&bgp_ipv6_node, NULL);
install_node (&bgp_ipv6m_node, NULL);
install_node (&bgp_vrf_policy_node, NULL);
+ install_node (&bgp_evpn_node, NULL);
install_node (&bgp_vnc_defaults_node, NULL);
install_node (&bgp_vnc_nve_group_node, NULL);
install_node (&bgp_vnc_l2_group_node, NULL);
@@ -3150,6 +3174,7 @@ vtysh_init_vty (void)
vtysh_install_default (BGP_IPV4M_NODE);
vtysh_install_default (BGP_IPV6_NODE);
vtysh_install_default (BGP_IPV6M_NODE);
+ vtysh_install_default (BGP_EVPN_NODE);
#if ENABLE_BGP_VNC
vtysh_install_default (BGP_VRF_POLICY_NODE);
vtysh_install_default (BGP_VNC_DEFAULTS_NODE);
@@ -3222,6 +3247,7 @@ vtysh_init_vty (void)
install_element (BGP_IPV6_NODE, &vtysh_quit_bgpd_cmd);
install_element (BGP_IPV6M_NODE, &vtysh_exit_bgpd_cmd);
install_element (BGP_IPV6M_NODE, &vtysh_quit_bgpd_cmd);
+ install_element (BGP_EVPN_NODE, &vtysh_quit_bgpd_cmd);
#if defined (ENABLE_BGP_VNC)
install_element (BGP_VRF_POLICY_NODE, &vtysh_exit_bgpd_cmd);
install_element (BGP_VRF_POLICY_NODE, &vtysh_quit_bgpd_cmd);
@@ -3267,6 +3293,7 @@ vtysh_init_vty (void)
install_element (BGP_IPV6_NODE, &vtysh_end_all_cmd);
install_element (BGP_IPV6M_NODE, &vtysh_end_all_cmd);
install_element (BGP_VRF_POLICY_NODE, &vtysh_end_all_cmd);
+ install_element (BGP_EVPN_NODE, &vtysh_end_all_cmd);
install_element (BGP_VNC_DEFAULTS_NODE, &vtysh_end_all_cmd);
install_element (BGP_VNC_NVE_GROUP_NODE, &vtysh_end_all_cmd);
install_element (BGP_VNC_L2_GROUP_NODE, &vtysh_end_all_cmd);
@@ -3322,6 +3349,7 @@ vtysh_init_vty (void)
#endif
install_element (BGP_NODE, &address_family_ipv4_unicast_cmd);
install_element (BGP_NODE, &address_family_ipv6_cmd);
+ install_element (BGP_NODE, &address_family_evpn_cmd);
install_element (BGP_VPNV4_NODE, &exit_address_family_cmd);
install_element (BGP_VPNV6_NODE, &exit_address_family_cmd);
install_element (BGP_ENCAP_NODE, &exit_address_family_cmd);
@@ -3330,6 +3358,7 @@ vtysh_init_vty (void)
install_element (BGP_IPV4M_NODE, &exit_address_family_cmd);
install_element (BGP_IPV6_NODE, &exit_address_family_cmd);
install_element (BGP_IPV6M_NODE, &exit_address_family_cmd);
+ install_element (BGP_EVPN_NODE, &exit_address_family_cmd);
install_element (BGP_VRF_POLICY_NODE, &exit_vrf_policy_cmd);
install_element (BGP_VNC_DEFAULTS_NODE, &exit_vnc_config_cmd);
diff --git a/zebra/rib.h b/zebra/rib.h
index b246b89a53..c0cde50baf 100644
--- a/zebra/rib.h
+++ b/zebra/rib.h
@@ -314,8 +314,8 @@ extern void rib_lookup_and_dump (struct prefix_ipv4 *, vrf_id_t);
extern void rib_lookup_and_pushup (struct prefix_ipv4 *, vrf_id_t);
#define rib_dump(prefix, src, rib) _rib_dump(__func__, prefix, src, rib)
extern void _rib_dump (const char *,
- union prefix46constptr,
- union prefix46constptr, const struct rib *);
+ union prefixconstptr,
+ union prefixconstptr, const struct rib *);
extern int rib_lookup_ipv4_route (struct prefix_ipv4 *, union sockunion *,
vrf_id_t);
#define ZEBRA_RIB_LOOKUP_ERROR -1
diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c
index 13418c509e..08874f22fc 100644
--- a/zebra/zebra_rib.c
+++ b/zebra/zebra_rib.c
@@ -2135,8 +2135,8 @@ rib_delnode (struct route_node *rn, struct rib *rib)
*/
void _rib_dump (const char * func,
- union prefix46constptr pp,
- union prefix46constptr src_pp,
+ union prefixconstptr pp,
+ union prefixconstptr src_pp,
const struct rib * rib)
{
const struct prefix *p = pp.p;