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 + +#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 /* ::00 */ +#define ESI_TYPE_MAC 3 /* : */ +#define ESI_TYPE_ROUTER 4 /* : */ +#define ESI_TYPE_AS 5 /* : */ +#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 + +#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 +#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 rd ASN:nn_or_IP-address:nn ethtag WORD label WORD esi WORD gwip 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 rd ASN:nn_or_IP-address:nn ethtag WORD label WORD esi WORD gwip ", + 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 [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 +#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 + +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 ", + "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) + switch (p->family) { - 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 - { - 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 ", + "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;