mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-07-25 11:28:06 +00:00
Merge pull request #103 from pguibert6WIND/frr_6wind_evpn_5
Provide EVPN basic support on master branch + EVPN Route Target 5 Support (V2)
This commit is contained in:
commit
bac515c64c
@ -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@
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
141
bgpd/bgp_attr_evpn.c
Normal file
141
bgpd/bgp_attr_evpn.c
Normal file
@ -0,0 +1,141 @@
|
||||
/* Ethernet-VPN Attribute handling file
|
||||
Copyright (C) 2016 6WIND
|
||||
|
||||
This file is part of Free Range Routing.
|
||||
|
||||
Free Range Routing is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 2, or (at your option) any
|
||||
later version.
|
||||
|
||||
Free Range Routing is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Free Range Routing; see the file COPYING. If not, write to the Free
|
||||
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA. */
|
||||
|
||||
#include <zebra.h>
|
||||
|
||||
#include "command.h"
|
||||
#include "filter.h"
|
||||
#include "prefix.h"
|
||||
#include "log.h"
|
||||
#include "memory.h"
|
||||
#include "stream.h"
|
||||
|
||||
#include "bgpd/bgpd.h"
|
||||
#include "bgpd/bgp_attr.h"
|
||||
#include "bgpd/bgp_route.h"
|
||||
#include "bgpd/bgp_attr_evpn.h"
|
||||
#include "bgpd/bgp_ecommunity.h"
|
||||
#include "bgpd/bgp_evpn.h"
|
||||
|
||||
void bgp_add_routermac_ecom(struct attr *attr, struct ethaddr *routermac)
|
||||
{
|
||||
struct ecommunity_val routermac_ecom;
|
||||
|
||||
if (attr->extra) {
|
||||
memset(&routermac_ecom, 0, sizeof(struct ecommunity_val));
|
||||
routermac_ecom.val[0] = ECOMMUNITY_ENCODE_EVPN;
|
||||
routermac_ecom.val[1] = ECOMMUNITY_EVPN_SUBTYPE_ROUTERMAC;
|
||||
memcpy(&routermac_ecom.val[2], routermac->octet, ETHER_ADDR_LEN);
|
||||
if (!attr->extra->ecommunity)
|
||||
attr->extra->ecommunity = ecommunity_new();
|
||||
ecommunity_add_val(attr->extra->ecommunity, &routermac_ecom);
|
||||
ecommunity_str (attr->extra->ecommunity);
|
||||
}
|
||||
}
|
||||
|
||||
/* converts to an esi
|
||||
* returns 1 on success, 0 otherwise
|
||||
* format accepted: AA:BB:CC:DD:EE:FF:GG:HH:II:JJ
|
||||
* if id is null, check only is done
|
||||
*/
|
||||
int str2esi(const char *str, struct eth_segment_id *id)
|
||||
{
|
||||
unsigned int a[ESI_LEN];
|
||||
int i;
|
||||
|
||||
if (!str)
|
||||
return 0;
|
||||
if (sscanf (str, "%2x:%2x:%2x:%2x:%2x:%2x:%2x:%2x:%2x:%2x",
|
||||
a + 0, a + 1, a + 2, a + 3, a + 4, a + 5,
|
||||
a + 6, a + 7, a + 8, a + 9) != ESI_LEN)
|
||||
{
|
||||
/* error in incoming str length */
|
||||
return 0;
|
||||
}
|
||||
/* valid mac address */
|
||||
if (!id)
|
||||
return 1;
|
||||
for (i = 0; i < ESI_LEN; ++i)
|
||||
id->val[i] = a[i] & 0xff;
|
||||
return 1;
|
||||
}
|
||||
|
||||
char *esi2str(struct eth_segment_id *id)
|
||||
{
|
||||
char *ptr;
|
||||
u_char *val;
|
||||
|
||||
if (!id)
|
||||
return NULL;
|
||||
|
||||
val = id->val;
|
||||
ptr = (char *)XMALLOC(MTYPE_TMP, (ESI_LEN * 2 + ESI_LEN - 1 + 1) * sizeof(char));
|
||||
|
||||
snprintf(ptr, (ESI_LEN * 2 + ESI_LEN - 1 + 1),
|
||||
"%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
|
||||
val[0], val[1], val[2], val[3], val[4],
|
||||
val[5], val[6], val[7], val[8], val[9]);
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
char *ecom_mac2str(char *ecom_mac)
|
||||
{
|
||||
char *en;
|
||||
|
||||
en = ecom_mac;
|
||||
en += 2;
|
||||
return prefix_mac2str((struct ethaddr *)en, NULL, 0);
|
||||
}
|
||||
|
||||
/* dst prefix must be AF_INET or AF_INET6 prefix, to forge EVPN prefix */
|
||||
extern int
|
||||
bgp_build_evpn_prefix(int evpn_type, uint32_t eth_tag, struct prefix *dst)
|
||||
{
|
||||
struct evpn_addr *p_evpn_p;
|
||||
struct prefix p2;
|
||||
struct prefix *src = &p2;
|
||||
|
||||
if (!dst || dst->family == 0)
|
||||
return -1;
|
||||
/* store initial prefix in src */
|
||||
prefix_copy(src, dst);
|
||||
memset(dst, 0, sizeof(struct prefix));
|
||||
p_evpn_p = &(dst->u.prefix_evpn);
|
||||
dst->family = AF_ETHERNET;
|
||||
p_evpn_p->route_type = evpn_type;
|
||||
if (evpn_type == EVPN_IP_PREFIX) {
|
||||
p_evpn_p->eth_tag = eth_tag;
|
||||
p_evpn_p->ip_prefix_length = p2.prefixlen;
|
||||
if (src->family == AF_INET) {
|
||||
p_evpn_p->flags = IP_PREFIX_V4;
|
||||
memcpy(&p_evpn_p->ip.v4_addr, &src->u.prefix4,
|
||||
sizeof(struct in_addr));
|
||||
dst->prefixlen = (u_char) PREFIX_LEN_ROUTE_TYPE_5_IPV4;
|
||||
} else {
|
||||
p_evpn_p->flags = IP_PREFIX_V6;
|
||||
memcpy(&p_evpn_p->ip.v6_addr, &src->u.prefix6,
|
||||
sizeof(struct in6_addr));
|
||||
dst->prefixlen = (u_char) PREFIX_LEN_ROUTE_TYPE_5_IPV6;
|
||||
}
|
||||
} else
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
59
bgpd/bgp_attr_evpn.h
Normal file
59
bgpd/bgp_attr_evpn.h
Normal file
@ -0,0 +1,59 @@
|
||||
/* E-VPN attribute handling structure file
|
||||
Copyright (C) 2016 6WIND
|
||||
|
||||
This file is part of Free Range Routing.
|
||||
|
||||
Free Range Routing is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 2, or (at your option) any
|
||||
later version.
|
||||
|
||||
Free Range Routing is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Free Range Routing; see the file COPYING. If not, write to the Free
|
||||
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA. */
|
||||
|
||||
#ifndef _QUAGGA_BGP_ATTR_EVPN_H
|
||||
#define _QUAGGA_BGP_ATTR_EVPN_H
|
||||
|
||||
/* value of first byte of ESI */
|
||||
#define ESI_TYPE_ARBITRARY 0 /* */
|
||||
#define ESI_TYPE_LACP 1 /* <> */
|
||||
#define ESI_TYPE_BRIDGE 2 /* <Root bridge Mac-6B>:<Root Br Priority-2B>:00 */
|
||||
#define ESI_TYPE_MAC 3 /* <Syst Mac Add-6B>:<Local Discriminator Value-3B> */
|
||||
#define ESI_TYPE_ROUTER 4 /* <RouterId-4B>:<Local Discriminator Value-4B> */
|
||||
#define ESI_TYPE_AS 5 /* <AS-4B>:<Local Discriminator Value-4B> */
|
||||
#define MAX_ESI {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}
|
||||
#define ESI_LEN 10
|
||||
|
||||
#define MAX_ET 0xffffffff
|
||||
u_long eth_tag_id;
|
||||
struct attr;
|
||||
|
||||
struct eth_segment_id {
|
||||
u_char val[ESI_LEN];
|
||||
};
|
||||
|
||||
union gw_addr {
|
||||
struct in_addr ipv4;
|
||||
struct in6_addr ipv6;
|
||||
};
|
||||
|
||||
struct bgp_route_evpn {
|
||||
struct eth_segment_id eth_s_id;
|
||||
union gw_addr gw_ip;
|
||||
};
|
||||
|
||||
extern int str2esi(const char *str, struct eth_segment_id *id);
|
||||
extern char *esi2str(struct eth_segment_id *id);
|
||||
extern char *ecom_mac2str(char *ecom_mac);
|
||||
|
||||
extern void bgp_add_routermac_ecom(struct attr *attr, struct ethaddr *routermac);
|
||||
extern int bgp_build_evpn_prefix(int type, uint32_t eth_tag,
|
||||
struct prefix *dst);
|
||||
#endif /* _QUAGGA_BGP_ATTR_EVPN_H */
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
225
bgpd/bgp_evpn.c
Normal file
225
bgpd/bgp_evpn.c
Normal file
@ -0,0 +1,225 @@
|
||||
/* Ethernet-VPN Packet and vty Processing File
|
||||
Copyright (C) 2016 6WIND
|
||||
|
||||
This file is part of Free Range Routing.
|
||||
|
||||
Free Range Routing is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 2, or (at your option) any
|
||||
later version.
|
||||
|
||||
Free Range Routing is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Free Range Routing; see the file COPYING. If not, write to the Free
|
||||
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA. */
|
||||
|
||||
#include <zebra.h>
|
||||
|
||||
#include "command.h"
|
||||
#include "filter.h"
|
||||
#include "prefix.h"
|
||||
#include "log.h"
|
||||
#include "memory.h"
|
||||
#include "stream.h"
|
||||
|
||||
#include "bgpd/bgp_attr_evpn.h"
|
||||
#include "bgpd/bgpd.h"
|
||||
#include "bgpd/bgp_table.h"
|
||||
#include "bgpd/bgp_route.h"
|
||||
#include "bgpd/bgp_attr.h"
|
||||
#include "bgpd/bgp_mplsvpn.h"
|
||||
#include "bgpd/bgp_evpn.h"
|
||||
|
||||
int
|
||||
bgp_nlri_parse_evpn(struct peer *peer, struct attr *attr,
|
||||
struct bgp_nlri *packet, int withdraw)
|
||||
{
|
||||
u_char *pnt;
|
||||
u_char *lim;
|
||||
struct prefix p;
|
||||
struct prefix_rd prd;
|
||||
struct evpn_addr *p_evpn_p;
|
||||
struct bgp_route_evpn evpn;
|
||||
uint8_t route_type, route_length;
|
||||
u_char *pnt_label;
|
||||
u_int32_t addpath_id = 0;
|
||||
|
||||
/* Check peer status. */
|
||||
if (peer->status != Established)
|
||||
return 0;
|
||||
|
||||
/* Make prefix_rd */
|
||||
prd.family = AF_UNSPEC;
|
||||
prd.prefixlen = 64;
|
||||
|
||||
p_evpn_p = &p.u.prefix_evpn;
|
||||
pnt = packet->nlri;
|
||||
lim = pnt + packet->length;
|
||||
while (pnt < lim) {
|
||||
/* clear evpn structure */
|
||||
memset(&evpn, 0, sizeof(evpn));
|
||||
|
||||
/* Clear prefix structure. */
|
||||
memset(&p, 0, sizeof(struct prefix));
|
||||
memset(&evpn.gw_ip, 0, sizeof(union gw_addr));
|
||||
memset(&evpn.eth_s_id, 0, sizeof(struct eth_segment_id));
|
||||
|
||||
/* Fetch Route Type */
|
||||
route_type = *pnt++;
|
||||
route_length = *pnt++;
|
||||
/* simply ignore. goto next route type if any */
|
||||
if (route_type != EVPN_IP_PREFIX) {
|
||||
if (pnt + route_length > lim) {
|
||||
zlog_err
|
||||
("not enough bytes for New Route Type left in NLRI?");
|
||||
return -1;
|
||||
}
|
||||
pnt += route_length;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Fetch RD */
|
||||
if (pnt + 8 > lim) {
|
||||
zlog_err("not enough bytes for RD left in NLRI?");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Copy routing distinguisher to rd. */
|
||||
memcpy(&prd.val, pnt, 8);
|
||||
pnt += 8;
|
||||
|
||||
/* Fetch ESI */
|
||||
if (pnt + 10 > lim) {
|
||||
zlog_err("not enough bytes for ESI left in NLRI?");
|
||||
return -1;
|
||||
}
|
||||
memcpy(&evpn.eth_s_id.val, pnt, 10);
|
||||
pnt += 10;
|
||||
|
||||
/* Fetch Ethernet Tag */
|
||||
if (pnt + 4 > lim) {
|
||||
zlog_err("not enough bytes for Eth Tag left in NLRI?");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (route_type == EVPN_IP_PREFIX) {
|
||||
p_evpn_p->route_type = route_type;
|
||||
memcpy(&(p_evpn_p->eth_tag), pnt, 4);
|
||||
p_evpn_p->eth_tag = ntohl(p_evpn_p->eth_tag);
|
||||
pnt += 4;
|
||||
|
||||
/* Fetch IP prefix length. */
|
||||
p_evpn_p->ip_prefix_length = *pnt++;
|
||||
|
||||
if (p_evpn_p->ip_prefix_length > 128) {
|
||||
zlog_err("invalid prefixlen %d in EVPN NLRI?",
|
||||
p.prefixlen);
|
||||
return -1;
|
||||
}
|
||||
/* determine IPv4 or IPv6 prefix */
|
||||
if (route_length - 4 - 10 - 8 -
|
||||
3 /* label to be read */ >= 32) {
|
||||
p_evpn_p->flags = IP_PREFIX_V6;
|
||||
memcpy(&(p_evpn_p->ip.v4_addr), pnt, 16);
|
||||
pnt += 16;
|
||||
memcpy(&evpn.gw_ip.ipv6, pnt, 16);
|
||||
pnt += 16;
|
||||
} else {
|
||||
p_evpn_p->flags = IP_PREFIX_V4;
|
||||
memcpy(&(p_evpn_p->ip.v4_addr), pnt, 4);
|
||||
pnt += 4;
|
||||
memcpy(&evpn.gw_ip.ipv4, pnt, 4);
|
||||
pnt += 4;
|
||||
}
|
||||
p.family = AFI_L2VPN;
|
||||
if (p_evpn_p->flags == IP_PREFIX_V4)
|
||||
p.prefixlen =
|
||||
(u_char) PREFIX_LEN_ROUTE_TYPE_5_IPV4;
|
||||
else
|
||||
p.prefixlen = PREFIX_LEN_ROUTE_TYPE_5_IPV6;
|
||||
p.family = AF_ETHERNET;
|
||||
}
|
||||
|
||||
/* Fetch Label */
|
||||
if (pnt + 3 > lim) {
|
||||
zlog_err("not enough bytes for Label left in NLRI?");
|
||||
return -1;
|
||||
}
|
||||
pnt_label = pnt;
|
||||
|
||||
pnt += 3;
|
||||
|
||||
if (!withdraw) {
|
||||
bgp_update(peer, &p, addpath_id, attr, AFI_L2VPN,
|
||||
SAFI_EVPN, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL,
|
||||
&prd, pnt_label, 0, &evpn);
|
||||
} else {
|
||||
bgp_withdraw(peer, &p, addpath_id, attr, AFI_L2VPN,
|
||||
SAFI_EVPN, ZEBRA_ROUTE_BGP,
|
||||
BGP_ROUTE_NORMAL, &prd, pnt_label, &evpn);
|
||||
}
|
||||
}
|
||||
|
||||
/* Packet length consistency check. */
|
||||
if (pnt != lim)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
bgp_packet_mpattr_route_type_5(struct stream *s,
|
||||
struct prefix *p, struct prefix_rd *prd,
|
||||
u_char * label, struct attr *attr)
|
||||
{
|
||||
int len;
|
||||
char temp[16];
|
||||
struct evpn_addr *p_evpn_p;
|
||||
|
||||
memset(&temp, 0, 16);
|
||||
if (p->family != AF_ETHERNET)
|
||||
return;
|
||||
p_evpn_p = &(p->u.prefix_evpn);
|
||||
if (p_evpn_p->flags & IP_PREFIX_V4)
|
||||
len = 8; /* ipv4 */
|
||||
else
|
||||
len = 32; /* ipv6 */
|
||||
stream_putc(s, EVPN_IP_PREFIX);
|
||||
stream_putc(s,
|
||||
8 /* RD */ + 10 /* ESI */ + 4 /* EthTag */ + 1 + len +
|
||||
3 /* label */ );
|
||||
stream_put(s, prd->val, 8);
|
||||
if (attr && attr->extra)
|
||||
stream_put(s, &(attr->extra->evpn_overlay.eth_s_id), 10);
|
||||
else
|
||||
stream_put(s, &temp, 10);
|
||||
stream_putl(s, p_evpn_p->eth_tag);
|
||||
stream_putc(s, p_evpn_p->ip_prefix_length);
|
||||
if (p_evpn_p->flags & IP_PREFIX_V4)
|
||||
stream_put_ipv4(s, p_evpn_p->ip.v4_addr.s_addr);
|
||||
else
|
||||
stream_put(s, &p_evpn_p->ip.v6_addr, 16);
|
||||
if (attr && attr->extra) {
|
||||
if (p_evpn_p->flags & IP_PREFIX_V4)
|
||||
stream_put_ipv4(s,
|
||||
attr->extra->evpn_overlay.gw_ip.ipv4.
|
||||
s_addr);
|
||||
else
|
||||
stream_put(s, &(attr->extra->evpn_overlay.gw_ip.ipv6),
|
||||
16);
|
||||
} else {
|
||||
if (p_evpn_p->flags & IP_PREFIX_V4)
|
||||
stream_put_ipv4(s, 0);
|
||||
else
|
||||
stream_put(s, &temp, 16);
|
||||
}
|
||||
if (label)
|
||||
stream_put(s, label, 3);
|
||||
else
|
||||
stream_put3(s, 0);
|
||||
return;
|
||||
}
|
40
bgpd/bgp_evpn.h
Normal file
40
bgpd/bgp_evpn.h
Normal file
@ -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 */
|
750
bgpd/bgp_evpn_vty.c
Normal file
750
bgpd/bgp_evpn_vty.c
Normal file
@ -0,0 +1,750 @@
|
||||
/* Ethernet-VPN Packet and vty Processing File
|
||||
Copyright (C) 2017 6WIND
|
||||
|
||||
This file is part of Free Range Routing
|
||||
|
||||
Free Range Routing is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 2, or (at your option) any
|
||||
later version.
|
||||
|
||||
Free Range Routing is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Free Range Routing; see the file COPYING. If not, write to the Free
|
||||
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA. */
|
||||
|
||||
#include <zebra.h>
|
||||
#include "command.h"
|
||||
#include "prefix.h"
|
||||
#include "lib/json.h"
|
||||
|
||||
#include "bgpd/bgpd.h"
|
||||
#include "bgpd/bgp_table.h"
|
||||
#include "bgpd/bgp_attr.h"
|
||||
#include "bgpd/bgp_route.h"
|
||||
#include "bgpd/bgp_mplsvpn.h"
|
||||
#include "bgpd/bgp_vpn.h"
|
||||
#include "bgpd/bgp_evpn_vty.h"
|
||||
#include "bgpd/bgp_evpn.h"
|
||||
|
||||
#define SHOW_DISPLAY_STANDARD 0
|
||||
#define SHOW_DISPLAY_TAGS 1
|
||||
#define SHOW_DISPLAY_OVERLAY 2
|
||||
|
||||
static int
|
||||
bgp_show_ethernet_vpn(struct vty *vty, struct prefix_rd *prd,
|
||||
enum bgp_show_type type, void *output_arg, int option,
|
||||
u_char use_json)
|
||||
{
|
||||
afi_t afi = AFI_L2VPN;
|
||||
struct bgp *bgp;
|
||||
struct bgp_table *table;
|
||||
struct bgp_node *rn;
|
||||
struct bgp_node *rm;
|
||||
struct bgp_info *ri;
|
||||
int rd_header;
|
||||
int header = 1;
|
||||
char v4_header[] =
|
||||
" Network Next Hop Metric LocPrf Weight Path%s";
|
||||
char v4_header_tag[] =
|
||||
" Network Next Hop In tag/Out tag%s";
|
||||
char v4_header_overlay[] =
|
||||
" Network Next Hop EthTag Overlay Index RouterMac%s";
|
||||
|
||||
unsigned long output_count = 0;
|
||||
unsigned long total_count = 0;
|
||||
json_object *json = NULL;
|
||||
json_object *json_nroute = NULL;
|
||||
json_object *json_array = NULL;
|
||||
json_object *json_scode = NULL;
|
||||
json_object *json_ocode = NULL;
|
||||
|
||||
bgp = bgp_get_default();
|
||||
if (bgp == NULL) {
|
||||
if (!use_json)
|
||||
vty_out(vty, "No BGP process is configured%s",
|
||||
VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
if (use_json) {
|
||||
json_scode = json_object_new_object();
|
||||
json_ocode = json_object_new_object();
|
||||
json = json_object_new_object();
|
||||
json_nroute = json_object_new_object();
|
||||
|
||||
json_object_string_add(json_scode, "suppressed", "s");
|
||||
json_object_string_add(json_scode, "damped", "d");
|
||||
json_object_string_add(json_scode, "history", "h");
|
||||
json_object_string_add(json_scode, "valid", "*");
|
||||
json_object_string_add(json_scode, "best", ">");
|
||||
json_object_string_add(json_scode, "internal", "i");
|
||||
|
||||
json_object_string_add(json_ocode, "igp", "i");
|
||||
json_object_string_add(json_ocode, "egp", "e");
|
||||
json_object_string_add(json_ocode, "incomplete", "?");
|
||||
}
|
||||
|
||||
for (rn = bgp_table_top(bgp->rib[afi][SAFI_EVPN]); rn;
|
||||
rn = bgp_route_next(rn)) {
|
||||
if (use_json)
|
||||
continue; /* XXX json TODO */
|
||||
|
||||
if (prd && memcmp(rn->p.u.val, prd->val, 8) != 0)
|
||||
continue;
|
||||
|
||||
if ((table = rn->info) != NULL) {
|
||||
rd_header = 1;
|
||||
|
||||
for (rm = bgp_table_top(table); rm;
|
||||
rm = bgp_route_next(rm))
|
||||
for (ri = rm->info; ri; ri = ri->next) {
|
||||
total_count++;
|
||||
if (type == bgp_show_type_neighbor) {
|
||||
union sockunion *su =
|
||||
output_arg;
|
||||
|
||||
if (ri->peer->su_remote == NULL
|
||||
|| !sockunion_same(ri->
|
||||
peer->
|
||||
su_remote,
|
||||
su))
|
||||
continue;
|
||||
}
|
||||
if (header == 0) {
|
||||
if (use_json) {
|
||||
if (option ==
|
||||
SHOW_DISPLAY_TAGS) {
|
||||
json_object_int_add
|
||||
(json,
|
||||
"bgpTableVersion",
|
||||
0);
|
||||
json_object_string_add
|
||||
(json,
|
||||
"bgpLocalRouterId",
|
||||
inet_ntoa
|
||||
(bgp->
|
||||
router_id));
|
||||
json_object_object_add
|
||||
(json,
|
||||
"bgpStatusCodes",
|
||||
json_scode);
|
||||
json_object_object_add
|
||||
(json,
|
||||
"bgpOriginCodes",
|
||||
json_ocode);
|
||||
}
|
||||
} else {
|
||||
if (option ==
|
||||
SHOW_DISPLAY_TAGS)
|
||||
vty_out(vty,
|
||||
v4_header_tag,
|
||||
VTY_NEWLINE);
|
||||
else if (option ==
|
||||
SHOW_DISPLAY_OVERLAY)
|
||||
vty_out(vty,
|
||||
v4_header_overlay,
|
||||
VTY_NEWLINE);
|
||||
else {
|
||||
vty_out(vty,
|
||||
"BGP table version is 0, local router ID is %s%s",
|
||||
inet_ntoa
|
||||
(bgp->
|
||||
router_id),
|
||||
VTY_NEWLINE);
|
||||
vty_out(vty,
|
||||
"Status codes: s suppressed, d damped, h history, * valid, > best, i - internal%s",
|
||||
VTY_NEWLINE);
|
||||
vty_out(vty,
|
||||
"Origin codes: i - IGP, e - EGP, ? - incomplete%s%s",
|
||||
VTY_NEWLINE,
|
||||
VTY_NEWLINE);
|
||||
vty_out(vty,
|
||||
v4_header,
|
||||
VTY_NEWLINE);
|
||||
}
|
||||
}
|
||||
header = 0;
|
||||
}
|
||||
if (rd_header) {
|
||||
u_int16_t type;
|
||||
struct rd_as rd_as;
|
||||
struct rd_ip rd_ip;
|
||||
u_char *pnt;
|
||||
|
||||
pnt = rn->p.u.val;
|
||||
|
||||
/* Decode RD type. */
|
||||
type = decode_rd_type(pnt);
|
||||
/* Decode RD value. */
|
||||
if (type == RD_TYPE_AS)
|
||||
decode_rd_as(pnt + 2,
|
||||
&rd_as);
|
||||
else if (type == RD_TYPE_AS4)
|
||||
decode_rd_as4(pnt + 2,
|
||||
&rd_as);
|
||||
else if (type == RD_TYPE_IP)
|
||||
decode_rd_ip(pnt + 2,
|
||||
&rd_ip);
|
||||
if (use_json) {
|
||||
char buffer[BUFSIZ];
|
||||
if (type == RD_TYPE_AS
|
||||
|| type ==
|
||||
RD_TYPE_AS4)
|
||||
sprintf(buffer,
|
||||
"%u:%d",
|
||||
rd_as.
|
||||
as,
|
||||
rd_as.
|
||||
val);
|
||||
else if (type ==
|
||||
RD_TYPE_IP)
|
||||
sprintf(buffer,
|
||||
"%s:%d",
|
||||
inet_ntoa
|
||||
(rd_ip.
|
||||
ip),
|
||||
rd_ip.
|
||||
val);
|
||||
json_object_string_add
|
||||
(json_nroute,
|
||||
"routeDistinguisher",
|
||||
buffer);
|
||||
} else {
|
||||
vty_out(vty,
|
||||
"Route Distinguisher: ");
|
||||
if (type == RD_TYPE_AS)
|
||||
vty_out(vty,
|
||||
"as2 %u:%d",
|
||||
rd_as.
|
||||
as,
|
||||
rd_as.
|
||||
val);
|
||||
else if (type ==
|
||||
RD_TYPE_AS4)
|
||||
vty_out(vty,
|
||||
"as4 %u:%d",
|
||||
rd_as.
|
||||
as,
|
||||
rd_as.
|
||||
val);
|
||||
else if (type ==
|
||||
RD_TYPE_IP)
|
||||
vty_out(vty,
|
||||
"ip %s:%d",
|
||||
inet_ntoa
|
||||
(rd_ip.
|
||||
ip),
|
||||
rd_ip.
|
||||
val);
|
||||
vty_out(vty, "%s",
|
||||
VTY_NEWLINE);
|
||||
}
|
||||
rd_header = 0;
|
||||
}
|
||||
if (use_json)
|
||||
json_array =
|
||||
json_object_new_array();
|
||||
else
|
||||
json_array = NULL;
|
||||
if (option == SHOW_DISPLAY_TAGS)
|
||||
route_vty_out_tag(vty, &rm->p,
|
||||
ri, 0,
|
||||
SAFI_EVPN,
|
||||
json_array);
|
||||
else if (option == SHOW_DISPLAY_OVERLAY)
|
||||
route_vty_out_overlay(vty,
|
||||
&rm->p,
|
||||
ri, 0,
|
||||
json_array);
|
||||
else
|
||||
route_vty_out(vty, &rm->p, ri,
|
||||
0, SAFI_EVPN,
|
||||
json_array);
|
||||
output_count++;
|
||||
}
|
||||
/* XXX json */
|
||||
}
|
||||
}
|
||||
if (output_count == 0)
|
||||
vty_out(vty, "No prefixes displayed, %ld exist%s", total_count,
|
||||
VTY_NEWLINE);
|
||||
else
|
||||
vty_out(vty, "%sDisplayed %ld out of %ld total prefixes%s",
|
||||
VTY_NEWLINE, output_count, total_count, VTY_NEWLINE);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(show_ip_bgp_l2vpn_evpn,
|
||||
show_ip_bgp_l2vpn_evpn_cmd,
|
||||
"show [ip] bgp l2vpn evpn [json]",
|
||||
SHOW_STR IP_STR BGP_STR L2VPN_HELP_STR EVPN_HELP_STR JSON_STR)
|
||||
{
|
||||
return bgp_show_ethernet_vpn(vty, NULL, bgp_show_type_normal, NULL, 0,
|
||||
use_json(argc, argv));
|
||||
}
|
||||
|
||||
DEFUN(show_ip_bgp_l2vpn_evpn_rd,
|
||||
show_ip_bgp_l2vpn_evpn_rd_cmd,
|
||||
"show [ip] bgp l2vpn evpn rd ASN:nn_or_IP-address:nn [json]",
|
||||
SHOW_STR
|
||||
IP_STR
|
||||
BGP_STR
|
||||
L2VPN_HELP_STR
|
||||
EVPN_HELP_STR
|
||||
"Display information for a route distinguisher\n"
|
||||
"VPN Route Distinguisher\n" JSON_STR)
|
||||
{
|
||||
int idx_ext_community = 6;
|
||||
int ret;
|
||||
struct prefix_rd prd;
|
||||
|
||||
ret = str2prefix_rd(argv[idx_ext_community]->arg, &prd);
|
||||
if (!ret) {
|
||||
vty_out(vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
return bgp_show_ethernet_vpn(vty, &prd, bgp_show_type_normal, NULL, 0,
|
||||
use_json(argc, argv));
|
||||
}
|
||||
|
||||
DEFUN(show_ip_bgp_l2vpn_evpn_all_tags,
|
||||
show_ip_bgp_l2vpn_evpn_all_tags_cmd,
|
||||
"show [ip] bgp l2vpn evpn all tags",
|
||||
SHOW_STR
|
||||
IP_STR
|
||||
BGP_STR
|
||||
L2VPN_HELP_STR
|
||||
EVPN_HELP_STR
|
||||
"Display information about all EVPN NLRIs\n"
|
||||
"Display BGP tags for prefixes\n")
|
||||
{
|
||||
return bgp_show_ethernet_vpn(vty, NULL, bgp_show_type_normal, NULL, 1,
|
||||
0);
|
||||
}
|
||||
|
||||
DEFUN(show_ip_bgp_l2vpn_evpn_rd_tags,
|
||||
show_ip_bgp_l2vpn_evpn_rd_tags_cmd,
|
||||
"show [ip] bgp l2vpn evpn rd ASN:nn_or_IP-address:nn tags",
|
||||
SHOW_STR
|
||||
IP_STR
|
||||
BGP_STR
|
||||
L2VPN_HELP_STR
|
||||
EVPN_HELP_STR
|
||||
"Display information for a route distinguisher\n"
|
||||
"VPN Route Distinguisher\n" "Display BGP tags for prefixes\n")
|
||||
{
|
||||
int idx_ext_community = 6;
|
||||
int ret;
|
||||
struct prefix_rd prd;
|
||||
|
||||
ret = str2prefix_rd(argv[idx_ext_community]->arg, &prd);
|
||||
if (!ret) {
|
||||
vty_out(vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
return bgp_show_ethernet_vpn(vty, &prd, bgp_show_type_normal, NULL, 1,
|
||||
0);
|
||||
}
|
||||
|
||||
DEFUN(show_ip_bgp_l2vpn_evpn_all_neighbor_routes,
|
||||
show_ip_bgp_l2vpn_evpn_all_neighbor_routes_cmd,
|
||||
"show [ip] bgp l2vpn evpn all neighbors A.B.C.D routes [json]",
|
||||
SHOW_STR
|
||||
IP_STR
|
||||
BGP_STR
|
||||
L2VPN_HELP_STR
|
||||
EVPN_HELP_STR
|
||||
"Display information about all EVPN NLRIs\n"
|
||||
"Detailed information on TCP and BGP neighbor connections\n"
|
||||
"Neighbor to display information about\n"
|
||||
"Display routes learned from neighbor\n" JSON_STR)
|
||||
{
|
||||
int idx_ipv4 = 6;
|
||||
union sockunion su;
|
||||
struct peer *peer;
|
||||
int ret;
|
||||
u_char uj = use_json(argc, argv);
|
||||
|
||||
ret = str2sockunion(argv[idx_ipv4]->arg, &su);
|
||||
if (ret < 0) {
|
||||
if (uj) {
|
||||
json_object *json_no = NULL;
|
||||
json_no = json_object_new_object();
|
||||
json_object_string_add(json_no, "warning",
|
||||
"Malformed address");
|
||||
vty_out(vty, "%s%s",
|
||||
json_object_to_json_string(json_no),
|
||||
VTY_NEWLINE);
|
||||
json_object_free(json_no);
|
||||
} else
|
||||
vty_out(vty, "Malformed address: %s%s",
|
||||
argv[idx_ipv4]->arg, VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
peer = peer_lookup(NULL, &su);
|
||||
if (!peer || !peer->afc[AFI_L2VPN][SAFI_EVPN]) {
|
||||
if (uj) {
|
||||
json_object *json_no = NULL;
|
||||
json_no = json_object_new_object();
|
||||
json_object_string_add(json_no, "warning",
|
||||
"No such neighbor or address family");
|
||||
vty_out(vty, "%s%s",
|
||||
json_object_to_json_string(json_no),
|
||||
VTY_NEWLINE);
|
||||
json_object_free(json_no);
|
||||
} else
|
||||
vty_out(vty, "%% No such neighbor or address family%s",
|
||||
VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
return bgp_show_ethernet_vpn(vty, NULL, bgp_show_type_neighbor, &su, 0,
|
||||
uj);
|
||||
}
|
||||
|
||||
DEFUN(show_ip_bgp_l2vpn_evpn_rd_neighbor_routes,
|
||||
show_ip_bgp_l2vpn_evpn_rd_neighbor_routes_cmd,
|
||||
"show [ip] bgp l2vpn evpn rd ASN:nn_or_IP-address:nn neighbors A.B.C.D routes [json]",
|
||||
SHOW_STR
|
||||
IP_STR
|
||||
BGP_STR
|
||||
L2VPN_HELP_STR
|
||||
EVPN_HELP_STR
|
||||
"Display information for a route distinguisher\n"
|
||||
"VPN Route Distinguisher\n"
|
||||
"Detailed information on TCP and BGP neighbor connections\n"
|
||||
"Neighbor to display information about\n"
|
||||
"Display routes learned from neighbor\n" JSON_STR)
|
||||
{
|
||||
int idx_ext_community = 6;
|
||||
int idx_ipv4 = 8;
|
||||
int ret;
|
||||
union sockunion su;
|
||||
struct peer *peer;
|
||||
struct prefix_rd prd;
|
||||
u_char uj = use_json(argc, argv);
|
||||
|
||||
ret = str2prefix_rd(argv[idx_ext_community]->arg, &prd);
|
||||
if (!ret) {
|
||||
if (uj) {
|
||||
json_object *json_no = NULL;
|
||||
json_no = json_object_new_object();
|
||||
json_object_string_add(json_no, "warning",
|
||||
"Malformed Route Distinguisher");
|
||||
vty_out(vty, "%s%s",
|
||||
json_object_to_json_string(json_no),
|
||||
VTY_NEWLINE);
|
||||
json_object_free(json_no);
|
||||
} else
|
||||
vty_out(vty, "%% Malformed Route Distinguisher%s",
|
||||
VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
ret = str2sockunion(argv[idx_ipv4]->arg, &su);
|
||||
if (ret < 0) {
|
||||
if (uj) {
|
||||
json_object *json_no = NULL;
|
||||
json_no = json_object_new_object();
|
||||
json_object_string_add(json_no, "warning",
|
||||
"Malformed address");
|
||||
vty_out(vty, "%s%s",
|
||||
json_object_to_json_string(json_no),
|
||||
VTY_NEWLINE);
|
||||
json_object_free(json_no);
|
||||
} else
|
||||
vty_out(vty, "Malformed address: %s%s",
|
||||
argv[idx_ext_community]->arg, VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
peer = peer_lookup(NULL, &su);
|
||||
if (!peer || !peer->afc[AFI_L2VPN][SAFI_EVPN]) {
|
||||
if (uj) {
|
||||
json_object *json_no = NULL;
|
||||
json_no = json_object_new_object();
|
||||
json_object_string_add(json_no, "warning",
|
||||
"No such neighbor or address family");
|
||||
vty_out(vty, "%s%s",
|
||||
json_object_to_json_string(json_no),
|
||||
VTY_NEWLINE);
|
||||
json_object_free(json_no);
|
||||
} else
|
||||
vty_out(vty, "%% No such neighbor or address family%s",
|
||||
VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
return bgp_show_ethernet_vpn(vty, &prd, bgp_show_type_neighbor, &su, 0,
|
||||
uj);
|
||||
}
|
||||
|
||||
DEFUN(show_ip_bgp_l2vpn_evpn_all_neighbor_advertised_routes,
|
||||
show_ip_bgp_l2vpn_evpn_all_neighbor_advertised_routes_cmd,
|
||||
"show [ip] bgp l2vpn evpn all neighbors A.B.C.D advertised-routes [json]",
|
||||
SHOW_STR
|
||||
IP_STR
|
||||
BGP_STR
|
||||
L2VPN_HELP_STR
|
||||
EVPN_HELP_STR
|
||||
"Display information about all EVPN NLRIs\n"
|
||||
"Detailed information on TCP and BGP neighbor connections\n"
|
||||
"Neighbor to display information about\n"
|
||||
"Display the routes advertised to a BGP neighbor\n" JSON_STR)
|
||||
{
|
||||
int idx_ipv4 = 7;
|
||||
int ret;
|
||||
struct peer *peer;
|
||||
union sockunion su;
|
||||
u_char uj = use_json(argc, argv);
|
||||
|
||||
ret = str2sockunion(argv[idx_ipv4]->arg, &su);
|
||||
if (ret < 0) {
|
||||
if (uj) {
|
||||
json_object *json_no = NULL;
|
||||
json_no = json_object_new_object();
|
||||
json_object_string_add(json_no, "warning",
|
||||
"Malformed address");
|
||||
vty_out(vty, "%s%s",
|
||||
json_object_to_json_string(json_no),
|
||||
VTY_NEWLINE);
|
||||
json_object_free(json_no);
|
||||
} else
|
||||
vty_out(vty, "Malformed address: %s%s",
|
||||
argv[idx_ipv4]->arg, VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
peer = peer_lookup(NULL, &su);
|
||||
if (!peer || !peer->afc[AFI_L2VPN][SAFI_EVPN]) {
|
||||
if (uj) {
|
||||
json_object *json_no = NULL;
|
||||
json_no = json_object_new_object();
|
||||
json_object_string_add(json_no, "warning",
|
||||
"No such neighbor or address family");
|
||||
vty_out(vty, "%s%s",
|
||||
json_object_to_json_string(json_no),
|
||||
VTY_NEWLINE);
|
||||
json_object_free(json_no);
|
||||
} else
|
||||
vty_out(vty, "%% No such neighbor or address family%s",
|
||||
VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
return show_adj_route_vpn(vty, peer, NULL, AFI_L2VPN, SAFI_EVPN, uj);
|
||||
}
|
||||
|
||||
DEFUN(show_ip_bgp_l2vpn_evpn_rd_neighbor_advertised_routes,
|
||||
show_ip_bgp_l2vpn_evpn_rd_neighbor_advertised_routes_cmd,
|
||||
"show [ip] bgp l2vpn evpn rd ASN:nn_or_IP-address:nn neighbors A.B.C.D advertised-routes [json]",
|
||||
SHOW_STR
|
||||
IP_STR
|
||||
BGP_STR
|
||||
L2VPN_HELP_STR
|
||||
EVPN_HELP_STR
|
||||
"Display information for a route distinguisher\n"
|
||||
"VPN Route Distinguisher\n"
|
||||
"Detailed information on TCP and BGP neighbor connections\n"
|
||||
"Neighbor to display information about\n"
|
||||
"Display the routes advertised to a BGP neighbor\n" JSON_STR)
|
||||
{
|
||||
int idx_ext_community = 6;
|
||||
int idx_ipv4 = 8;
|
||||
int ret;
|
||||
struct peer *peer;
|
||||
struct prefix_rd prd;
|
||||
union sockunion su;
|
||||
u_char uj = use_json(argc, argv);
|
||||
|
||||
ret = str2sockunion(argv[idx_ipv4]->arg, &su);
|
||||
if (ret < 0) {
|
||||
if (uj) {
|
||||
json_object *json_no = NULL;
|
||||
json_no = json_object_new_object();
|
||||
json_object_string_add(json_no, "warning",
|
||||
"Malformed address");
|
||||
vty_out(vty, "%s%s",
|
||||
json_object_to_json_string(json_no),
|
||||
VTY_NEWLINE);
|
||||
json_object_free(json_no);
|
||||
} else
|
||||
vty_out(vty, "Malformed address: %s%s",
|
||||
argv[idx_ext_community]->arg, VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
peer = peer_lookup(NULL, &su);
|
||||
if (!peer || !peer->afc[AFI_L2VPN][SAFI_EVPN]) {
|
||||
if (uj) {
|
||||
json_object *json_no = NULL;
|
||||
json_no = json_object_new_object();
|
||||
json_object_string_add(json_no, "warning",
|
||||
"No such neighbor or address family");
|
||||
vty_out(vty, "%s%s",
|
||||
json_object_to_json_string(json_no),
|
||||
VTY_NEWLINE);
|
||||
json_object_free(json_no);
|
||||
} else
|
||||
vty_out(vty, "%% No such neighbor or address family%s",
|
||||
VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
ret = str2prefix_rd(argv[idx_ext_community]->arg, &prd);
|
||||
if (!ret) {
|
||||
if (uj) {
|
||||
json_object *json_no = NULL;
|
||||
json_no = json_object_new_object();
|
||||
json_object_string_add(json_no, "warning",
|
||||
"Malformed Route Distinguisher");
|
||||
vty_out(vty, "%s%s",
|
||||
json_object_to_json_string(json_no),
|
||||
VTY_NEWLINE);
|
||||
json_object_free(json_no);
|
||||
} else
|
||||
vty_out(vty, "%% Malformed Route Distinguisher%s",
|
||||
VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
return show_adj_route_vpn(vty, peer, &prd, AFI_L2VPN, SAFI_EVPN, uj);
|
||||
}
|
||||
|
||||
DEFUN(show_ip_bgp_l2vpn_evpn_all_overlay,
|
||||
show_ip_bgp_l2vpn_evpn_all_overlay_cmd,
|
||||
"show [ip] bgp l2vpn evpn all overlay",
|
||||
SHOW_STR
|
||||
IP_STR
|
||||
BGP_STR
|
||||
L2VPN_HELP_STR
|
||||
EVPN_HELP_STR
|
||||
"Display information about all EVPN NLRIs\n"
|
||||
"Display BGP Overlay Information for prefixes\n")
|
||||
{
|
||||
return bgp_show_ethernet_vpn(vty, NULL, bgp_show_type_normal, NULL,
|
||||
SHOW_DISPLAY_OVERLAY, use_json(argc,
|
||||
argv));
|
||||
}
|
||||
|
||||
DEFUN(show_ip_bgp_evpn_rd_overlay,
|
||||
show_ip_bgp_evpn_rd_overlay_cmd,
|
||||
"show [ip] bgp l2vpn evpn rd ASN:nn_or_IP-address:nn overlay",
|
||||
SHOW_STR
|
||||
IP_STR
|
||||
BGP_STR
|
||||
L2VPN_HELP_STR
|
||||
EVPN_HELP_STR
|
||||
"Display information for a route distinguisher\n"
|
||||
"VPN Route Distinguisher\n"
|
||||
"Display BGP Overlay Information for prefixes\n")
|
||||
{
|
||||
int idx_ext_community = 6;
|
||||
int ret;
|
||||
struct prefix_rd prd;
|
||||
|
||||
ret = str2prefix_rd(argv[idx_ext_community]->arg, &prd);
|
||||
if (!ret) {
|
||||
vty_out(vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
return bgp_show_ethernet_vpn(vty, &prd, bgp_show_type_normal, NULL,
|
||||
SHOW_DISPLAY_OVERLAY, use_json(argc,
|
||||
argv));
|
||||
}
|
||||
|
||||
/* For testing purpose, static route of MPLS-VPN. */
|
||||
DEFUN(evpnrt5_network,
|
||||
evpnrt5_network_cmd,
|
||||
"network <A.B.C.D/M|X:X::X:X/M> rd ASN:nn_or_IP-address:nn ethtag WORD label WORD esi WORD gwip <A.B.C.D|X:X::X:X> routermac WORD [route-map WORD]",
|
||||
"Specify a network to announce via BGP\n"
|
||||
"IP prefix\n"
|
||||
"IPv6 prefix\n"
|
||||
"Specify Route Distinguisher\n"
|
||||
"VPN Route Distinguisher\n"
|
||||
"Ethernet Tag\n"
|
||||
"Ethernet Tag Value\n"
|
||||
"BGP label\n"
|
||||
"label value\n"
|
||||
"Ethernet Segment Identifier\n"
|
||||
"ESI value ( 00:11:22:33:44:55:66:77:88:99 format) \n"
|
||||
"Gateway IP\n"
|
||||
"Gateway IP ( A.B.C.D )\n"
|
||||
"Gateway IPv6 ( X:X::X:X )\n"
|
||||
"Router Mac Ext Comm\n"
|
||||
"Router Mac address Value ( aa:bb:cc:dd:ee:ff format)\n")
|
||||
{
|
||||
int idx_ipv4_prefixlen = 1;
|
||||
int idx_ext_community = 3;
|
||||
int idx_word = 7;
|
||||
int idx_esi = 9;
|
||||
int idx_gwip = 11;
|
||||
int idx_ethtag = 5;
|
||||
int idx_routermac = 13;
|
||||
int idx_rmap = 15;
|
||||
return bgp_static_set_safi(SAFI_EVPN, vty,
|
||||
argv[idx_ipv4_prefixlen]->arg,
|
||||
argv[idx_ext_community]->arg,
|
||||
argv[idx_word]->arg,
|
||||
argv[idx_rmap] ? argv[idx_gwip]->arg : NULL,
|
||||
EVPN_IP_PREFIX, argv[idx_esi]->arg,
|
||||
argv[idx_gwip]->arg, argv[idx_ethtag]->arg,
|
||||
argv[idx_routermac]->arg);
|
||||
}
|
||||
|
||||
/* For testing purpose, static route of MPLS-VPN. */
|
||||
DEFUN(no_evpnrt5_network,
|
||||
no_evpnrt5_network_cmd,
|
||||
"no network <A.B.C.D/M|X:X::X:X/M> rd ASN:nn_or_IP-address:nn ethtag WORD label WORD esi WORD gwip <A.B.C.D|X:X::X:X>",
|
||||
NO_STR
|
||||
"Specify a network to announce via BGP\n"
|
||||
"IP prefix\n"
|
||||
"IPv6 prefix\n"
|
||||
"Specify Route Distinguisher\n"
|
||||
"VPN Route Distinguisher\n"
|
||||
"Ethernet Tag\n"
|
||||
"Ethernet Tag Value\n"
|
||||
"BGP label\n"
|
||||
"label value\n"
|
||||
"Ethernet Segment Identifier\n"
|
||||
"ESI value ( 00:11:22:33:44:55:66:77:88:99 format) \n"
|
||||
"Gateway IP\n" "Gateway IP ( A.B.C.D )\n" "Gateway IPv6 ( X:X::X:X )\n")
|
||||
{
|
||||
int idx_ipv4_prefixlen = 2;
|
||||
int idx_ext_community = 4;
|
||||
int idx_label = 8;
|
||||
int idx_ethtag = 6;
|
||||
int idx_esi = 10;
|
||||
int idx_gwip = 12;
|
||||
return bgp_static_unset_safi(SAFI_EVPN, vty,
|
||||
argv[idx_ipv4_prefixlen]->arg,
|
||||
argv[idx_ext_community]->arg,
|
||||
argv[idx_label]->arg, EVPN_IP_PREFIX,
|
||||
argv[idx_esi]->arg, argv[idx_gwip]->arg,
|
||||
argv[idx_ethtag]->arg);
|
||||
}
|
||||
|
||||
void bgp_ethernetvpn_init(void)
|
||||
{
|
||||
install_element(VIEW_NODE, &show_ip_bgp_l2vpn_evpn_cmd);
|
||||
install_element(VIEW_NODE, &show_ip_bgp_l2vpn_evpn_rd_cmd);
|
||||
install_element(VIEW_NODE, &show_ip_bgp_l2vpn_evpn_all_tags_cmd);
|
||||
install_element(VIEW_NODE, &show_ip_bgp_l2vpn_evpn_rd_tags_cmd);
|
||||
install_element(VIEW_NODE,
|
||||
&show_ip_bgp_l2vpn_evpn_all_neighbor_routes_cmd);
|
||||
install_element(VIEW_NODE,
|
||||
&show_ip_bgp_l2vpn_evpn_rd_neighbor_routes_cmd);
|
||||
install_element(VIEW_NODE,
|
||||
&show_ip_bgp_l2vpn_evpn_all_neighbor_advertised_routes_cmd);
|
||||
install_element(VIEW_NODE,
|
||||
&show_ip_bgp_l2vpn_evpn_rd_neighbor_advertised_routes_cmd);
|
||||
install_element(VIEW_NODE, &show_ip_bgp_evpn_rd_overlay_cmd);
|
||||
install_element(VIEW_NODE, &show_ip_bgp_l2vpn_evpn_all_overlay_cmd);
|
||||
install_element(BGP_EVPN_NODE, &no_evpnrt5_network_cmd);
|
||||
install_element(BGP_EVPN_NODE, &evpnrt5_network_cmd);
|
||||
}
|
29
bgpd/bgp_evpn_vty.h
Normal file
29
bgpd/bgp_evpn_vty.h
Normal file
@ -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 */
|
@ -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;
|
||||
}
|
||||
|
@ -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 *);
|
||||
|
@ -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",
|
||||
|
@ -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;
|
||||
|
@ -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 *);
|
||||
|
635
bgpd/bgp_route.c
635
bgpd/bgp_route.c
File diff suppressed because it is too large
Load Diff
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
200
bgpd/bgp_vpn.c
Normal file
200
bgpd/bgp_vpn.c
Normal file
@ -0,0 +1,200 @@
|
||||
/* VPN Related functions
|
||||
Copyright (C) 2017 6WIND
|
||||
|
||||
This file is part of Free Range Routing
|
||||
|
||||
Free Range Routing is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 2, or (at your option) any
|
||||
later version.
|
||||
|
||||
Free Range Routing is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Free Range Routing; see the file COPYING. If not, write to the Free
|
||||
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA. */
|
||||
|
||||
#include <zebra.h>
|
||||
#include "command.h"
|
||||
#include "prefix.h"
|
||||
#include "lib/json.h"
|
||||
|
||||
#include "bgpd/bgpd.h"
|
||||
#include "bgpd/bgp_route.h"
|
||||
#include "bgpd/bgp_table.h"
|
||||
#include "bgpd/bgp_attr.h"
|
||||
#include "bgpd/bgp_mplsvpn.h"
|
||||
#include "bgpd/bgp_vpn.h"
|
||||
|
||||
int
|
||||
show_adj_route_vpn (struct vty *vty, struct peer *peer, struct prefix_rd *prd,
|
||||
afi_t afi, safi_t safi, u_char use_json)
|
||||
{
|
||||
struct bgp *bgp;
|
||||
struct bgp_table *table;
|
||||
struct bgp_node *rn;
|
||||
struct bgp_node *rm;
|
||||
struct attr *attr;
|
||||
int rd_header;
|
||||
int header = 1;
|
||||
char v4_header[] = " Network Next Hop Metric LocPrf Weight Path%s";
|
||||
json_object *json = NULL;
|
||||
json_object *json_scode = NULL;
|
||||
json_object *json_ocode = NULL;
|
||||
json_object *json_routes = NULL;
|
||||
json_object *json_array = NULL;
|
||||
|
||||
bgp = bgp_get_default ();
|
||||
if (bgp == NULL)
|
||||
{
|
||||
if (!use_json)
|
||||
vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
if (use_json)
|
||||
{
|
||||
json_scode = json_object_new_object();
|
||||
json_ocode = json_object_new_object();
|
||||
json_routes = json_object_new_object();
|
||||
json = json_object_new_object();
|
||||
|
||||
json_object_string_add(json_scode, "suppressed", "s");
|
||||
json_object_string_add(json_scode, "damped", "d");
|
||||
json_object_string_add(json_scode, "history", "h");
|
||||
json_object_string_add(json_scode, "valid", "*");
|
||||
json_object_string_add(json_scode, "best", ">");
|
||||
json_object_string_add(json_scode, "internal", "i");
|
||||
|
||||
json_object_string_add(json_ocode, "igp", "i");
|
||||
json_object_string_add(json_ocode, "egp", "e");
|
||||
json_object_string_add(json_ocode, "incomplete", "?");
|
||||
}
|
||||
|
||||
for (rn = bgp_table_top (bgp->rib[afi][SAFI_MPLS_VPN]); rn;
|
||||
rn = bgp_route_next (rn))
|
||||
{
|
||||
if (prd && memcmp (rn->p.u.val, prd->val, 8) != 0)
|
||||
continue;
|
||||
|
||||
if ((table = rn->info) != NULL)
|
||||
{
|
||||
if (use_json)
|
||||
json_array = json_object_new_array();
|
||||
else
|
||||
json_array = NULL;
|
||||
|
||||
rd_header = 1;
|
||||
|
||||
for (rm = bgp_table_top (table); rm; rm = bgp_route_next (rm))
|
||||
{
|
||||
if ((attr = rm->info) != NULL)
|
||||
{
|
||||
if (header)
|
||||
{
|
||||
if (use_json)
|
||||
{
|
||||
json_object_int_add(json, "bgpTableVersion", 0);
|
||||
json_object_string_add(json, "bgpLocalRouterId", inet_ntoa (bgp->router_id));
|
||||
json_object_object_add(json, "bgpStatusCodes", json_scode);
|
||||
json_object_object_add(json, "bgpOriginCodes", json_ocode);
|
||||
}
|
||||
else
|
||||
{
|
||||
vty_out (vty, "BGP table version is 0, local router ID is %s%s",
|
||||
inet_ntoa (bgp->router_id), VTY_NEWLINE);
|
||||
vty_out (vty, "Status codes: s suppressed, d damped, h history, * valid, > best, i - internal%s",
|
||||
VTY_NEWLINE);
|
||||
vty_out (vty, "Origin codes: i - IGP, e - EGP, ? - incomplete%s%s",
|
||||
VTY_NEWLINE, VTY_NEWLINE);
|
||||
vty_out (vty, v4_header, VTY_NEWLINE);
|
||||
}
|
||||
header = 0;
|
||||
}
|
||||
|
||||
if (rd_header)
|
||||
{
|
||||
u_int16_t type;
|
||||
struct rd_as rd_as;
|
||||
struct rd_ip rd_ip = {0};
|
||||
#if ENABLE_BGP_VNC
|
||||
struct rd_vnc_eth rd_vnc_eth = {0};
|
||||
#endif
|
||||
u_char *pnt;
|
||||
|
||||
pnt = rn->p.u.val;
|
||||
|
||||
/* Decode RD type. */
|
||||
type = decode_rd_type (pnt);
|
||||
/* Decode RD value. */
|
||||
if (type == RD_TYPE_AS)
|
||||
decode_rd_as (pnt + 2, &rd_as);
|
||||
else if (type == RD_TYPE_AS4)
|
||||
decode_rd_as4 (pnt + 2, &rd_as);
|
||||
else if (type == RD_TYPE_IP)
|
||||
decode_rd_ip (pnt + 2, &rd_ip);
|
||||
#if ENABLE_BGP_VNC
|
||||
else if (type == RD_TYPE_VNC_ETH)
|
||||
decode_rd_vnc_eth (pnt, &rd_vnc_eth);
|
||||
#endif
|
||||
|
||||
if (use_json)
|
||||
{
|
||||
char buffer[BUFSIZ];
|
||||
if (type == RD_TYPE_AS || type == RD_TYPE_AS4)
|
||||
sprintf (buffer, "%u:%d", rd_as.as, rd_as.val);
|
||||
else if (type == RD_TYPE_IP)
|
||||
sprintf (buffer, "%s:%d", inet_ntoa (rd_ip.ip), rd_ip.val);
|
||||
json_object_string_add(json_routes, "routeDistinguisher", buffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
vty_out (vty, "Route Distinguisher: ");
|
||||
|
||||
if (type == RD_TYPE_AS || type == RD_TYPE_AS4)
|
||||
vty_out (vty, "%u:%d", rd_as.as, rd_as.val);
|
||||
else if (type == RD_TYPE_IP)
|
||||
vty_out (vty, "%s:%d", inet_ntoa (rd_ip.ip), rd_ip.val);
|
||||
#if ENABLE_BGP_VNC
|
||||
else if (type == RD_TYPE_VNC_ETH)
|
||||
vty_out (vty, "%u:%02x:%02x:%02x:%02x:%02x:%02x",
|
||||
rd_vnc_eth.local_nve_id,
|
||||
rd_vnc_eth.macaddr.octet[0],
|
||||
rd_vnc_eth.macaddr.octet[1],
|
||||
rd_vnc_eth.macaddr.octet[2],
|
||||
rd_vnc_eth.macaddr.octet[3],
|
||||
rd_vnc_eth.macaddr.octet[4],
|
||||
rd_vnc_eth.macaddr.octet[5]);
|
||||
#endif
|
||||
|
||||
vty_out (vty, "%s", VTY_NEWLINE);
|
||||
}
|
||||
rd_header = 0;
|
||||
}
|
||||
route_vty_out_tmp (vty, &rm->p, attr, SAFI_MPLS_VPN, use_json, json_array);
|
||||
}
|
||||
}
|
||||
if (use_json)
|
||||
{
|
||||
struct prefix *p;
|
||||
char buf_a[BUFSIZ];
|
||||
char buf_b[BUFSIZ];
|
||||
p = &rm->p;
|
||||
sprintf(buf_a, "%s/%d", inet_ntop (p->family, &p->u.prefix, buf_b, BUFSIZ), p->prefixlen);
|
||||
json_object_object_add(json_routes, buf_a, json_array);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (use_json)
|
||||
{
|
||||
json_object_object_add(json, "routes", json_routes);
|
||||
vty_out (vty, "%s%s", json_object_to_json_string_ext(json, JSON_C_TO_STRING_PRETTY), VTY_NEWLINE);
|
||||
json_object_free(json);
|
||||
}
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
30
bgpd/bgp_vpn.h
Normal file
30
bgpd/bgp_vpn.h
Normal file
@ -0,0 +1,30 @@
|
||||
/* VPN common functions to MP-BGP
|
||||
Copyright (C) 2017 6WIND
|
||||
|
||||
This file is part of Free Range Routing.
|
||||
|
||||
Free Range Routing is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 2, or (at your option) any
|
||||
later version.
|
||||
|
||||
Free Range Routing is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Free Range Routing; see the file COPYING. If not, write to the Free
|
||||
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA. */
|
||||
|
||||
#ifndef _FRR_BGP_VPN_H
|
||||
#define _FRR_BGP_VPN_H
|
||||
|
||||
#include <zebra.h>
|
||||
|
||||
extern int
|
||||
show_adj_route_vpn (struct vty *vty, struct peer *peer, struct prefix_rd *prd,
|
||||
afi_t afi, safi_t safi, u_char use_json);
|
||||
|
||||
#endif /* _QUAGGA_BGP_VPN_H */
|
@ -74,6 +74,9 @@ bgp_node_afi (struct vty *vty)
|
||||
case BGP_ENCAPV6_NODE:
|
||||
afi = AFI_IP6;
|
||||
break;
|
||||
case BGP_EVPN_NODE:
|
||||
afi = AFI_L2VPN;
|
||||
break;
|
||||
default:
|
||||
afi = AFI_IP;
|
||||
break;
|
||||
@ -101,6 +104,9 @@ bgp_node_safi (struct vty *vty)
|
||||
case BGP_IPV6M_NODE:
|
||||
safi = SAFI_MULTICAST;
|
||||
break;
|
||||
case BGP_EVPN_NODE:
|
||||
safi = SAFI_EVPN;
|
||||
break;
|
||||
default:
|
||||
safi = SAFI_UNICAST;
|
||||
break;
|
||||
@ -119,6 +125,9 @@ bgp_vty_afi_from_arg(const char *afi_str)
|
||||
else if (!strcmp(afi_str, "ipv6")) {
|
||||
afi = AFI_IP6;
|
||||
}
|
||||
else if (!strcmp(afi_str, "l2vpn")) {
|
||||
afi = AFI_L2VPN;
|
||||
}
|
||||
return afi;
|
||||
}
|
||||
|
||||
@ -195,6 +204,12 @@ argv_find_and_parse_safi (struct cmd_token **argv, int argc, int *index, safi_t
|
||||
if (safi)
|
||||
*safi = SAFI_ENCAP;
|
||||
}
|
||||
else if (argv_find (argv, argc, "evpn", index))
|
||||
{
|
||||
ret = 1;
|
||||
if (safi)
|
||||
*safi = SAFI_EVPN;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -5695,6 +5710,18 @@ DEFUN (address_family_encapv6,
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN (address_family_evpn,
|
||||
address_family_evpn_cmd,
|
||||
"address-family <l2vpn evpn>",
|
||||
"Enter Address Family command mode\n"
|
||||
"EVPN Address family\n"
|
||||
"Layer2 VPN Address family\n"
|
||||
"Ethernet Virtual Private Network Subsequent Address Family\n")
|
||||
{
|
||||
vty->node = BGP_EVPN_NODE;
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN (exit_address_family,
|
||||
exit_address_family_cmd,
|
||||
"exit-address-family",
|
||||
@ -5707,7 +5734,8 @@ DEFUN (exit_address_family,
|
||||
|| vty->node == BGP_IPV6M_NODE
|
||||
|| vty->node == BGP_VPNV6_NODE
|
||||
|| vty->node == BGP_ENCAP_NODE
|
||||
|| vty->node == BGP_ENCAPV6_NODE)
|
||||
|| vty->node == BGP_ENCAPV6_NODE
|
||||
|| vty->node == BGP_EVPN_NODE)
|
||||
vty->node = BGP_NODE;
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
@ -6662,7 +6690,7 @@ bgp_show_summary_afi_safi (struct vty *vty, struct bgp *bgp, int afi, int safi,
|
||||
}
|
||||
afi++;
|
||||
if (! afi_wildcard ||
|
||||
afi == AFI_ETHER) /* special case, not handled yet */
|
||||
afi == AFI_L2VPN) /* special case, not handled yet */
|
||||
afi = AFI_MAX;
|
||||
}
|
||||
|
||||
@ -6806,6 +6834,8 @@ afi_safi_print (afi_t afi, safi_t safi)
|
||||
return "IPv6 VPN";
|
||||
else if (afi == AFI_IP6 && safi == SAFI_ENCAP)
|
||||
return "IPv6 Encap";
|
||||
else if (afi == AFI_L2VPN && safi == SAFI_EVPN)
|
||||
return "L2VPN EVPN";
|
||||
else
|
||||
return "Unknown";
|
||||
}
|
||||
@ -6829,6 +6859,8 @@ afi_safi_json (afi_t afi, safi_t safi)
|
||||
return "IPv6VPN";
|
||||
else if (afi == AFI_IP6 && safi == SAFI_ENCAP)
|
||||
return "IPv6Encap";
|
||||
else if (afi == AFI_L2VPN && safi == SAFI_EVPN)
|
||||
return "L2VPN EVPN";
|
||||
else
|
||||
return "Unknown";
|
||||
}
|
||||
@ -9966,6 +9998,13 @@ static struct cmd_node bgp_encapv6_node =
|
||||
1
|
||||
};
|
||||
|
||||
static struct cmd_node bgp_evpn_node =
|
||||
{
|
||||
BGP_EVPN_NODE,
|
||||
"%s(config-router-evpn)# ",
|
||||
1
|
||||
};
|
||||
|
||||
static void community_list_vty (void);
|
||||
|
||||
void
|
||||
@ -9981,6 +10020,7 @@ bgp_vty_init (void)
|
||||
install_node (&bgp_vpnv6_node, NULL);
|
||||
install_node (&bgp_encap_node, NULL);
|
||||
install_node (&bgp_encapv6_node, NULL);
|
||||
install_node (&bgp_evpn_node, NULL);
|
||||
|
||||
/* Install default VTY commands to new nodes. */
|
||||
install_default (BGP_NODE);
|
||||
@ -9992,6 +10032,7 @@ bgp_vty_init (void)
|
||||
install_default (BGP_VPNV6_NODE);
|
||||
install_default (BGP_ENCAP_NODE);
|
||||
install_default (BGP_ENCAPV6_NODE);
|
||||
install_default (BGP_EVPN_NODE);
|
||||
|
||||
/* "bgp multiple-instance" commands. */
|
||||
install_element (CONFIG_NODE, &bgp_multiple_instance_cmd);
|
||||
@ -10205,6 +10246,7 @@ bgp_vty_init (void)
|
||||
install_element (BGP_VPNV6_NODE, &neighbor_activate_cmd);
|
||||
install_element (BGP_ENCAP_NODE, &neighbor_activate_cmd);
|
||||
install_element (BGP_ENCAPV6_NODE, &neighbor_activate_cmd);
|
||||
install_element (BGP_EVPN_NODE, &neighbor_activate_cmd);
|
||||
|
||||
/* "no neighbor activate" commands. */
|
||||
install_element (BGP_NODE, &no_neighbor_activate_cmd);
|
||||
@ -10216,6 +10258,7 @@ bgp_vty_init (void)
|
||||
install_element (BGP_VPNV6_NODE, &no_neighbor_activate_cmd);
|
||||
install_element (BGP_ENCAP_NODE, &no_neighbor_activate_cmd);
|
||||
install_element (BGP_ENCAPV6_NODE, &no_neighbor_activate_cmd);
|
||||
install_element (BGP_EVPN_NODE, &no_neighbor_activate_cmd);
|
||||
|
||||
/* "neighbor peer-group" set commands.
|
||||
* Long term we should only accept this command under BGP_NODE and not all of
|
||||
@ -10286,6 +10329,9 @@ bgp_vty_init (void)
|
||||
install_element (BGP_ENCAPV6_NODE, &neighbor_attr_unchanged_cmd);
|
||||
install_element (BGP_ENCAPV6_NODE, &no_neighbor_attr_unchanged_cmd);
|
||||
|
||||
install_element (BGP_EVPN_NODE, &neighbor_attr_unchanged_cmd);
|
||||
install_element (BGP_EVPN_NODE, &no_neighbor_attr_unchanged_cmd);
|
||||
|
||||
/* "nexthop-local unchanged" commands */
|
||||
install_element (BGP_IPV6_NODE, &neighbor_nexthop_local_unchanged_cmd);
|
||||
install_element (BGP_IPV6_NODE, &no_neighbor_nexthop_local_unchanged_cmd);
|
||||
@ -10828,6 +10874,8 @@ bgp_vty_init (void)
|
||||
install_element (BGP_NODE, &address_family_encap_cmd);
|
||||
install_element (BGP_NODE, &address_family_encapv6_cmd);
|
||||
|
||||
install_element (BGP_NODE, &address_family_evpn_cmd);
|
||||
|
||||
/* "exit-address-family" command. */
|
||||
install_element (BGP_IPV4_NODE, &exit_address_family_cmd);
|
||||
install_element (BGP_IPV4M_NODE, &exit_address_family_cmd);
|
||||
@ -10837,6 +10885,7 @@ bgp_vty_init (void)
|
||||
install_element (BGP_VPNV6_NODE, &exit_address_family_cmd);
|
||||
install_element (BGP_ENCAP_NODE, &exit_address_family_cmd);
|
||||
install_element (BGP_ENCAPV6_NODE, &exit_address_family_cmd);
|
||||
install_element (BGP_EVPN_NODE, &exit_address_family_cmd);
|
||||
|
||||
/* "clear ip bgp commands" */
|
||||
install_element (ENABLE_NODE, &clear_ip_bgp_all_cmd);
|
||||
|
14
bgpd/bgpd.c
14
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 ();
|
||||
|
11
bgpd/bgpd.h
11
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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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];
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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) )))
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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 */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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:
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
|
77
lib/prefix.c
77
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;
|
||||
|
47
lib/prefix.h
47
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 *);
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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:
|
||||
|
16
lib/zebra.h
16
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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -307,7 +307,7 @@ vtysh_execute_func (const char *line, int pager)
|
||||
|| saved_node == BGP_ENCAP_NODE || saved_node == BGP_ENCAPV6_NODE
|
||||
|| saved_node == BGP_IPV4_NODE
|
||||
|| saved_node == BGP_IPV6_NODE || saved_node == BGP_IPV4M_NODE
|
||||
|| saved_node == BGP_IPV6M_NODE)
|
||||
|| saved_node == BGP_IPV6M_NODE || saved_node == BGP_EVPN_NODE)
|
||||
&& (tried == 1))
|
||||
{
|
||||
vtysh_execute("exit-address-family");
|
||||
@ -561,7 +561,8 @@ vtysh_mark_file (const char *filename)
|
||||
{
|
||||
if ((prev_node == BGP_VPNV4_NODE || prev_node == BGP_IPV4_NODE
|
||||
|| prev_node == BGP_IPV6_NODE || prev_node == BGP_IPV4M_NODE
|
||||
|| prev_node == BGP_IPV6M_NODE || prev_node == BGP_VPNV6_NODE)
|
||||
|| prev_node == BGP_IPV6M_NODE || prev_node == BGP_VPNV6_NODE
|
||||
|| prev_node == BGP_EVPN_NODE)
|
||||
&& (tried == 1))
|
||||
{
|
||||
fprintf(stdout, "exit-address-family\n");
|
||||
@ -956,6 +957,12 @@ static struct cmd_node bgp_ipv6m_node =
|
||||
"%s(config-router-af)# "
|
||||
};
|
||||
|
||||
static struct cmd_node bgp_evpn_node =
|
||||
{
|
||||
BGP_EVPN_NODE,
|
||||
"%s(config-router-af)# "
|
||||
};
|
||||
|
||||
static struct cmd_node bgp_vnc_defaults_node =
|
||||
{
|
||||
BGP_VNC_DEFAULTS_NODE,
|
||||
@ -1203,6 +1210,21 @@ DEFUNSH (VTYSH_BGPD,
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUNSH (VTYSH_BGPD,
|
||||
address_family_evpn,
|
||||
address_family_evpn_cmd,
|
||||
"address-family <l2vpn evpn>",
|
||||
"Enter Address Family command mode\n"
|
||||
"EVPN Address family\n"
|
||||
"Layer2 VPN Address family\n"
|
||||
"Ethernet Virtual Private Network Subsequent Address Family\n")
|
||||
{
|
||||
#if defined(HAVE_EVPN)
|
||||
vty->node = BGP_EVPN_NODE;
|
||||
#endif /* HAVE_EVPN */
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
#if defined (ENABLE_BGP_VNC)
|
||||
DEFUNSH (VTYSH_BGPD,
|
||||
vnc_defaults,
|
||||
@ -1511,6 +1533,7 @@ vtysh_exit (struct vty *vty)
|
||||
case BGP_IPV6_NODE:
|
||||
case BGP_IPV6M_NODE:
|
||||
case BGP_VRF_POLICY_NODE:
|
||||
case BGP_EVPN_NODE:
|
||||
case BGP_VNC_DEFAULTS_NODE:
|
||||
case BGP_VNC_NVE_GROUP_NODE:
|
||||
case BGP_VNC_L2_GROUP_NODE:
|
||||
@ -3114,6 +3137,7 @@ vtysh_init_vty (void)
|
||||
install_node (&bgp_ipv6_node, NULL);
|
||||
install_node (&bgp_ipv6m_node, NULL);
|
||||
install_node (&bgp_vrf_policy_node, NULL);
|
||||
install_node (&bgp_evpn_node, NULL);
|
||||
install_node (&bgp_vnc_defaults_node, NULL);
|
||||
install_node (&bgp_vnc_nve_group_node, NULL);
|
||||
install_node (&bgp_vnc_l2_group_node, NULL);
|
||||
@ -3150,6 +3174,7 @@ vtysh_init_vty (void)
|
||||
vtysh_install_default (BGP_IPV4M_NODE);
|
||||
vtysh_install_default (BGP_IPV6_NODE);
|
||||
vtysh_install_default (BGP_IPV6M_NODE);
|
||||
vtysh_install_default (BGP_EVPN_NODE);
|
||||
#if ENABLE_BGP_VNC
|
||||
vtysh_install_default (BGP_VRF_POLICY_NODE);
|
||||
vtysh_install_default (BGP_VNC_DEFAULTS_NODE);
|
||||
@ -3222,6 +3247,7 @@ vtysh_init_vty (void)
|
||||
install_element (BGP_IPV6_NODE, &vtysh_quit_bgpd_cmd);
|
||||
install_element (BGP_IPV6M_NODE, &vtysh_exit_bgpd_cmd);
|
||||
install_element (BGP_IPV6M_NODE, &vtysh_quit_bgpd_cmd);
|
||||
install_element (BGP_EVPN_NODE, &vtysh_quit_bgpd_cmd);
|
||||
#if defined (ENABLE_BGP_VNC)
|
||||
install_element (BGP_VRF_POLICY_NODE, &vtysh_exit_bgpd_cmd);
|
||||
install_element (BGP_VRF_POLICY_NODE, &vtysh_quit_bgpd_cmd);
|
||||
@ -3267,6 +3293,7 @@ vtysh_init_vty (void)
|
||||
install_element (BGP_IPV6_NODE, &vtysh_end_all_cmd);
|
||||
install_element (BGP_IPV6M_NODE, &vtysh_end_all_cmd);
|
||||
install_element (BGP_VRF_POLICY_NODE, &vtysh_end_all_cmd);
|
||||
install_element (BGP_EVPN_NODE, &vtysh_end_all_cmd);
|
||||
install_element (BGP_VNC_DEFAULTS_NODE, &vtysh_end_all_cmd);
|
||||
install_element (BGP_VNC_NVE_GROUP_NODE, &vtysh_end_all_cmd);
|
||||
install_element (BGP_VNC_L2_GROUP_NODE, &vtysh_end_all_cmd);
|
||||
@ -3322,6 +3349,7 @@ vtysh_init_vty (void)
|
||||
#endif
|
||||
install_element (BGP_NODE, &address_family_ipv4_unicast_cmd);
|
||||
install_element (BGP_NODE, &address_family_ipv6_cmd);
|
||||
install_element (BGP_NODE, &address_family_evpn_cmd);
|
||||
install_element (BGP_VPNV4_NODE, &exit_address_family_cmd);
|
||||
install_element (BGP_VPNV6_NODE, &exit_address_family_cmd);
|
||||
install_element (BGP_ENCAP_NODE, &exit_address_family_cmd);
|
||||
@ -3330,6 +3358,7 @@ vtysh_init_vty (void)
|
||||
install_element (BGP_IPV4M_NODE, &exit_address_family_cmd);
|
||||
install_element (BGP_IPV6_NODE, &exit_address_family_cmd);
|
||||
install_element (BGP_IPV6M_NODE, &exit_address_family_cmd);
|
||||
install_element (BGP_EVPN_NODE, &exit_address_family_cmd);
|
||||
|
||||
install_element (BGP_VRF_POLICY_NODE, &exit_vrf_policy_cmd);
|
||||
install_element (BGP_VNC_DEFAULTS_NODE, &exit_vnc_config_cmd);
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user