Merge pull request #809 from donaldsharp/evpn_plus_struct_attr

Evpn plus struct attr
This commit is contained in:
Russ White 2017-07-14 09:36:31 -04:00 committed by GitHub
commit 805d1ca6b0
81 changed files with 13420 additions and 2123 deletions

View File

@ -83,7 +83,7 @@ libbgp_a_SOURCES = \
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_tlv.c $(BGP_VNC_RFAPI_SRC) bgp_attr_evpn.c \
bgp_evpn.c bgp_evpn_vty.c bgp_vpn.c bgp_label.c
bgp_evpn.c bgp_evpn_vty.c bgp_vpn.c bgp_label.c bgp_rd.c
noinst_HEADERS = \
bgp_memory.h \
@ -95,7 +95,7 @@ noinst_HEADERS = \
bgp_advertise.h bgp_vty.h bgp_mpath.h bgp_nht.h \
bgp_updgrp.h bgp_bfd.h bgp_encap_tlv.h bgp_encap_types.h \
$(BGP_VNC_RFAPI_HD) bgp_attr_evpn.h bgp_evpn.h bgp_evpn_vty.h \
bgp_vpn.h bgp_label.h
bgp_vpn.h bgp_label.h bgp_rd.h bgp_evpn_private.h
bgpd_SOURCES = bgp_main.c
bgpd_LDADD = libbgp.a $(BGP_VNC_RFP_LIB) ../lib/libfrr.la @LIBCAP@ @LIBM@

File diff suppressed because it is too large Load Diff

View File

@ -98,13 +98,35 @@ struct overlay_index
union gw_addr gw_ip;
};
/* Additional/uncommon BGP attributes.
* lazily allocated as and when a struct attr
* requires it.
*/
struct attr_extra
/* BGP core attribute structure. */
struct attr
{
/* Multi-Protocol Nexthop, AFI IPv6 */
/* AS Path structure */
struct aspath *aspath;
/* Community structure */
struct community *community;
/* Reference count of this attribute. */
unsigned long refcnt;
/* Flag of attribute is set or not. */
uint64_t flag;
/* Apart from in6_addr, the remaining static attributes */
struct in_addr nexthop;
u_int32_t med;
u_int32_t local_pref;
ifindex_t nh_ifindex;
/* Path origin attribute */
u_char origin;
/* has the route-map changed any attribute?
Used on the peer outbound side. */
u_int32_t rmap_change_flags;
/* Multi-Protocol Nexthop, AFI IPv6 */
struct in6_addr mp_nexthop_global;
struct in6_addr mp_nexthop_local;
@ -140,6 +162,9 @@ struct attr_extra
/* MP Nexthop preference */
u_char mp_nexthop_prefer_global;
/* Static MAC for EVPN */
u_char sticky;
/* route tag */
route_tag_t tag;
@ -157,38 +182,9 @@ struct attr_extra
#endif
/* EVPN */
struct overlay_index evpn_overlay;
};
/* BGP core attribute structure. */
struct attr
{
/* AS Path structure */
struct aspath *aspath;
/* Community structure */
struct community *community;
/* Lazily allocated pointer to extra attributes */
struct attr_extra *extra;
/* Reference count of this attribute. */
unsigned long refcnt;
/* Flag of attribute is set or not. */
uint64_t flag;
/* Apart from in6_addr, the remaining static attributes */
struct in_addr nexthop;
u_int32_t med;
u_int32_t local_pref;
ifindex_t nh_ifindex;
/* Path origin attribute */
u_char origin;
/* has the route-map changed any attribute?
Used on the peer outbound side. */
u_int32_t rmap_change_flags;
/* EVPN MAC Mobility sequence number, if any. */
u_int32_t mm_seqnum;
};
/* rmap_change_flags definition */
@ -220,7 +216,7 @@ struct transit
#define BGP_CLUSTER_LIST_LENGTH(attr) \
(((attr)->flag & ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST)) ? \
(attr)->extra->cluster->length : 0)
(attr)->cluster->length : 0)
typedef enum {
BGP_ATTR_PARSE_PROCEED = 0,
@ -239,8 +235,6 @@ extern void bgp_attr_finish (void);
extern bgp_attr_parse_ret_t bgp_attr_parse (struct peer *, struct attr *,
bgp_size_t, struct bgp_nlri *,
struct bgp_nlri *);
extern struct attr_extra *bgp_attr_extra_get (struct attr *);
extern void bgp_attr_extra_free (struct attr *);
extern void bgp_attr_dup (struct attr *, struct attr *);
extern void bgp_attr_deep_dup (struct attr *, struct attr *);
extern void bgp_attr_deep_free (struct attr *);
@ -333,4 +327,10 @@ bgp_rmap_nhop_changed(u_int32_t out_rmap_flags, u_int32_t in_rmap_flags)
CHECK_FLAG(in_rmap_flags, BATTR_RMAP_NEXTHOP_UNCHANGED)) ? 1 : 0);
}
static inline u_int32_t
mac_mobility_seqnum (struct attr *attr)
{
return (attr) ? attr->mm_seqnum : 0;
}
#endif /* _QUAGGA_BGP_ATTR_H */

View File

@ -33,21 +33,20 @@
#include "bgpd/bgp_attr_evpn.h"
#include "bgpd/bgp_ecommunity.h"
#include "bgpd/bgp_evpn.h"
#include "bgpd/bgp_evpn_private.h"
void bgp_add_routermac_ecom(struct attr *attr, struct ethaddr *routermac)
{
struct ecommunity_val routermac_ecom;
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);
}
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->ecommunity)
attr->ecommunity = ecommunity_new();
ecommunity_add_val(attr->ecommunity, &routermac_ecom);
ecommunity_str (attr->ecommunity);
}
/* converts to an esi
@ -57,85 +56,138 @@ void bgp_add_routermac_ecom(struct attr *attr, struct ethaddr *routermac)
*/
int str2esi(const char *str, struct eth_segment_id *id)
{
unsigned int a[ESI_LEN];
int i;
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;
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;
char *ptr;
u_char *val;
if (!id)
return NULL;
if (!id)
return NULL;
val = id->val;
ptr = (char *)XMALLOC(MTYPE_TMP, (ESI_LEN * 2 + ESI_LEN - 1 + 1) * sizeof(char));
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]);
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;
return ptr;
}
char *ecom_mac2str(char *ecom_mac)
{
char *en;
char *en;
en = ecom_mac;
en += 2;
return prefix_mac2str((struct ethaddr *)en, NULL, 0);
en = ecom_mac;
en += 2;
return prefix_mac2str((struct ethaddr *)en, NULL, 0);
}
/*
* Fetch and return the sequence number from MAC Mobility extended
* community, if present, else 0.
*/
u_int32_t
bgp_attr_mac_mobility_seqnum (struct attr *attr, u_char *sticky)
{
struct ecommunity *ecom;
int i;
u_char flags = 0;
ecom = attr->ecommunity;
if (!ecom || !ecom->size)
return 0;
/* If there is a MAC Mobility extended community, return its
* sequence number.
* TODO: RFC is silent on handling of multiple MAC mobility extended
* communities for the same route. We will bail out upon the first
* one.
*/
for (i = 0; i < ecom->size; i++)
{
u_char *pnt;
u_char type, sub_type;
u_int32_t seq_num;
pnt = (ecom->val + (i * ECOMMUNITY_SIZE));
type = *pnt++;
sub_type = *pnt++;
if (!(type == ECOMMUNITY_ENCODE_EVPN &&
sub_type == ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY))
continue;
flags = *pnt++;
if (flags & ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY_FLAG_STICKY)
*sticky = 1;
else
*sticky = 0;
pnt++;
seq_num = (*pnt++ << 24);
seq_num |= (*pnt++ << 16);
seq_num |= (*pnt++ << 8);
seq_num |= (*pnt++);
return seq_num;
}
return 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;
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) {
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 == BGP_EVPN_IP_PREFIX_ROUTE) {
p_evpn_p->eth_tag = eth_tag;
p_evpn_p->ip_prefix_length = p2.prefixlen;
if (src->family == AF_INET) {
SET_IPADDR_V4 (&p_evpn_p->ip);
memcpy(&p_evpn_p->ip.ipaddr_v4, &src->u.prefix4,
sizeof(struct in_addr));
dst->prefixlen = (u_char) PREFIX_LEN_ROUTE_TYPE_5_IPV4;
} else {
memcpy(&p_evpn_p->ip.ipaddr_v4, &src->u.prefix4,
sizeof(struct in_addr));
dst->prefixlen = (u_char) PREFIX_LEN_ROUTE_TYPE_5_IPV4;
} else {
SET_IPADDR_V6 (&p_evpn_p->ip);
memcpy(&p_evpn_p->ip.ipaddr_v6, &src->u.prefix6,
sizeof(struct in6_addr));
dst->prefixlen = (u_char) PREFIX_LEN_ROUTE_TYPE_5_IPV6;
}
} else
return -1;
return 0;
memcpy(&p_evpn_p->ip.ipaddr_v6, &src->u.prefix6,
sizeof(struct in6_addr));
dst->prefixlen = (u_char) PREFIX_LEN_ROUTE_TYPE_5_IPV6;
}
} else
return -1;
return 0;
}

View File

@ -22,31 +22,37 @@
#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 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];
struct eth_segment_id
{
u_char val[ESI_LEN];
};
union gw_addr {
struct in_addr ipv4;
struct in6_addr ipv6;
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;
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);
@ -55,5 +61,9 @@ 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 */
struct prefix *dst);
extern u_int32_t
bgp_attr_mac_mobility_seqnum (struct attr *attr, u_char *sticky);
#endif /* _QUAGGA_BGP_ATTR_EVPN_H */

View File

@ -39,6 +39,9 @@
#include "bgpd/bgp_community.h"
#include "bgpd/bgp_updgrp.h"
#include "bgpd/bgp_mplsvpn.h"
#include "bgpd/bgp_ecommunity.h"
#include "bgpd/bgp_label.h"
#include "bgpd/bgp_evpn.h"
unsigned long conf_bgp_debug_as4;
unsigned long conf_bgp_debug_neighbor_events;
@ -384,6 +387,8 @@ bgp_debug_peer_updout_enabled(char *host)
int
bgp_dump_attr (struct attr *attr, char *buf, size_t size)
{
char addrbuf[BUFSIZ];
if (! attr)
return 0;
@ -394,66 +399,68 @@ bgp_dump_attr (struct attr *attr, char *buf, size_t size)
snprintf (buf + strlen (buf), size - strlen (buf), ", origin %s",
bgp_origin_str[attr->origin]);
if (attr->extra)
{
char addrbuf[BUFSIZ];
/* Add MP case. */
if (attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL
|| attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL)
snprintf (buf + strlen (buf), size - strlen (buf), ", mp_nexthop %s",
inet_ntop (AF_INET6, &attr->mp_nexthop_global,
addrbuf, BUFSIZ));
/* Add MP case. */
if (attr->extra->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL
|| attr->extra->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL)
snprintf (buf + strlen (buf), size - strlen (buf), ", mp_nexthop %s",
inet_ntop (AF_INET6, &attr->extra->mp_nexthop_global,
addrbuf, BUFSIZ));
if (attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL)
snprintf (buf + strlen (buf), size - strlen (buf), "(%s)",
inet_ntop (AF_INET6, &attr->mp_nexthop_local,
addrbuf, BUFSIZ));
if (attr->extra->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL)
snprintf (buf + strlen (buf), size - strlen (buf), "(%s)",
inet_ntop (AF_INET6, &attr->extra->mp_nexthop_local,
addrbuf, BUFSIZ));
}
if (attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV4)
snprintf (buf, size, "nexthop %s", inet_ntoa (attr->nexthop));
if (CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)))
snprintf (buf + strlen (buf), size - strlen (buf), ", localpref %u",
attr->local_pref);
if (CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC)))
if (CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC)))
snprintf (buf + strlen (buf), size - strlen (buf), ", metric %u",
attr->med);
if (CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES)))
if (CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES)))
snprintf (buf + strlen (buf), size - strlen (buf), ", community %s",
community_str (attr->community));
if (CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES)))
snprintf (buf + strlen (buf), size - strlen (buf), ", extcommunity %s",
ecommunity_str (attr->ecommunity));
if (CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE)))
snprintf (buf + strlen (buf), size - strlen (buf), ", atomic-aggregate");
if (CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR)))
snprintf (buf + strlen (buf), size - strlen (buf), ", aggregated by %u %s",
attr->extra->aggregator_as,
inet_ntoa (attr->extra->aggregator_addr));
attr->aggregator_as,
inet_ntoa (attr->aggregator_addr));
if (CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID)))
snprintf (buf + strlen (buf), size - strlen (buf), ", originator %s",
inet_ntoa (attr->extra->originator_id));
inet_ntoa (attr->originator_id));
if (CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST)))
{
int i;
snprintf (buf + strlen (buf), size - strlen (buf), ", clusterlist");
for (i = 0; i < attr->extra->cluster->length / 4; i++)
for (i = 0; i < attr->cluster->length / 4; i++)
snprintf (buf + strlen (buf), size - strlen (buf), " %s",
inet_ntoa (attr->extra->cluster->list[i]));
inet_ntoa (attr->cluster->list[i]));
}
if (CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH)))
if (CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH)))
snprintf (buf + strlen (buf), size - strlen (buf), ", path %s",
aspath_print (attr->aspath));
if (CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_PREFIX_SID)))
{
if (attr->extra->label_index != BGP_INVALID_LABEL_INDEX)
if (attr->label_index != BGP_INVALID_LABEL_INDEX)
snprintf (buf + strlen (buf), size - strlen (buf), ", label-index %u",
attr->extra->label_index);
attr->label_index);
}
if (strlen (buf) > 1)
@ -2142,12 +2149,14 @@ bgp_debug_zebra (struct prefix *p)
}
const char *
bgp_debug_rdpfxpath2str (struct prefix_rd *prd, union prefixconstptr pu,
int addpath_valid, u_int32_t addpath_id,
char *str, int size)
bgp_debug_rdpfxpath2str (afi_t afi, safi_t safi,
struct prefix_rd *prd, union prefixconstptr pu,
mpls_label_t *label, int addpath_valid,
u_int32_t addpath_id, char *str, int size)
{
char rd_buf[RD_ADDRSTRLEN];
char pfx_buf[PREFIX_STRLEN];
char tag_buf[30];
/* ' with addpath ID ' 17
* max strlen of uint32 + 10
* +/- (just in case) + 1
@ -2163,13 +2172,24 @@ bgp_debug_rdpfxpath2str (struct prefix_rd *prd, union prefixconstptr pu,
if (addpath_valid)
snprintf(pathid_buf, sizeof(pathid_buf), " with addpath ID %u", addpath_id);
tag_buf[0] = '\0';
if (bgp_labeled_safi (safi) && label)
{
u_int32_t label_value;
label_value = decode_label (label);
sprintf (tag_buf, " label %u", label_value);
}
if (prd)
snprintf (str, size, "RD %s %s%s",
snprintf (str, size, "RD %s %s%s%s",
prefix_rd2str(prd, rd_buf, sizeof (rd_buf)),
prefix2str (pu, pfx_buf, sizeof (pfx_buf)), pathid_buf);
prefix2str (pu, pfx_buf, sizeof (pfx_buf)),
tag_buf, pathid_buf);
else
snprintf (str, size, "%s%s",
prefix2str (pu, pfx_buf, sizeof (pfx_buf)), pathid_buf);
snprintf (str, size, "%s%s%s",
prefix2str (pu, pfx_buf, sizeof (pfx_buf)),
tag_buf, pathid_buf);
return str;
}

View File

@ -153,7 +153,8 @@ 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,
extern const char *bgp_debug_rdpfxpath2str (afi_t, safi_t, struct prefix_rd *,
union prefixconstptr, mpls_label_t *,
int, u_int32_t, char *, int);
const char *bgp_notify_admin_message(char *buf, size_t bufsz, u_char *data, size_t datalen);

View File

@ -304,6 +304,61 @@ enum ecommunity_token
ecommunity_token_val,
};
/*
* Encode BGP extended community from passed values. Supports types
* defined in RFC 4360 and well-known sub-types.
*/
static int
ecommunity_encode (u_char type, u_char sub_type, int trans,
as_t as, struct in_addr ip, u_int32_t val,
struct ecommunity_val *eval)
{
assert (eval);
if (type == ECOMMUNITY_ENCODE_AS)
{
if (as > BGP_AS_MAX)
return -1;
}
else if (type == ECOMMUNITY_ENCODE_IP
|| type == ECOMMUNITY_ENCODE_AS4)
{
if (val > UINT16_MAX)
return -1;
}
/* Fill in the values. */
eval->val[0] = type;
if (!trans)
eval->val[0] |= ECOMMUNITY_FLAG_NON_TRANSITIVE;
eval->val[1] = sub_type;
if (type == ECOMMUNITY_ENCODE_AS)
{
eval->val[2] = (as >> 8) & 0xff;
eval->val[3] = as & 0xff;
eval->val[4] = (val >> 24) & 0xff;
eval->val[5] = (val >> 16) & 0xff;
eval->val[6] = (val >> 8) & 0xff;
eval->val[7] = val & 0xff;
}
else if (type == ECOMMUNITY_ENCODE_IP)
{
memcpy (&eval->val[2], &ip, sizeof (struct in_addr));
eval->val[6] = (val >> 8) & 0xff;
eval->val[7] = val & 0xff;
}
else
{
eval->val[2] = (as >> 24) & 0xff;
eval->val[3] = (as >> 16) & 0xff;
eval->val[4] = (as >> 8) & 0xff;
eval->val[5] = as & 0xff;
eval->val[6] = (val >> 8) & 0xff;
eval->val[7] = val & 0xff;
}
return 0;
}
/* Get next Extended Communities token from the string. */
static const char *
ecommunity_gettoken (const char *str, struct ecommunity_val *eval,
@ -318,6 +373,7 @@ ecommunity_gettoken (const char *str, struct ecommunity_val *eval,
struct in_addr ip;
as_t as = 0;
u_int32_t val = 0;
u_char ecomm_type;
char buf[INET_ADDRSTRLEN + 1];
/* Skip white space. */
@ -452,44 +508,15 @@ ecommunity_gettoken (const char *str, struct ecommunity_val *eval,
if (!digit || !separator)
goto error;
/* Encode result into routing distinguisher. */
/* Encode result into extended community. */
if (dot)
{
if (val > UINT16_MAX)
goto error;
eval->val[0] = ECOMMUNITY_ENCODE_IP;
eval->val[1] = 0;
memcpy (&eval->val[2], &ip, sizeof (struct in_addr));
eval->val[6] = (val >> 8) & 0xff;
eval->val[7] = val & 0xff;
}
ecomm_type = ECOMMUNITY_ENCODE_IP;
else if (as > BGP_AS_MAX)
{
if (val > UINT16_MAX)
goto error;
eval->val[0] = ECOMMUNITY_ENCODE_AS4;
eval->val[1] = 0;
eval->val[2] = (as >>24) & 0xff;
eval->val[3] = (as >>16) & 0xff;
eval->val[4] = (as >>8) & 0xff;
eval->val[5] = as & 0xff;
eval->val[6] = (val >> 8) & 0xff;
eval->val[7] = val & 0xff;
}
ecomm_type = ECOMMUNITY_ENCODE_AS4;
else
{
eval->val[0] = ECOMMUNITY_ENCODE_AS;
eval->val[1] = 0;
eval->val[2] = (as >>8) & 0xff;
eval->val[3] = as & 0xff;
eval->val[4] = (val >>24) & 0xff;
eval->val[5] = (val >>16) & 0xff;
eval->val[6] = (val >>8) & 0xff;
eval->val[7] = val & 0xff;
}
ecomm_type = ECOMMUNITY_ENCODE_AS;
if (ecommunity_encode (ecomm_type, 0, 1, as, ip, val, eval))
goto error;
*token = ecommunity_token_val;
return p;
@ -581,6 +608,81 @@ ecommunity_str2com (const char *str, int type, int keyword_included)
return ecom;
}
static int
ecommunity_rt_soo_str (char *buf, u_int8_t *pnt, int type,
int sub_type, int format)
{
int len = 0;
const char *prefix;
/* For parse Extended Community attribute tupple. */
struct ecommunity_as
{
as_t as;
u_int32_t val;
} eas;
struct ecommunity_ip
{
struct in_addr ip;
u_int16_t val;
} eip;
/* Determine prefix for string, if any. */
switch (format)
{
case ECOMMUNITY_FORMAT_COMMUNITY_LIST:
prefix = (sub_type == ECOMMUNITY_ROUTE_TARGET ? "rt " : "soo ");
break;
case ECOMMUNITY_FORMAT_DISPLAY:
prefix = (sub_type == ECOMMUNITY_ROUTE_TARGET ? "RT:" : "SoO:");
break;
case ECOMMUNITY_FORMAT_ROUTE_MAP:
prefix = "";
break;
default:
prefix = "";
break;
}
/* Put string into buffer. */
if (type == ECOMMUNITY_ENCODE_AS4)
{
eas.as = (*pnt++ << 24);
eas.as |= (*pnt++ << 16);
eas.as |= (*pnt++ << 8);
eas.as |= (*pnt++);
eas.val = (*pnt++ << 8);
eas.val |= (*pnt++);
len = sprintf (buf, "%s%u:%u", prefix, eas.as, eas.val);
}
else if (type == ECOMMUNITY_ENCODE_AS)
{
eas.as = (*pnt++ << 8);
eas.as |= (*pnt++);
eas.val = (*pnt++ << 24);
eas.val |= (*pnt++ << 16);
eas.val |= (*pnt++ << 8);
eas.val |= (*pnt++);
len = sprintf (buf, "%s%u:%u", prefix, eas.as, eas.val);
}
else if (type == ECOMMUNITY_ENCODE_IP)
{
memcpy (&eip.ip, pnt, 4);
pnt += 4;
eip.val = (*pnt++ << 8);
eip.val |= (*pnt++);
len = sprintf (buf, "%s%s:%u", prefix, inet_ntoa (eip.ip), eip.val);
}
return len;
}
/* Convert extended community attribute to string.
Due to historical reason of industry standard implementation, there
@ -610,29 +712,15 @@ ecommunity_ecom2str (struct ecommunity *ecom, int format, int filter)
{
int i;
u_int8_t *pnt;
int encode = 0;
int type = 0;
int sub_type = 0;
#define ECOMMUNITY_STR_DEFAULT_LEN 27
int str_size;
int str_pnt;
char *str_buf;
const char *prefix;
int len = 0;
int first = 1;
/* For parse Extended Community attribute tupple. */
struct ecommunity_as
{
as_t as;
u_int32_t val;
} eas;
struct ecommunity_ip
{
struct in_addr ip;
u_int16_t val;
} eip;
if (ecom->size == 0)
{
str_buf = XMALLOC (MTYPE_ECOMMUNITY_STR, 1);
@ -648,6 +736,8 @@ ecommunity_ecom2str (struct ecommunity *ecom, int format, int filter)
for (i = 0; i < ecom->size; i++)
{
int unk_ecom = 0;
/* Make it sure size is enough. */
while (str_pnt + ECOMMUNITY_STR_DEFAULT_LEN >= str_size)
{
@ -662,39 +752,39 @@ ecommunity_ecom2str (struct ecommunity *ecom, int format, int filter)
pnt = ecom->val + (i * 8);
/* High-order octet of type. */
encode = *pnt++;
type = *pnt++;
switch (encode)
if (type == ECOMMUNITY_ENCODE_AS ||
type == ECOMMUNITY_ENCODE_IP ||
type == ECOMMUNITY_ENCODE_AS4)
{
case ECOMMUNITY_ENCODE_AS:
case ECOMMUNITY_ENCODE_IP:
case ECOMMUNITY_ENCODE_AS4:
break;
case ECOMMUNITY_ENCODE_OPAQUE:
if(filter == ECOMMUNITY_ROUTE_TARGET)
{
continue;
}
/* Low-order octet of type. */
sub_type = *pnt++;
if (sub_type != ECOMMUNITY_ROUTE_TARGET &&
sub_type != ECOMMUNITY_SITE_ORIGIN)
unk_ecom = 1;
else
len = ecommunity_rt_soo_str (str_buf + str_pnt, pnt, type,
sub_type, format);
}
else if (type == ECOMMUNITY_ENCODE_OPAQUE)
{
if (filter == ECOMMUNITY_ROUTE_TARGET)
continue;
if (*pnt == ECOMMUNITY_OPAQUE_SUBTYPE_ENCAP)
{
uint16_t tunneltype;
memcpy (&tunneltype, pnt + 5, 2);
tunneltype = ntohs(tunneltype);
len = sprintf (str_buf + str_pnt, "ET:%d", tunneltype);
str_pnt += len;
first = 0;
continue;
}
len = sprintf (str_buf + str_pnt, "?");
str_pnt += len;
first = 0;
continue;
case ECOMMUNITY_ENCODE_EVPN:
if(filter == ECOMMUNITY_ROUTE_TARGET)
{
continue;
}
else
unk_ecom = 1;
}
else if (type == ECOMMUNITY_ENCODE_EVPN)
{
if (filter == ECOMMUNITY_ROUTE_TARGET)
continue;
if (*pnt == ECOMMUNITY_SITE_ORIGIN)
{
char macaddr[6];
@ -703,91 +793,32 @@ ecommunity_ecom2str (struct ecommunity *ecom, int format, int filter)
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;
first = 0;
continue;
else if (*pnt == ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY)
{
u_int32_t seqnum;
u_char flags = *++pnt;
memcpy (&seqnum, pnt + 2, 4);
seqnum = ntohl(seqnum);
if (flags & ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY_FLAG_STICKY)
len = sprintf (str_buf + str_pnt, "MM:%u, sticky MAC", seqnum);
else
len = sprintf (str_buf + str_pnt, "MM:%u", seqnum);
}
else
unk_ecom = 1;
}
else
unk_ecom = 1;
/* Low-order octet of type. */
type = *pnt++;
if (type != ECOMMUNITY_ROUTE_TARGET && type != ECOMMUNITY_SITE_ORIGIN)
{
len = sprintf (str_buf + str_pnt, "?");
str_pnt += len;
first = 0;
continue;
}
if (unk_ecom)
len = sprintf (str_buf + str_pnt, "?");
switch (format)
{
case ECOMMUNITY_FORMAT_COMMUNITY_LIST:
prefix = (type == ECOMMUNITY_ROUTE_TARGET ? "rt " : "soo ");
break;
case ECOMMUNITY_FORMAT_DISPLAY:
prefix = (type == ECOMMUNITY_ROUTE_TARGET ? "RT:" : "SoO:");
break;
case ECOMMUNITY_FORMAT_ROUTE_MAP:
prefix = "";
break;
default:
prefix = "";
break;
}
/* Put string into buffer. */
if (encode == ECOMMUNITY_ENCODE_AS4)
{
eas.as = (*pnt++ << 24);
eas.as |= (*pnt++ << 16);
eas.as |= (*pnt++ << 8);
eas.as |= (*pnt++);
eas.val = (*pnt++ << 8);
eas.val |= (*pnt++);
len = sprintf( str_buf + str_pnt, "%s%u:%u", prefix,
eas.as, eas.val );
str_pnt += len;
first = 0;
}
if (encode == ECOMMUNITY_ENCODE_AS)
{
eas.as = (*pnt++ << 8);
eas.as |= (*pnt++);
eas.val = (*pnt++ << 24);
eas.val |= (*pnt++ << 16);
eas.val |= (*pnt++ << 8);
eas.val |= (*pnt++);
len = sprintf (str_buf + str_pnt, "%s%u:%u", prefix,
eas.as, eas.val);
str_pnt += len;
first = 0;
}
else if (encode == ECOMMUNITY_ENCODE_IP)
{
memcpy (&eip.ip, pnt, 4);
pnt += 4;
eip.val = (*pnt++ << 8);
eip.val |= (*pnt++);
len = sprintf (str_buf + str_pnt, "%s%s:%u", prefix,
inet_ntoa (eip.ip), eip.val);
str_pnt += len;
first = 0;
}
str_pnt += len;
first = 0;
}
return str_buf;
}

View File

@ -32,12 +32,15 @@
#define ECOMMUNITY_ROUTE_TARGET 0x02
#define ECOMMUNITY_SITE_ORIGIN 0x03
/* Low-order octet of the Extended Communities type field for EVPN types */
#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
#define ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY_FLAG_STICKY 0x01
/* Low-order octet of the Extended Communities type field for OPAQUE types */
#define ECOMMUNITY_OPAQUE_SUBTYPE_ENCAP 0x0c
@ -76,6 +79,54 @@ struct ecommunity_val
#define ecom_length(X) ((X)->size * ECOMMUNITY_SIZE)
/*
* Encode BGP Route Target AS:nn.
*/
static inline void
encode_route_target_as (as_t as, u_int32_t val,
struct ecommunity_val *eval)
{
eval->val[0] = ECOMMUNITY_ENCODE_AS;
eval->val[1] = ECOMMUNITY_ROUTE_TARGET;
eval->val[2] = (as >> 8) & 0xff;
eval->val[3] = as & 0xff;
eval->val[4] = (val >> 24) & 0xff;
eval->val[5] = (val >> 16) & 0xff;
eval->val[6] = (val >> 8) & 0xff;
eval->val[7] = val & 0xff;
}
/*
* Encode BGP Route Target IP:nn.
*/
static inline void
encode_route_target_ip (struct in_addr ip, u_int16_t val,
struct ecommunity_val *eval)
{
eval->val[0] = ECOMMUNITY_ENCODE_IP;
eval->val[1] = ECOMMUNITY_ROUTE_TARGET;
memcpy (&eval->val[2], &ip, sizeof (struct in_addr));
eval->val[6] = (val >> 8) & 0xff;
eval->val[7] = val & 0xff;
}
/*
* Encode BGP Route Target AS4:nn.
*/
static inline void
encode_route_target_as4 (as_t as, u_int16_t val,
struct ecommunity_val *eval)
{
eval->val[0] = ECOMMUNITY_ENCODE_AS4;
eval->val[1] = ECOMMUNITY_ROUTE_TARGET;
eval->val[2] = (as >> 24) & 0xff;
eval->val[3] = (as >> 16) & 0xff;
eval->val[4] = (as >> 8) & 0xff;
eval->val[5] = as & 0xff;
eval->val[6] = (val >> 8) & 0xff;
eval->val[7] = val & 0xff;
}
extern void ecommunity_init (void);
extern void ecommunity_finish (void);
extern void ecommunity_free (struct ecommunity **);

View File

@ -238,7 +238,7 @@ subtlv_encode_remote_endpoint(
if (last) {\
last->next = new;\
} else {\
extra->encap_subtlvs = new;\
attr->encap_subtlvs = new;\
}\
last = new;\
}\
@ -249,13 +249,12 @@ bgp_encap_type_l2tpv3overip_to_tlv(
struct bgp_encap_type_l2tpv3_over_ip *bet, /* input structure */
struct attr *attr)
{
struct attr_extra *extra = bgp_attr_extra_get(attr);
struct bgp_attr_encap_subtlv *last;
/* advance to last subtlv */
for (last = extra->encap_subtlvs; last && last->next; last = last->next);
for (last = attr->encap_subtlvs; last && last->next; last = last->next);
extra->encap_tunneltype = BGP_ENCAP_TYPE_L2TPV3_OVER_IP;
attr->encap_tunneltype = BGP_ENCAP_TYPE_L2TPV3_OVER_IP;
assert(CHECK_FLAG(bet->valid_subtlvs, BGP_TEA_SUBTLV_ENCAP));
@ -270,13 +269,12 @@ bgp_encap_type_gre_to_tlv(
struct bgp_encap_type_gre *bet, /* input structure */
struct attr *attr)
{
struct attr_extra *extra = bgp_attr_extra_get(attr);
struct bgp_attr_encap_subtlv *last;
/* advance to last subtlv */
for (last = extra->encap_subtlvs; last && last->next; last = last->next);
for (last = attr->encap_subtlvs; last && last->next; last = last->next);
extra->encap_tunneltype = BGP_ENCAP_TYPE_GRE;
attr->encap_tunneltype = BGP_ENCAP_TYPE_GRE;
ENC_SUBTLV(BGP_TEA_SUBTLV_ENCAP, subtlv_encode_encap_gre, st_encap);
ENC_SUBTLV(BGP_TEA_SUBTLV_PROTO_TYPE, subtlv_encode_proto_type, st_proto);
@ -289,13 +287,12 @@ bgp_encap_type_ip_in_ip_to_tlv(
struct bgp_encap_type_ip_in_ip *bet, /* input structure */
struct attr *attr)
{
struct attr_extra *extra = bgp_attr_extra_get(attr);
struct bgp_attr_encap_subtlv *last;
/* advance to last subtlv */
for (last = extra->encap_subtlvs; last && last->next; last = last->next);
for (last = attr->encap_subtlvs; last && last->next; last = last->next);
extra->encap_tunneltype = BGP_ENCAP_TYPE_IP_IN_IP;
attr->encap_tunneltype = BGP_ENCAP_TYPE_IP_IN_IP;
ENC_SUBTLV(BGP_TEA_SUBTLV_PROTO_TYPE, subtlv_encode_proto_type, st_proto);
ENC_SUBTLV(BGP_TEA_SUBTLV_COLOR, subtlv_encode_color, st_color);
@ -307,13 +304,12 @@ bgp_encap_type_transmit_tunnel_endpoint(
struct bgp_encap_type_transmit_tunnel_endpoint *bet, /* input structure */
struct attr *attr)
{
struct attr_extra *extra = bgp_attr_extra_get(attr);
struct bgp_attr_encap_subtlv *last;
/* advance to last subtlv */
for (last = extra->encap_subtlvs; last && last->next; last = last->next);
for (last = attr->encap_subtlvs; last && last->next; last = last->next);
extra->encap_tunneltype = BGP_ENCAP_TYPE_TRANSMIT_TUNNEL_ENDPOINT;
attr->encap_tunneltype = BGP_ENCAP_TYPE_TRANSMIT_TUNNEL_ENDPOINT;
/* no subtlvs for this type */
}
@ -323,13 +319,12 @@ bgp_encap_type_ipsec_in_tunnel_mode_to_tlv(
struct bgp_encap_type_ipsec_in_tunnel_mode *bet, /* input structure */
struct attr *attr)
{
struct attr_extra *extra = bgp_attr_extra_get(attr);
struct bgp_attr_encap_subtlv *last;
/* advance to last subtlv */
for (last = extra->encap_subtlvs; last && last->next; last = last->next);
for (last = attr->encap_subtlvs; last && last->next; last = last->next);
extra->encap_tunneltype = BGP_ENCAP_TYPE_IPSEC_IN_TUNNEL_MODE;
attr->encap_tunneltype = BGP_ENCAP_TYPE_IPSEC_IN_TUNNEL_MODE;
ENC_SUBTLV(BGP_TEA_SUBTLV_IPSEC_TA, subtlv_encode_ipsec_ta, st_ipsec_ta);
}
@ -339,13 +334,12 @@ bgp_encap_type_ip_in_ip_tunnel_with_ipsec_transport_mode_to_tlv(
struct bgp_encap_type_ip_in_ip_tunnel_with_ipsec_transport_mode *bet, /* input structure */
struct attr *attr)
{
struct attr_extra *extra = bgp_attr_extra_get(attr);
struct bgp_attr_encap_subtlv *last;
/* advance to last subtlv */
for (last = extra->encap_subtlvs; last && last->next; last = last->next);
for (last = attr->encap_subtlvs; last && last->next; last = last->next);
extra->encap_tunneltype = BGP_ENCAP_TYPE_IP_IN_IP_TUNNEL_WITH_IPSEC_TRANSPORT_MODE;
attr->encap_tunneltype = BGP_ENCAP_TYPE_IP_IN_IP_TUNNEL_WITH_IPSEC_TRANSPORT_MODE;
ENC_SUBTLV(BGP_TEA_SUBTLV_IPSEC_TA, subtlv_encode_ipsec_ta, st_ipsec_ta);
}
@ -355,13 +349,12 @@ bgp_encap_type_mpls_in_ip_tunnel_with_ipsec_transport_mode_to_tlv(
struct bgp_encap_type_mpls_in_ip_tunnel_with_ipsec_transport_mode *bet, /* input structure */
struct attr *attr)
{
struct attr_extra *extra = bgp_attr_extra_get(attr);
struct bgp_attr_encap_subtlv *last;
/* advance to last subtlv */
for (last = extra->encap_subtlvs; last && last->next; last = last->next);
for (last = attr->encap_subtlvs; last && last->next; last = last->next);
extra->encap_tunneltype = BGP_ENCAP_TYPE_MPLS_IN_IP_TUNNEL_WITH_IPSEC_TRANSPORT_MODE;
attr->encap_tunneltype = BGP_ENCAP_TYPE_MPLS_IN_IP_TUNNEL_WITH_IPSEC_TRANSPORT_MODE;
ENC_SUBTLV(BGP_TEA_SUBTLV_IPSEC_TA, subtlv_encode_ipsec_ta, st_ipsec_ta);
}
@ -371,13 +364,12 @@ bgp_encap_type_pbb_to_tlv(
struct bgp_encap_type_pbb *bet, /* input structure */
struct attr *attr)
{
struct attr_extra *extra = bgp_attr_extra_get(attr);
struct bgp_attr_encap_subtlv *last;
/* advance to last subtlv */
for (last = extra->encap_subtlvs; last && last->next; last = last->next);
for (last = attr->encap_subtlvs; last && last->next; last = last->next);
extra->encap_tunneltype = BGP_ENCAP_TYPE_PBB;
attr->encap_tunneltype = BGP_ENCAP_TYPE_PBB;
assert(CHECK_FLAG(bet->valid_subtlvs, BGP_TEA_SUBTLV_ENCAP));
ENC_SUBTLV(BGP_TEA_SUBTLV_ENCAP, subtlv_encode_encap_pbb, st_encap);
@ -388,16 +380,15 @@ bgp_encap_type_vxlan_to_tlv(
struct bgp_encap_type_vxlan *bet, /* input structure */
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;
attr->encap_tunneltype = BGP_ENCAP_TYPE_VXLAN;
if(bet == NULL ||!bet->vnid)
return;
if(extra->encap_subtlvs)
XFREE(MTYPE_ENCAP_TLV, extra->encap_subtlvs);
if(attr->encap_subtlvs)
XFREE(MTYPE_ENCAP_TLV, attr->encap_subtlvs);
tlv = XCALLOC (MTYPE_ENCAP_TLV, sizeof(struct bgp_attr_encap_subtlv)-1+12);
tlv->type = 1; /* encapsulation type */
tlv->length = 12;
@ -411,7 +402,7 @@ bgp_encap_type_vxlan_to_tlv(
char *ptr = (char *)&tlv->value + 4;
memcpy( ptr, bet->mac_address, 6);
}
extra->encap_subtlvs = tlv;
attr->encap_subtlvs = tlv;
return;
}
@ -420,9 +411,7 @@ bgp_encap_type_nvgre_to_tlv(
struct bgp_encap_type_nvgre *bet, /* input structure */
struct attr *attr)
{
struct attr_extra *extra = bgp_attr_extra_get(attr);
extra->encap_tunneltype = BGP_ENCAP_TYPE_NVGRE;
attr->encap_tunneltype = BGP_ENCAP_TYPE_NVGRE;
}
void
@ -438,9 +427,7 @@ bgp_encap_type_mpls_in_gre_to_tlv(
struct bgp_encap_type_mpls_in_gre *bet, /* input structure */
struct attr *attr)
{
struct attr_extra *extra = bgp_attr_extra_get(attr);
extra->encap_tunneltype = BGP_ENCAP_TYPE_MPLS_IN_GRE;
attr->encap_tunneltype = BGP_ENCAP_TYPE_MPLS_IN_GRE;
}
void
@ -448,9 +435,8 @@ bgp_encap_type_vxlan_gpe_to_tlv(
struct bgp_encap_type_vxlan_gpe *bet, /* input structure */
struct attr *attr)
{
struct attr_extra *extra = bgp_attr_extra_get(attr);
extra->encap_tunneltype = BGP_ENCAP_TYPE_VXLAN_GPE;
attr->encap_tunneltype = BGP_ENCAP_TYPE_VXLAN_GPE;
}
void
@ -458,9 +444,8 @@ bgp_encap_type_mpls_in_udp_to_tlv(
struct bgp_encap_type_mpls_in_udp *bet, /* input structure */
struct attr *attr)
{
struct attr_extra *extra = bgp_attr_extra_get(attr);
extra->encap_tunneltype = BGP_ENCAP_TYPE_MPLS_IN_UDP;
attr->encap_tunneltype = BGP_ENCAP_TYPE_MPLS_IN_UDP;
}

View File

@ -19,6 +19,8 @@
#ifndef _QUAGGA_BGP_ENCAP_TYPES_H
#define _QUAGGA_BGP_ENCAP_TYPES_H
#include "bgpd/bgp_ecommunity.h"
/* from http://www.iana.org/assignments/bgp-parameters/bgp-parameters.xhtml#tunnel-types */
typedef enum {
BGP_ENCAP_TYPE_RESERVED=0,
@ -213,4 +215,15 @@ struct bgp_encap_type_pbb {
struct bgp_tea_subtlv_encap_pbb st_encap;
};
static inline void
encode_encap_extcomm (bgp_encap_types tnl_type,
struct ecommunity_val *eval)
{
memset (eval, 0, sizeof (*eval));
eval->val[0] = ECOMMUNITY_ENCODE_OPAQUE;
eval->val[1] = ECOMMUNITY_OPAQUE_SUBTYPE_ENCAP;
eval->val[6] = ((tnl_type) >> 8) & 0xff;
eval->val[7] = (tnl_type) & 0xff;
}
#endif /* _QUAGGA_BGP_ENCAP_TYPES_H */

File diff suppressed because it is too large Load Diff

View File

@ -21,20 +21,45 @@
#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);
#include "vxlan.h"
#define EVPN_ROUTE_STRLEN 200 /* Must be >> MAC + IPv6 strings. */
extern void
bgp_packet_mpattr_route_type_5(struct stream *s,
struct prefix *p, struct prefix_rd *prd,
mpls_label_t *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
bgp_evpn_handle_router_id_update (struct bgp *bgp, int withdraw);
extern char *
bgp_evpn_label2str (mpls_label_t *label, char *buf, int len);
extern char *
bgp_evpn_route2str (struct prefix_evpn *p, char *buf, int len);
extern void
bgp_evpn_encode_prefix (struct stream *s, struct prefix *p,
struct prefix_rd *prd, mpls_label_t *label,
struct attr *attr, int addpath_encode,
u_int32_t addpath_tx_id);
extern int bgp_nlri_parse_evpn(struct peer *peer, struct attr *attr,
struct bgp_nlri *packet, int withdraw);
extern int
bgp_evpn_import_route (struct bgp *bgp, afi_t afi, safi_t safi,
struct prefix *p, struct bgp_info *ri);
extern int
bgp_evpn_unimport_route (struct bgp *bgp, afi_t afi, safi_t safi,
struct prefix *p, struct bgp_info *ri);
extern int
bgp_evpn_local_macip_del (struct bgp *bgp, vni_t vni,
struct ethaddr *mac, struct ipaddr *ip);
extern int
bgp_evpn_local_macip_add (struct bgp *bgp, vni_t vni,
struct ethaddr *mac, struct ipaddr *ip,
u_char sticky);
extern int
bgp_evpn_local_vni_del (struct bgp *bgp, vni_t vni);
extern int
bgp_evpn_local_vni_add (struct bgp *bgp, vni_t vni, struct in_addr originator_ip);
extern void
bgp_evpn_cleanup_on_disable (struct bgp *bgp);
extern void
bgp_evpn_cleanup (struct bgp *bgp);
extern void
bgp_evpn_init (struct bgp *bgp);
#endif /* _QUAGGA_BGP_EVPN_H */
#endif /* _QUAGGA_BGP_EVPN_H */

232
bgpd/bgp_evpn_private.h Normal file
View File

@ -0,0 +1,232 @@
/* BGP EVPN internal definitions
* Copyright (C) 2017 Cumulus Networks, Inc.
*
* This file is part of FRR.
*
* FRR 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.
*
* FRR 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 FRR; see the file COPYING. If not, write to the Free
* Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/
#ifndef _BGP_EVPN_PRIVATE_H
#define _BGP_EVPN_PRIVATE_H
#include "vxlan.h"
#include "zebra.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_ecommunity.h"
/* EVPN prefix lengths. */
#define EVPN_TYPE_2_ROUTE_PREFIXLEN 224
#define EVPN_TYPE_3_ROUTE_PREFIXLEN 224
/* EVPN route types. */
typedef enum
{
BGP_EVPN_AD_ROUTE = 1, /* Ethernet Auto-Discovery (A-D) route */
BGP_EVPN_MAC_IP_ROUTE, /* MAC/IP Advertisement route */
BGP_EVPN_IMET_ROUTE, /* Inclusive Multicast Ethernet Tag route */
BGP_EVPN_ES_ROUTE, /* Ethernet Segment route */
BGP_EVPN_IP_PREFIX_ROUTE, /* IP Prefix route */
} bgp_evpn_route_type;
/*
* Hash table of EVIs. Right now, the only type of EVI supported is with
* VxLAN encapsulation, hence each EVI corresponds to a L2 VNI.
* The VNIs are not "created" through BGP but through some other interface
* on the system. This table stores VNIs that BGP comes to know as present
* on the system (through interaction with zebra) as well as pre-configured
* VNIs (which need to be defined in the system to become "live").
*/
struct bgpevpn
{
vni_t vni;
u_int32_t flags;
#define VNI_FLAG_CFGD 0x1 /* VNI is user configured */
#define VNI_FLAG_LIVE 0x2 /* VNI is "live" */
#define VNI_FLAG_RD_CFGD 0x4 /* RD is user configured. */
#define VNI_FLAG_IMPRT_CFGD 0x8 /* Import RT is user configured */
#define VNI_FLAG_EXPRT_CFGD 0x10 /* Export RT is user configured */
/* Id for deriving the RD automatically for this VNI */
u_int16_t rd_id;
/* RD for this VNI. */
struct prefix_rd prd;
/* Route type 3 field */
struct in_addr originator_ip;
/* Import and Export RTs. */
struct list *import_rtl;
struct list *export_rtl;
/* Route table for EVPN routes for this VNI. */
struct bgp_table *route_table;
QOBJ_FIELDS
};
DECLARE_QOBJ_TYPE(bgpevpn)
/* Mapping of Import RT to VNIs.
* The Import RTs of all VNIs are maintained in a hash table with each
* RT linking to all VNIs that will import routes matching this RT.
*/
struct irt_node
{
/* RT */
struct ecommunity_val rt;
/* List of VNIs importing routes matching this RT. */
struct list *vnis;
};
#define RT_TYPE_IMPORT 1
#define RT_TYPE_EXPORT 2
#define RT_TYPE_BOTH 3
static inline int
is_vni_configured (struct bgpevpn *vpn)
{
return (CHECK_FLAG (vpn->flags, VNI_FLAG_CFGD));
}
static inline int
is_vni_live (struct bgpevpn *vpn)
{
return (CHECK_FLAG (vpn->flags, VNI_FLAG_LIVE));
}
static inline int
is_rd_configured (struct bgpevpn *vpn)
{
return (CHECK_FLAG (vpn->flags, VNI_FLAG_RD_CFGD));
}
static inline int
bgp_evpn_rd_matches_existing (struct bgpevpn *vpn, struct prefix_rd *prd)
{
return(memcmp (&vpn->prd.val, prd->val, ECOMMUNITY_SIZE) == 0);
}
static inline int
is_import_rt_configured (struct bgpevpn *vpn)
{
return (CHECK_FLAG (vpn->flags, VNI_FLAG_IMPRT_CFGD));
}
static inline int
is_export_rt_configured (struct bgpevpn *vpn)
{
return (CHECK_FLAG (vpn->flags, VNI_FLAG_EXPRT_CFGD));
}
static inline int
is_vni_param_configured (struct bgpevpn *vpn)
{
return (is_rd_configured (vpn) ||
is_import_rt_configured (vpn) ||
is_export_rt_configured (vpn));
}
static inline void
vni2label (vni_t vni, mpls_label_t *label)
{
u_char *tag = (u_char *) label;
tag[0] = (vni >> 16) & 0xFF;
tag[1] = (vni >> 8) & 0xFF;
tag[2] = vni & 0xFF;
}
static inline vni_t
label2vni (mpls_label_t *label)
{
u_char *tag = (u_char *) label;
vni_t vni;
vni = ((u_int32_t) *tag++ << 16);
vni |= (u_int32_t) *tag++ << 8;
vni |= (u_int32_t) (*tag & 0xFF);
return vni;
}
static inline void
encode_mac_mobility_extcomm (int static_mac, u_int32_t seq,
struct ecommunity_val *eval)
{
memset (eval, 0, sizeof (*eval));
eval->val[0] = ECOMMUNITY_ENCODE_EVPN;
eval->val[1] = ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY;
if (static_mac)
eval->val[2] = ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY_FLAG_STICKY;
eval->val[4] = (seq >> 24) & 0xff;
eval->val[5] = (seq >> 16) & 0xff;
eval->val[6] = (seq >> 8) & 0xff;
eval->val[7] = seq & 0xff;
}
static inline void
build_evpn_type2_prefix (struct prefix_evpn *p, struct ethaddr *mac,
struct ipaddr *ip)
{
memset (p, 0, sizeof (struct prefix_evpn));
p->family = AF_ETHERNET;
p->prefixlen = EVPN_TYPE_2_ROUTE_PREFIXLEN;
p->prefix.route_type = BGP_EVPN_MAC_IP_ROUTE;
memcpy(&p->prefix.mac.octet, mac->octet, ETHER_ADDR_LEN);
p->prefix.ip.ipa_type = IPADDR_NONE;
if (ip)
memcpy(&p->prefix.ip, ip, sizeof (*ip));
}
static inline void
build_evpn_type3_prefix (struct prefix_evpn *p, struct in_addr originator_ip)
{
memset (p, 0, sizeof (struct prefix_evpn));
p->family = AF_ETHERNET;
p->prefixlen = EVPN_TYPE_3_ROUTE_PREFIXLEN;
p->prefix.route_type = BGP_EVPN_IMET_ROUTE;
p->prefix.ip.ipa_type = IPADDR_V4;
p->prefix.ip.ipaddr_v4 = originator_ip;
}
extern int
bgp_evpn_handle_export_rt_change (struct bgp *bgp, struct bgpevpn *vpn);
extern void
bgp_evpn_handle_rd_change (struct bgp *bgp, struct bgpevpn *vpn, int withdraw);
extern int
bgp_evpn_install_routes (struct bgp *bgp, struct bgpevpn *vpn);
extern int
bgp_evpn_uninstall_routes (struct bgp *bgp, struct bgpevpn *vpn);
extern void
bgp_evpn_map_vni_to_its_rts (struct bgp *bgp, struct bgpevpn *vpn);
extern void
bgp_evpn_unmap_vni_from_its_rts (struct bgp *bgp, struct bgpevpn *vpn);
extern void
bgp_evpn_derive_auto_rt_import (struct bgp *bgp, struct bgpevpn *vpn);
extern void
bgp_evpn_derive_auto_rt_export (struct bgp *bgp, struct bgpevpn *vpn);
extern void
bgp_evpn_derive_auto_rd (struct bgp *bgp, struct bgpevpn *vpn);
extern struct bgpevpn *
bgp_evpn_lookup_vni (struct bgp *bgp, vni_t vni);
extern struct bgpevpn *
bgp_evpn_new (struct bgp *bgp, vni_t vni, struct in_addr originator_ip);
extern void
bgp_evpn_free (struct bgp *bgp, struct bgpevpn *vpn);
#endif /* _BGP_EVPN_PRIVATE_H */

File diff suppressed because it is too large Load Diff

View File

@ -21,6 +21,9 @@
#ifndef _FRR_BGP_EVPN_VTY_H
#define _FRR_BGP_EVPN_VTY_H
extern void
bgp_config_write_evpn_info (struct vty *vty, struct bgp *bgp, afi_t afi,
safi_t safi, int *write);
extern void bgp_ethernetvpn_init(void);
#define L2VPN_HELP_STR "Layer 2 Virtual Private Network\n"

View File

@ -151,12 +151,10 @@ bgp_reg_dereg_for_label (struct bgp_node *rn, struct bgp_info *ri,
assert (ri);
if (ri->attr->flag & ATTR_FLAG_BIT (BGP_ATTR_PREFIX_SID))
{
assert (ri->attr->extra);
if (ri->attr->extra->label_index != BGP_INVALID_LABEL_INDEX)
if (ri->attr->label_index != BGP_INVALID_LABEL_INDEX)
{
flags |= ZEBRA_FEC_REGISTER_LABEL_INDEX;
stream_putl (s, ri->attr->extra->label_index);
stream_putl (s, ri->attr->label_index);
}
}
SET_FLAG (rn->flags, BGP_NODE_REGISTERED_FOR_LABEL);

View File

@ -41,6 +41,9 @@ extern int bgp_nlri_parse_label (struct peer *peer, struct attr *attr,
static inline int
bgp_labeled_safi (safi_t safi)
{
/* NOTE: This API really says a label (tag) MAY be present. Not all EVPN
* routes will have a label.
*/
if ((safi == SAFI_LABELED_UNICAST) || (safi == SAFI_MPLS_VPN) ||
(safi == SAFI_EVPN))
return 1;

View File

@ -43,7 +43,6 @@ DEFINE_MTYPE(BGPD, BGP_UPDGRP, "BGP update group")
DEFINE_MTYPE(BGPD, BGP_UPD_SUBGRP, "BGP update subgroup")
DEFINE_MTYPE(BGPD, BGP_PACKET, "BGP packet")
DEFINE_MTYPE(BGPD, ATTR, "BGP attribute")
DEFINE_MTYPE(BGPD, ATTR_EXTRA, "BGP extra attributes")
DEFINE_MTYPE(BGPD, AS_PATH, "BGP aspath")
DEFINE_MTYPE(BGPD, AS_SEG, "BGP aspath seg")
DEFINE_MTYPE(BGPD, AS_SEG_DATA, "BGP aspath segment data")
@ -114,3 +113,7 @@ DEFINE_MTYPE(BGPD, BGP_TEA_OPTIONS_VALUE, "BGP TEA Options Value")
DEFINE_MTYPE(BGPD, LCOMMUNITY, "Large Community")
DEFINE_MTYPE(BGPD, LCOMMUNITY_STR, "Large Community display string")
DEFINE_MTYPE(BGPD, LCOMMUNITY_VAL, "Large Community value")
DEFINE_MTYPE(BGPD, BGP_EVPN, "BGP EVPN Information")
DEFINE_MTYPE(BGPD, BGP_EVPN_IMPORT_RT, "BGP EVPN Import RT")
DEFINE_MTYPE(BGPD, BGP_EVPN_MACIP, "BGP EVPN MAC IP")

View File

@ -39,7 +39,6 @@ DECLARE_MTYPE(BGP_UPDGRP)
DECLARE_MTYPE(BGP_UPD_SUBGRP)
DECLARE_MTYPE(BGP_PACKET)
DECLARE_MTYPE(ATTR)
DECLARE_MTYPE(ATTR_EXTRA)
DECLARE_MTYPE(AS_PATH)
DECLARE_MTYPE(AS_SEG)
DECLARE_MTYPE(AS_SEG_DATA)
@ -110,4 +109,8 @@ DECLARE_MTYPE(BGP_TEA_OPTIONS_VALUE)
DECLARE_MTYPE(LCOMMUNITY)
DECLARE_MTYPE(LCOMMUNITY_STR)
DECLARE_MTYPE(LCOMMUNITY_VAL)
DECLARE_MTYPE(BGP_EVPN)
DECLARE_MTYPE(BGP_EVPN_IMPORT_RT)
DECLARE_MTYPE(BGP_EVPN_MACIP)
#endif /* _QUAGGA_BGP_MEMORY_H */

View File

@ -106,35 +106,31 @@ bgp_maximum_paths_unset (struct bgp *bgp, afi_t afi, safi_t safi,
int
bgp_info_nexthop_cmp (struct bgp_info *bi1, struct bgp_info *bi2)
{
struct attr_extra *ae1, *ae2;
int compare;
ae1 = bi1->attr->extra;
ae2 = bi2->attr->extra;
compare = IPV4_ADDR_CMP (&bi1->attr->nexthop, &bi2->attr->nexthop);
if (!compare && ae1 && ae2)
if (!compare)
{
if (ae1->mp_nexthop_len == ae2->mp_nexthop_len)
if (bi1->attr->mp_nexthop_len == bi2->attr->mp_nexthop_len)
{
switch (ae1->mp_nexthop_len)
switch (bi1->attr->mp_nexthop_len)
{
case BGP_ATTR_NHLEN_IPV4:
case BGP_ATTR_NHLEN_VPNV4:
compare = IPV4_ADDR_CMP (&ae1->mp_nexthop_global_in,
&ae2->mp_nexthop_global_in);
compare = IPV4_ADDR_CMP (&bi1->attr->mp_nexthop_global_in,
&bi2->attr->mp_nexthop_global_in);
break;
case BGP_ATTR_NHLEN_IPV6_GLOBAL:
case BGP_ATTR_NHLEN_VPNV6_GLOBAL:
compare = IPV6_ADDR_CMP (&ae1->mp_nexthop_global,
&ae2->mp_nexthop_global);
compare = IPV6_ADDR_CMP (&bi1->attr->mp_nexthop_global,
&bi2->attr->mp_nexthop_global);
break;
case BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL:
compare = IPV6_ADDR_CMP (&ae1->mp_nexthop_global,
&ae2->mp_nexthop_global);
compare = IPV6_ADDR_CMP (&bi1->attr->mp_nexthop_global,
&bi2->attr->mp_nexthop_global);
if (!compare)
compare = IPV6_ADDR_CMP (&ae1->mp_nexthop_local,
&ae2->mp_nexthop_local);
compare = IPV6_ADDR_CMP (&bi1->attr->mp_nexthop_local,
&bi2->attr->mp_nexthop_local);
break;
}
}
@ -142,14 +138,14 @@ bgp_info_nexthop_cmp (struct bgp_info *bi1, struct bgp_info *bi2)
/* This can happen if one IPv6 peer sends you global and link-local
* nexthops but another IPv6 peer only sends you global
*/
else if (ae1->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL ||
ae1->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL)
else if (bi1->attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL ||
bi1->attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL)
{
compare = IPV6_ADDR_CMP (&ae1->mp_nexthop_global,
&ae2->mp_nexthop_global);
compare = IPV6_ADDR_CMP (&bi1->attr->mp_nexthop_global,
&bi2->attr->mp_nexthop_global);
if (!compare)
{
if (ae1->mp_nexthop_len < ae2->mp_nexthop_len)
if (bi1->attr->mp_nexthop_len < bi2->attr->mp_nexthop_len)
compare = -1;
else
compare = 1;
@ -663,7 +659,6 @@ bgp_info_mpath_aggregate_update (struct bgp_info *new_best,
struct community *community, *commerge;
struct ecommunity *ecomm, *ecommerge;
struct lcommunity *lcomm, *lcommerge;
struct attr_extra *ae;
struct attr attr = { 0 };
if (old_best && (old_best != new_best) &&
@ -697,9 +692,8 @@ bgp_info_mpath_aggregate_update (struct bgp_info *new_best,
aspath = aspath_dup (attr.aspath);
origin = attr.origin;
community = attr.community ? community_dup (attr.community) : NULL;
ae = attr.extra;
ecomm = (ae && ae->ecommunity) ? ecommunity_dup (ae->ecommunity) : NULL;
lcomm = (ae && ae->lcommunity) ? lcommunity_dup (ae->lcommunity) : NULL;
ecomm = (attr.ecommunity) ? ecommunity_dup (attr.ecommunity) : NULL;
lcomm = (attr.lcommunity) ? lcommunity_dup (attr.lcommunity) : NULL;
for (mpinfo = bgp_info_mpath_first (new_best); mpinfo;
mpinfo = bgp_info_mpath_next (mpinfo))
@ -723,28 +717,27 @@ bgp_info_mpath_aggregate_update (struct bgp_info *new_best,
community = community_dup (mpinfo->attr->community);
}
ae = mpinfo->attr->extra;
if (ae && ae->ecommunity)
if (mpinfo->attr->ecommunity)
{
if (ecomm)
{
ecommerge = ecommunity_merge (ecomm, ae->ecommunity);
ecommerge = ecommunity_merge (ecomm, mpinfo->attr->ecommunity);
ecomm = ecommunity_uniq_sort (ecommerge);
ecommunity_free (&ecommerge);
}
else
ecomm = ecommunity_dup (ae->ecommunity);
ecomm = ecommunity_dup (mpinfo->attr->ecommunity);
}
if (ae && ae->lcommunity)
if (mpinfo->attr->lcommunity)
{
if (lcomm)
{
lcommerge = lcommunity_merge (lcomm, ae->lcommunity);
lcommerge = lcommunity_merge (lcomm, mpinfo->attr->lcommunity);
lcomm = lcommunity_uniq_sort (lcommerge);
lcommunity_free (&lcommerge);
}
else
lcomm = lcommunity_dup (ae->lcommunity);
lcomm = lcommunity_dup (mpinfo->attr->lcommunity);
}
}
@ -757,21 +750,18 @@ bgp_info_mpath_aggregate_update (struct bgp_info *new_best,
}
if (ecomm)
{
ae = bgp_attr_extra_get (&attr);
ae->ecommunity = ecomm;
attr.ecommunity = ecomm;
attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES);
}
/* Zap multipath attr nexthop so we set nexthop to self */
attr.nexthop.s_addr = 0;
if (attr.extra)
memset (&attr.extra->mp_nexthop_global, 0, sizeof (struct in6_addr));
memset (&attr.mp_nexthop_global, 0, sizeof (struct in6_addr));
/* TODO: should we set ATOMIC_AGGREGATE and AGGREGATOR? */
}
new_attr = bgp_attr_intern (&attr);
bgp_attr_extra_free (&attr);
if (new_attr != bgp_info_mpath_attr (new_best))
{

View File

@ -62,31 +62,6 @@ argv_find_and_parse_vpnvx(struct cmd_token **argv, int argc, int *index, afi_t *
return ret;
}
u_int16_t
decode_rd_type (u_char *pnt)
{
u_int16_t v;
v = ((u_int16_t) *pnt++ << 8);
#if ENABLE_BGP_VNC
/*
* VNC L2 stores LHI in lower byte, so omit it
*/
if (v != RD_TYPE_VNC_ETH)
v |= (u_int16_t) *pnt;
#else /* duplicate code for clarity */
v |= (u_int16_t) *pnt;
#endif
return v;
}
void
encode_rd_type (u_int16_t v, u_char *pnt)
{
*((u_int16_t *)pnt) = htons(v);
}
u_int32_t
decode_label (mpls_label_t *label_pnt)
{
@ -111,54 +86,6 @@ encode_label(mpls_label_t label,
*pnt++ = ((label<<4)+1) & 0xff; /* S=1 */
}
/* type == RD_TYPE_AS */
void
decode_rd_as (u_char *pnt, struct rd_as *rd_as)
{
rd_as->as = (u_int16_t) *pnt++ << 8;
rd_as->as |= (u_int16_t) *pnt++;
rd_as->val = ((u_int32_t) *pnt++ << 24);
rd_as->val |= ((u_int32_t) *pnt++ << 16);
rd_as->val |= ((u_int32_t) *pnt++ << 8);
rd_as->val |= (u_int32_t) *pnt;
}
/* type == RD_TYPE_AS4 */
void
decode_rd_as4 (u_char *pnt, struct rd_as *rd_as)
{
rd_as->as = (u_int32_t) *pnt++ << 24;
rd_as->as |= (u_int32_t) *pnt++ << 16;
rd_as->as |= (u_int32_t) *pnt++ << 8;
rd_as->as |= (u_int32_t) *pnt++;
rd_as->val = ((u_int16_t) *pnt++ << 8);
rd_as->val |= (u_int16_t) *pnt;
}
/* type == RD_TYPE_IP */
void
decode_rd_ip (u_char *pnt, struct rd_ip *rd_ip)
{
memcpy (&rd_ip->ip, pnt, 4);
pnt += 4;
rd_ip->val = ((u_int16_t) *pnt++ << 8);
rd_ip->val |= (u_int16_t) *pnt;
}
#if ENABLE_BGP_VNC
/* type == RD_TYPE_VNC_ETH */
void
decode_rd_vnc_eth (u_char *pnt, struct rd_vnc_eth *rd_vnc_eth)
{
rd_vnc_eth->type = RD_TYPE_VNC_ETH;
rd_vnc_eth->local_nve_id = pnt[1];
memcpy (rd_vnc_eth->macaddr.octet, pnt + 2, ETHER_ADDR_LEN);
}
#endif
int
bgp_nlri_parse_vpn (struct peer *peer, struct attr *attr,
struct bgp_nlri *packet)
@ -313,129 +240,6 @@ bgp_nlri_parse_vpn (struct peer *peer, struct attr *attr,
#undef VPN_PREFIXLEN_MIN_BYTES
}
int
str2prefix_rd (const char *str, struct prefix_rd *prd)
{
int ret; /* ret of called functions */
int lret; /* local ret, of this func */
char *p;
char *p2;
struct stream *s = NULL;
char *half = NULL;
struct in_addr addr;
s = stream_new (8);
prd->family = AF_UNSPEC;
prd->prefixlen = 64;
lret = 0;
p = strchr (str, ':');
if (! p)
goto out;
if (! all_digit (p + 1))
goto out;
half = XMALLOC (MTYPE_TMP, (p - str) + 1);
memcpy (half, str, (p - str));
half[p - str] = '\0';
p2 = strchr (str, '.');
if (! p2)
{
unsigned long as_val;
if (! all_digit (half))
goto out;
as_val = atol(half);
if (as_val > 0xffff)
{
stream_putw (s, RD_TYPE_AS4);
stream_putl (s, as_val);
stream_putw (s, atol (p + 1));
}
else
{
stream_putw (s, RD_TYPE_AS);
stream_putw (s, as_val);
stream_putl (s, atol (p + 1));
}
}
else
{
ret = inet_aton (half, &addr);
if (! ret)
goto out;
stream_putw (s, RD_TYPE_IP);
stream_put_in_addr (s, &addr);
stream_putw (s, atol (p + 1));
}
memcpy (prd->val, s->data, 8);
lret = 1;
out:
if (s)
stream_free (s);
if (half)
XFREE(MTYPE_TMP, half);
return lret;
}
char *
prefix_rd2str (struct prefix_rd *prd, char *buf, size_t size)
{
u_char *pnt;
u_int16_t type;
struct rd_as rd_as;
struct rd_ip rd_ip;
if (size < RD_ADDRSTRLEN)
return NULL;
pnt = prd->val;
type = decode_rd_type (pnt);
if (type == RD_TYPE_AS)
{
decode_rd_as (pnt + 2, &rd_as);
snprintf (buf, size, "%u:%d", rd_as.as, rd_as.val);
return buf;
}
else if (type == RD_TYPE_AS4)
{
decode_rd_as4 (pnt + 2, &rd_as);
snprintf (buf, size, "%u:%d", rd_as.as, rd_as.val);
return buf;
}
else if (type == RD_TYPE_IP)
{
decode_rd_ip (pnt + 2, &rd_ip);
snprintf (buf, size, "%s:%d", inet_ntoa (rd_ip.ip), rd_ip.val);
return buf;
}
#if ENABLE_BGP_VNC
else if (type == RD_TYPE_VNC_ETH)
{
snprintf(buf, size, "LHI:%d, %02x:%02x:%02x:%02x:%02x:%02x",
*(pnt+1), /* LHI */
*(pnt+2), /* MAC[0] */
*(pnt+3),
*(pnt+4),
*(pnt+5),
*(pnt+6),
*(pnt+7));
return buf;
}
#endif
return NULL;
}
/* For testing purpose, static route of MPLS-VPN. */
DEFUN (vpnv4_network,
vpnv4_network_cmd,

View File

@ -1,7 +1,7 @@
/* MPLS-VPN
* Copyright (C) 2000 Kunihiro Ishiguro <kunihiro@zebra.org>
*
* This file is part of GNU Zebra.
* This file is part of GxNU Zebra.
*
* GNU Zebra is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@ -22,15 +22,7 @@
#define _QUAGGA_BGP_MPLSVPN_H
#include "bgpd/bgp_route.h"
#define RD_TYPE_AS 0
#define RD_TYPE_IP 1
#define RD_TYPE_AS4 2
#if ENABLE_BGP_VNC
#define RD_TYPE_VNC_ETH 0xff00 /* VNC L2VPN */
#endif
#define RD_ADDRSTRLEN 28
#include "bgpd/bgp_rd.h"
#ifdef MPLS_LABEL_MAX
# undef MPLS_LABEL_MAX
@ -74,44 +66,10 @@ typedef enum {
#define V4_HEADER_OVERLAY \
" Network Next Hop EthTag Overlay Index RouterMac\n"
struct rd_as
{
u_int16_t type;
as_t as;
u_int32_t val;
};
struct rd_ip
{
u_int16_t type;
struct in_addr ip;
u_int16_t val;
};
#if ENABLE_BGP_VNC
struct rd_vnc_eth
{
u_int16_t type;
uint8_t local_nve_id;
struct ethaddr macaddr;
};
#endif
extern u_int16_t decode_rd_type (u_char *);
extern void encode_rd_type (u_int16_t, u_char *);
extern void bgp_mplsvpn_init (void);
extern int bgp_nlri_parse_vpn (struct peer *, struct attr *, struct bgp_nlri *);
extern u_int32_t decode_label (mpls_label_t *);
extern void encode_label(mpls_label_t, mpls_label_t *);
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_rd_vnc_eth (u_char *pnt, struct rd_vnc_eth *rd_vnc_eth);
#endif
extern int str2prefix_rd (const char *, struct prefix_rd *);
extern char *prefix_rd2str (struct prefix_rd *, char *, size_t);
extern int
argv_find_and_parse_vpnvx(struct cmd_token **argv, int argc, int *index, afi_t *afi);

View File

@ -329,11 +329,11 @@ bgp_connected_delete (struct bgp *bgp, struct connected *ifc)
}
int
bgp_nexthop_self (struct bgp *bgp, struct attr *attr)
bgp_nexthop_self (struct bgp *bgp, struct in_addr nh_addr)
{
struct bgp_addr tmp, *addr;
tmp.addr = attr->nexthop;
tmp.addr = nh_addr;
addr = hash_lookup (bgp->address_hash, &tmp);
if (addr)

View File

@ -74,7 +74,7 @@ extern void bgp_connected_add (struct bgp *bgp, struct connected *c);
extern void bgp_connected_delete (struct bgp *bgp, struct connected *c);
extern int bgp_multiaccess_check_v4 (struct in_addr, struct peer *);
extern int bgp_config_write_scan_time (struct vty *);
extern int bgp_nexthop_self (struct bgp *, struct attr *);
extern int bgp_nexthop_self (struct bgp *, struct in_addr);
extern struct bgp_nexthop_cache *bnc_new(void);
extern void bnc_free(struct bgp_nexthop_cache *bnc);
extern void bnc_nexthop_free(struct bgp_nexthop_cache *bnc);

View File

@ -532,8 +532,8 @@ make_prefix (int afi, struct bgp_info *ri, struct prefix *p)
break;
case AFI_IP6:
/* We don't register link local NH */
if (ri->attr->extra->mp_nexthop_len != BGP_ATTR_NHLEN_IPV6_GLOBAL
|| IN6_IS_ADDR_LINKLOCAL (&ri->attr->extra->mp_nexthop_global))
if (ri->attr->mp_nexthop_len != BGP_ATTR_NHLEN_IPV6_GLOBAL
|| IN6_IS_ADDR_LINKLOCAL (&ri->attr->mp_nexthop_global))
return -1;
p->family = AF_INET6;
@ -545,7 +545,7 @@ make_prefix (int afi, struct bgp_info *ri, struct prefix *p)
}
else
{
p->u.prefix6 = ri->attr->extra->mp_nexthop_global;
p->u.prefix6 = ri->attr->mp_nexthop_global;
p->prefixlen = IPV6_MAX_BITLEN;
}
break;

View File

@ -1364,7 +1364,6 @@ bgp_update_receive (struct peer *peer, bgp_size_t size)
u_char *end;
struct stream *s;
struct attr attr;
struct attr_extra extra;
bgp_size_t attribute_len;
bgp_size_t update_len;
bgp_size_t withdraw_len;
@ -1389,11 +1388,9 @@ bgp_update_receive (struct peer *peer, bgp_size_t size)
/* Set initial values. */
memset (&attr, 0, sizeof (struct attr));
memset (&extra, 0, sizeof (struct attr_extra));
extra.label_index = BGP_INVALID_LABEL_INDEX;
extra.label = MPLS_INVALID_LABEL;
attr.label_index = BGP_INVALID_LABEL_INDEX;
attr.label = MPLS_INVALID_LABEL;
memset (&nlris, 0, sizeof (nlris));
attr.extra = &extra;
memset (peer->rcvd_attr_str, 0, BUFSIZ);
peer->rcvd_attr_printed = 0;

232
bgpd/bgp_rd.c Normal file
View File

@ -0,0 +1,232 @@
/* BGP RD definitions for BGP-based VPNs (IP/EVPN)
* -- brought over from bgpd/bgp_mplsvpn.c
* Copyright (C) 2000 Kunihiro Ishiguro <kunihiro@zebra.org>
*
* This file is part of FRR.
*
* FRR 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.
*
* FRR 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 FRR; 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 "log.h"
#include "prefix.h"
#include "memory.h"
#include "stream.h"
#include "filter.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_rd.h"
#include "bgpd/bgp_attr.h"
#if ENABLE_BGP_VNC
#include "bgpd/rfapi/rfapi_backend.h"
#endif
u_int16_t
decode_rd_type (u_char *pnt)
{
u_int16_t v;
v = ((u_int16_t) *pnt++ << 8);
#if ENABLE_BGP_VNC
/*
* VNC L2 stores LHI in lower byte, so omit it
*/
if (v != RD_TYPE_VNC_ETH)
v |= (u_int16_t) *pnt;
#else /* duplicate code for clarity */
v |= (u_int16_t) *pnt;
#endif
return v;
}
void
encode_rd_type (u_int16_t v, u_char *pnt)
{
*((u_int16_t *)pnt) = htons(v);
}
/* type == RD_TYPE_AS */
void
decode_rd_as (u_char *pnt, struct rd_as *rd_as)
{
rd_as->as = (u_int16_t) *pnt++ << 8;
rd_as->as |= (u_int16_t) *pnt++;
rd_as->val = ((u_int32_t) *pnt++ << 24);
rd_as->val |= ((u_int32_t) *pnt++ << 16);
rd_as->val |= ((u_int32_t) *pnt++ << 8);
rd_as->val |= (u_int32_t) *pnt;
}
/* type == RD_TYPE_AS4 */
void
decode_rd_as4 (u_char *pnt, struct rd_as *rd_as)
{
rd_as->as = (u_int32_t) *pnt++ << 24;
rd_as->as |= (u_int32_t) *pnt++ << 16;
rd_as->as |= (u_int32_t) *pnt++ << 8;
rd_as->as |= (u_int32_t) *pnt++;
rd_as->val = ((u_int16_t) *pnt++ << 8);
rd_as->val |= (u_int16_t) *pnt;
}
/* type == RD_TYPE_IP */
void
decode_rd_ip (u_char *pnt, struct rd_ip *rd_ip)
{
memcpy (&rd_ip->ip, pnt, 4);
pnt += 4;
rd_ip->val = ((u_int16_t) *pnt++ << 8);
rd_ip->val |= (u_int16_t) *pnt;
}
#if ENABLE_BGP_VNC
/* type == RD_TYPE_VNC_ETH */
void
decode_rd_vnc_eth (u_char *pnt, struct rd_vnc_eth *rd_vnc_eth)
{
rd_vnc_eth->type = RD_TYPE_VNC_ETH;
rd_vnc_eth->local_nve_id = pnt[1];
memcpy (rd_vnc_eth->macaddr.octet, pnt + 2, ETHER_ADDR_LEN);
}
#endif
int
str2prefix_rd (const char *str, struct prefix_rd *prd)
{
int ret; /* ret of called functions */
int lret; /* local ret, of this func */
char *p;
char *p2;
struct stream *s = NULL;
char *half = NULL;
struct in_addr addr;
s = stream_new (8);
prd->family = AF_UNSPEC;
prd->prefixlen = 64;
lret = 0;
p = strchr (str, ':');
if (! p)
goto out;
if (! all_digit (p + 1))
goto out;
half = XMALLOC (MTYPE_TMP, (p - str) + 1);
memcpy (half, str, (p - str));
half[p - str] = '\0';
p2 = strchr (str, '.');
if (! p2)
{
unsigned long as_val;
if (! all_digit (half))
goto out;
as_val = atol(half);
if (as_val > 0xffff)
{
stream_putw (s, RD_TYPE_AS4);
stream_putl (s, as_val);
stream_putw (s, atol (p + 1));
}
else
{
stream_putw (s, RD_TYPE_AS);
stream_putw (s, as_val);
stream_putl (s, atol (p + 1));
}
}
else
{
ret = inet_aton (half, &addr);
if (! ret)
goto out;
stream_putw (s, RD_TYPE_IP);
stream_put_in_addr (s, &addr);
stream_putw (s, atol (p + 1));
}
memcpy (prd->val, s->data, 8);
lret = 1;
out:
if (s)
stream_free (s);
if (half)
XFREE(MTYPE_TMP, half);
return lret;
}
char *
prefix_rd2str (struct prefix_rd *prd, char *buf, size_t size)
{
u_char *pnt;
u_int16_t type;
struct rd_as rd_as;
struct rd_ip rd_ip;
if (size < RD_ADDRSTRLEN)
return NULL;
pnt = prd->val;
type = decode_rd_type (pnt);
if (type == RD_TYPE_AS)
{
decode_rd_as (pnt + 2, &rd_as);
snprintf (buf, size, "%u:%d", rd_as.as, rd_as.val);
return buf;
}
else if (type == RD_TYPE_AS4)
{
decode_rd_as4 (pnt + 2, &rd_as);
snprintf (buf, size, "%u:%d", rd_as.as, rd_as.val);
return buf;
}
else if (type == RD_TYPE_IP)
{
decode_rd_ip (pnt + 2, &rd_ip);
snprintf (buf, size, "%s:%d", inet_ntoa (rd_ip.ip), rd_ip.val);
return buf;
}
#if ENABLE_BGP_VNC
else if (type == RD_TYPE_VNC_ETH)
{
snprintf(buf, size, "LHI:%d, %02x:%02x:%02x:%02x:%02x:%02x",
*(pnt+1), /* LHI */
*(pnt+2), /* MAC[0] */
*(pnt+3),
*(pnt+4),
*(pnt+5),
*(pnt+6),
*(pnt+7));
return buf;
}
#endif
return NULL;
}

74
bgpd/bgp_rd.h Normal file
View File

@ -0,0 +1,74 @@
/* BGP RD definitions for BGP-based VPNs (IP/EVPN)
* -- brought over from bgpd/bgp_mplsvpn.h
* Copyright (C) 2000 Kunihiro Ishiguro <kunihiro@zebra.org>
*
* This file is part of FRR.
*
* FRR 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.
*
* FRR 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 FRR; 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_RD_H
#define _QUAGGA_BGP_RD_H
/* RD types */
#define RD_TYPE_AS 0
#define RD_TYPE_IP 1
#define RD_TYPE_AS4 2
#if ENABLE_BGP_VNC
#define RD_TYPE_VNC_ETH 0xff00 /* VNC L2VPN */
#endif
#define RD_ADDRSTRLEN 28
struct rd_as
{
u_int16_t type;
as_t as;
u_int32_t val;
};
struct rd_ip
{
u_int16_t type;
struct in_addr ip;
u_int16_t val;
};
#if ENABLE_BGP_VNC
struct rd_vnc_eth
{
u_int16_t type;
uint8_t local_nve_id;
struct ethaddr macaddr;
};
#endif
extern u_int16_t decode_rd_type (u_char *pnt);
extern void encode_rd_type (u_int16_t, u_char *);
extern void decode_rd_as (u_char *pnt, struct rd_as *rd_as);
extern void decode_rd_as4 (u_char *pnt, struct rd_as *rd_as);
extern void decode_rd_ip (u_char *pnt, struct rd_ip *rd_ip);
#if ENABLE_BGP_VNC
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 char *prefix_rd2str (struct prefix_rd *, char *, size_t);
#endif /* _QUAGGA_BGP_RD_H */

File diff suppressed because it is too large Load Diff

View File

@ -99,6 +99,9 @@ struct bgp_info_extra
} vnc;
#endif
/* For imported routes into a VNI (or VRF), this points to the parent. */
void *parent;
};
struct bgp_info
@ -174,6 +177,13 @@ struct bgp_info
};
/* Structure used in BGP path selection */
struct bgp_info_pair
{
struct bgp_info *old;
struct bgp_info *new;
};
/* BGP static route configuration. */
struct bgp_static
{
@ -222,8 +232,8 @@ struct bgp_static
#define BGP_ATTR_NEXTHOP_AFI_IP6(attr) \
(! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP)) && \
(attr)->extra && ((attr)->extra->mp_nexthop_len == 16 || \
(attr)->extra->mp_nexthop_len == 32))
((attr)->mp_nexthop_len == 16 || \
(attr)->mp_nexthop_len == 32))
#define BGP_INFO_COUNTABLE(BI) \
(! CHECK_FLAG ((BI)->flags, BGP_INFO_HISTORY) \
&& ! CHECK_FLAG ((BI)->flags, BGP_INFO_REMOVED))
@ -309,6 +319,7 @@ extern struct bgp_node *bgp_afi_node_get (struct bgp_table *table, afi_t afi,
extern struct bgp_info *bgp_info_lock (struct bgp_info *);
extern struct bgp_info *bgp_info_unlock (struct bgp_info *);
extern void bgp_info_add (struct bgp_node *rn, struct bgp_info *ri);
extern void bgp_info_reap (struct bgp_node *rn, struct bgp_info *ri);
extern void bgp_info_delete (struct bgp_node *rn, struct bgp_info *ri);
extern struct bgp_info_extra *bgp_info_extra_get (struct bgp_info *);
extern void bgp_info_set_flag (struct bgp_node *, struct bgp_info *, u_int32_t);
@ -372,6 +383,10 @@ extern u_char bgp_distance_apply (struct prefix *, struct bgp_info *, afi_t, saf
extern afi_t bgp_node_afi (struct vty *);
extern safi_t bgp_node_safi (struct vty *);
extern struct bgp_info *
info_make (int type, int sub_type, u_short instance, struct peer *peer,
struct attr *attr, struct bgp_node *rn);
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 *);
@ -396,10 +411,32 @@ extern void bgp_process_queues_drain_immediate (void);
extern struct bgp_node *
bgp_afi_node_get (struct bgp_table *, afi_t , safi_t , struct prefix *,
struct prefix_rd *);
extern struct bgp_node *
bgp_afi_node_lookup (struct bgp_table *table, afi_t afi, safi_t safi,
struct prefix *p, struct prefix_rd *prd);
extern struct bgp_info *bgp_info_new (void);
extern void bgp_info_restore (struct bgp_node *, struct bgp_info *);
extern int bgp_info_cmp_compatible (struct bgp *, struct bgp_info *,
struct bgp_info *, afi_t, safi_t );
extern int
bgp_info_cmp_compatible (struct bgp *, struct bgp_info *, struct bgp_info *,
char *pfx_buf, afi_t afi, safi_t safi);
extern void
bgp_best_selection (struct bgp *bgp, struct bgp_node *rn,
struct bgp_maxpaths_cfg *mpath_cfg,
struct bgp_info_pair *result,
afi_t afi, safi_t safi);
extern void bgp_zebra_clear_route_change_flags (struct bgp_node *rn);
extern int
bgp_zebra_has_route_changed (struct bgp_node *rn, struct bgp_info *selected);
extern void
route_vty_out_detail_header (struct vty *vty, struct bgp *bgp,
struct bgp_node *rn,
struct prefix_rd *prd, afi_t afi, safi_t safi,
json_object *json);
extern void
route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p,
struct bgp_info *binfo, afi_t afi, safi_t safi,
json_object *json_paths);
#endif /* _QUAGGA_BGP_ROUTE_H */

View File

@ -868,8 +868,7 @@ route_match_lcommunity (void *rule, struct prefix *prefix,
if (! list)
return RMAP_NOMATCH;
if (bgp_info->attr->extra &&
lcommunity_list_match (bgp_info->attr->extra->lcommunity, list))
if (lcommunity_list_match (bgp_info->attr->lcommunity, list))
return RMAP_MATCH;
}
@ -933,15 +932,12 @@ route_match_ecommunity (void *rule, struct prefix *prefix,
{
bgp_info = object;
if (!bgp_info->attr->extra)
return RMAP_NOMATCH;
list = community_list_lookup (bgp_clist, (char *) rule,
EXTCOMMUNITY_LIST_MASTER);
if (! list)
return RMAP_NOMATCH;
if (ecommunity_list_match (bgp_info->attr->extra->ecommunity, list))
if (ecommunity_list_match (bgp_info->attr->ecommunity, list))
return RMAP_MATCH;
}
return RMAP_NOMATCH;
@ -1149,10 +1145,7 @@ route_match_tag (void *rule, struct prefix *prefix,
tag = rule;
bgp_info = object;
if (!bgp_info->attr->extra)
return RMAP_NOMATCH;
return ((bgp_info->attr->extra->tag == *tag)? RMAP_MATCH : RMAP_NOMATCH);
return ((bgp_info->attr->tag == *tag)? RMAP_MATCH : RMAP_NOMATCH);
}
return RMAP_NOMATCH;
@ -1332,7 +1325,6 @@ route_set_weight (void *rule, struct prefix *prefix, route_map_object_t type,
{
struct rmap_value *rv;
struct bgp_info *bgp_info;
u_int32_t weight;
if (type == RMAP_BGP)
{
@ -1341,11 +1333,7 @@ route_set_weight (void *rule, struct prefix *prefix, route_map_object_t type,
bgp_info = object;
/* Set weight value. */
weight = route_value_adjust(rv, 0, bgp_info->peer);
if (weight)
(bgp_attr_extra_get (bgp_info->attr))->weight = weight;
else if (bgp_info->attr->extra)
bgp_info->attr->extra->weight = 0;
bgp_info->attr->weight = route_value_adjust(rv, 0, bgp_info->peer);
}
return RMAP_OKAY;
@ -1644,14 +1632,13 @@ route_set_lcommunity (void *rule, struct prefix *prefix,
rcs = rule;
binfo = object;
attr = binfo->attr;
old = (attr->extra) ? attr->extra->lcommunity : NULL;
old = attr->lcommunity;
/* "none" case. */
if (rcs->none)
{
attr->flag &= ~(ATTR_FLAG_BIT (BGP_ATTR_LARGE_COMMUNITIES));
if (attr->extra)
attr->extra->lcommunity = NULL;
attr->lcommunity = NULL;
/* See the longer comment down below. */
if (old && old->refcnt == 0)
@ -1676,7 +1663,7 @@ route_set_lcommunity (void *rule, struct prefix *prefix,
new = lcommunity_dup (rcs->lcom);
/* will be intern()'d or attr_flush()'d by bgp_update_main() */
(bgp_attr_extra_get (attr))->lcommunity = new;
attr->lcommunity = new;
attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LARGE_COMMUNITIES);
}
@ -1766,7 +1753,7 @@ route_set_lcommunity_delete (void *rule, struct prefix *prefix,
binfo = object;
list = community_list_lookup (bgp_clist, rule,
LARGE_COMMUNITY_LIST_MASTER);
old = ((binfo->attr->extra) ? binfo->attr->extra->lcommunity : NULL);
old = binfo->attr->lcommunity;
if (list && old)
{
@ -1783,13 +1770,13 @@ route_set_lcommunity_delete (void *rule, struct prefix *prefix,
if (new->size == 0)
{
binfo->attr->extra->lcommunity = NULL;
binfo->attr->lcommunity = NULL;
binfo->attr->flag &= ~ATTR_FLAG_BIT (BGP_ATTR_LARGE_COMMUNITIES);
lcommunity_free (&new);
}
else
{
binfo->attr->extra->lcommunity = new;
binfo->attr->lcommunity = new;
binfo->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LARGE_COMMUNITIES);
}
}
@ -1946,7 +1933,7 @@ route_set_ecommunity (void *rule, struct prefix *prefix,
return RMAP_OKAY;
/* We assume additive for Extended Community. */
old_ecom = (bgp_attr_extra_get (bgp_info->attr))->ecommunity;
old_ecom = bgp_info->attr->ecommunity;
if (old_ecom)
{
@ -1961,7 +1948,7 @@ route_set_ecommunity (void *rule, struct prefix *prefix,
new_ecom = ecommunity_dup (ecom);
/* will be intern()'d or attr_flush()'d by bgp_update_main() */
bgp_info->attr->extra->ecommunity = new_ecom;
bgp_info->attr->ecommunity = new_ecom;
bgp_info->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES);
}
@ -2129,16 +2116,14 @@ route_set_aggregator_as (void *rule, struct prefix *prefix,
{
struct bgp_info *bgp_info;
struct aggregator *aggregator;
struct attr_extra *ae;
if (type == RMAP_BGP)
{
bgp_info = object;
aggregator = rule;
ae = bgp_attr_extra_get (bgp_info->attr);
ae->aggregator_as = aggregator->as;
ae->aggregator_addr = aggregator->address;
bgp_info->attr->aggregator_as = aggregator->as;
bgp_info->attr->aggregator_addr = aggregator->address;
bgp_info->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
}
@ -2187,16 +2172,14 @@ route_set_tag (void *rule, struct prefix *prefix,
{
route_tag_t *tag;
struct bgp_info *bgp_info;
struct attr_extra *ae;
if (type == RMAP_BGP)
{
tag = rule;
bgp_info = object;
ae = bgp_attr_extra_get (bgp_info->attr);
/* Set tag value */
ae->tag=*tag;
bgp_info->attr->tag=*tag;
}
@ -2231,7 +2214,7 @@ route_set_label_index (void *rule, struct prefix *prefix,
label_index = rv->value;
if (label_index)
{
(bgp_attr_extra_get (bgp_info->attr))->label_index = label_index;
bgp_info->attr->label_index = label_index;
bgp_info->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_PREFIX_SID);
}
}
@ -2302,14 +2285,11 @@ route_match_ipv6_next_hop (void *rule, struct prefix *prefix,
{
bgp_info = object;
if (!bgp_info->attr->extra)
return RMAP_NOMATCH;
if (IPV6_ADDR_SAME (&bgp_info->attr->extra->mp_nexthop_global, addr))
if (IPV6_ADDR_SAME (&bgp_info->attr->mp_nexthop_global, addr))
return RMAP_MATCH;
if (bgp_info->attr->extra->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL &&
IPV6_ADDR_SAME (&bgp_info->attr->extra->mp_nexthop_local, rule))
if (bgp_info->attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL &&
IPV6_ADDR_SAME (&bgp_info->attr->mp_nexthop_local, rule))
return RMAP_MATCH;
return RMAP_NOMATCH;
@ -2407,11 +2387,11 @@ route_set_ipv6_nexthop_global (void *rule, struct prefix *prefix,
bgp_info = object;
/* Set next hop value. */
(bgp_attr_extra_get (bgp_info->attr))->mp_nexthop_global = *address;
bgp_info->attr->mp_nexthop_global = *address;
/* Set nexthop length. */
if (bgp_info->attr->extra->mp_nexthop_len == 0)
bgp_info->attr->extra->mp_nexthop_len = BGP_ATTR_NHLEN_IPV6_GLOBAL;
if (bgp_info->attr->mp_nexthop_len == 0)
bgp_info->attr->mp_nexthop_len = BGP_ATTR_NHLEN_IPV6_GLOBAL;
SET_FLAG(bgp_info->attr->rmap_change_flags,
BATTR_RMAP_IPV6_GLOBAL_NHOP_CHANGED);
@ -2477,13 +2457,13 @@ route_set_ipv6_nexthop_prefer_global (void *rule, struct prefix *prefix,
&& sockunion_family (peer->su_remote) == AF_INET6)
{
/* Set next hop preference to global */
bgp_info->attr->extra->mp_nexthop_prefer_global = TRUE;
bgp_info->attr->mp_nexthop_prefer_global = TRUE;
SET_FLAG(bgp_info->attr->rmap_change_flags,
BATTR_RMAP_IPV6_PREFER_GLOBAL_CHANGED);
}
else
{
bgp_info->attr->extra->mp_nexthop_prefer_global = FALSE;
bgp_info->attr->mp_nexthop_prefer_global = FALSE;
SET_FLAG(bgp_info->attr->rmap_change_flags,
BATTR_RMAP_IPV6_PREFER_GLOBAL_CHANGED);
}
@ -2535,11 +2515,11 @@ route_set_ipv6_nexthop_local (void *rule, struct prefix *prefix,
bgp_info = object;
/* Set next hop value. */
(bgp_attr_extra_get (bgp_info->attr))->mp_nexthop_local = *address;
bgp_info->attr->mp_nexthop_local = *address;
/* Set nexthop length. */
if (bgp_info->attr->extra->mp_nexthop_len != BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL)
bgp_info->attr->extra->mp_nexthop_len = BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL;
if (bgp_info->attr->mp_nexthop_len != BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL)
bgp_info->attr->mp_nexthop_len = BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL;
SET_FLAG(bgp_info->attr->rmap_change_flags,
BATTR_RMAP_IPV6_LL_NHOP_CHANGED);
@ -2611,15 +2591,15 @@ route_set_ipv6_nexthop_peer (void *rule, struct prefix *prefix,
/* Set next hop value and length in attribute. */
if (IN6_IS_ADDR_LINKLOCAL(&peer_address))
{
(bgp_attr_extra_get (bgp_info->attr))->mp_nexthop_local = peer_address;
if (bgp_info->attr->extra->mp_nexthop_len != 32)
bgp_info->attr->extra->mp_nexthop_len = 32;
bgp_info->attr->mp_nexthop_local = peer_address;
if (bgp_info->attr->mp_nexthop_len != 32)
bgp_info->attr->mp_nexthop_len = 32;
}
else
{
(bgp_attr_extra_get (bgp_info->attr))->mp_nexthop_global = peer_address;
if (bgp_info->attr->extra->mp_nexthop_len == 0)
bgp_info->attr->extra->mp_nexthop_len = 16;
bgp_info->attr->mp_nexthop_global = peer_address;
if (bgp_info->attr->mp_nexthop_len == 0)
bgp_info->attr->mp_nexthop_len = 16;
}
}
@ -2633,9 +2613,9 @@ route_set_ipv6_nexthop_peer (void *rule, struct prefix *prefix,
SET_FLAG(bgp_info->attr->rmap_change_flags,
BATTR_RMAP_NEXTHOP_PEER_ADDRESS);
/* clear next hop value. */
memset (&((bgp_attr_extra_get (bgp_info->attr))->mp_nexthop_global),
memset (&(bgp_info->attr->mp_nexthop_global),
0, sizeof (struct in6_addr));
memset (&((bgp_attr_extra_get (bgp_info->attr))->mp_nexthop_local),
memset (&(bgp_info->attr->mp_nexthop_local),
0, sizeof (struct in6_addr));
}
}
@ -2688,8 +2668,8 @@ route_set_vpnv4_nexthop (void *rule, struct prefix *prefix,
bgp_info = object;
/* Set next hop value. */
(bgp_attr_extra_get (bgp_info->attr))->mp_nexthop_global_in = *address;
(bgp_attr_extra_get (bgp_info->attr))->mp_nexthop_len = 4;
bgp_info->attr->mp_nexthop_global_in = *address;
bgp_info->attr->mp_nexthop_len = 4;
}
return RMAP_OKAY;
@ -2730,8 +2710,8 @@ route_set_vpnv6_nexthop (void *rule, struct prefix *prefix,
bgp_info = object;
/* Set next hop value. */
memcpy (&(bgp_attr_extra_get (bgp_info->attr))->mp_nexthop_global, address, sizeof(struct in6_addr));
(bgp_attr_extra_get (bgp_info->attr))->mp_nexthop_len = BGP_ATTR_NHLEN_VPNV6_GLOBAL;
memcpy (&bgp_info->attr->mp_nexthop_global, address, sizeof(struct in6_addr));
bgp_info->attr->mp_nexthop_len = BGP_ATTR_NHLEN_VPNV6_GLOBAL;
}
return RMAP_OKAY;
@ -2794,7 +2774,7 @@ route_set_originator_id (void *rule, struct prefix *prefix, route_map_object_t t
bgp_info = object;
bgp_info->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID);
(bgp_attr_extra_get (bgp_info->attr))->originator_id = *address;
bgp_info->attr->originator_id = *address;
}
return RMAP_OKAY;
@ -3112,6 +3092,9 @@ bgp_route_map_process_update (struct bgp *bgp, const char *rmap_name, int route_
for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
{
/* For table route-map updates. */
if (!bgp_fibupd_safi(safi))
continue;
if (bgp->table_map[afi][safi].name &&
(strcmp(rmap_name, bgp->table_map[afi][safi].name) == 0))
{

View File

@ -802,16 +802,10 @@ bgp4PathAttrTable (struct variable *v, oid name[], size_t *length,
return SNMP_INTEGER (1);
break;
case BGP4PATHATTRAGGREGATORAS: /* 10 */
if (binfo->attr->extra)
return SNMP_INTEGER (binfo->attr->extra->aggregator_as);
else
return SNMP_INTEGER (0);
return SNMP_INTEGER (binfo->attr->aggregator_as);
break;
case BGP4PATHATTRAGGREGATORADDR: /* 11 */
if (binfo->attr->extra)
return SNMP_IPADDRESS (binfo->attr->extra->aggregator_addr);
else
return SNMP_INTEGER (0);
return SNMP_IPADDRESS (binfo->attr->aggregator_addr);
break;
case BGP4PATHATTRCALCLOCALPREF: /* 12 */
return SNMP_INTEGER (-1);

View File

@ -586,7 +586,6 @@ subgroup_announce_table (struct update_subgroup *subgrp,
struct bgp_node *rn;
struct bgp_info *ri;
struct attr attr;
struct attr_extra extra;
struct peer *peer;
afi_t afi;
safi_t safi;
@ -609,9 +608,6 @@ subgroup_announce_table (struct update_subgroup *subgrp,
&& CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_DEFAULT_ORIGINATE))
subgroup_default_originate (subgrp, 0);
/* It's initialized in bgp_announce_check() */
attr.extra = &extra;
for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn))
for (ri = rn->info; ri; ri = ri->next)
@ -715,18 +711,16 @@ subgroup_default_originate (struct update_subgroup *subgrp, int withdraw)
str2prefix ("0.0.0.0/0", &p);
else if (afi == AFI_IP6)
{
struct attr_extra *ae = attr.extra;
str2prefix ("::/0", &p);
/* IPv6 global nexthop must be included. */
ae->mp_nexthop_len = BGP_ATTR_NHLEN_IPV6_GLOBAL;
attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV6_GLOBAL;
/* If the peer is on shared nextwork and we have link-local
nexthop set it. */
if (peer->shared_network
&& !IN6_IS_ADDR_UNSPECIFIED (&peer->nexthop.v6_local))
ae->mp_nexthop_len = BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL;
attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL;
}
if (peer->default_rmap[afi][safi].name)
@ -738,11 +732,9 @@ subgroup_default_originate (struct update_subgroup *subgrp, int withdraw)
for (ri = rn->info; ri; ri = ri->next)
{
struct attr dummy_attr;
struct attr_extra dummy_extra;
struct bgp_info info;
/* Provide dummy so the route-map can't modify the attributes */
dummy_attr.extra = &dummy_extra;
bgp_attr_dup (&dummy_attr, ri->attr);
info.peer = ri->peer;
info.attr = &dummy_attr;
@ -793,7 +785,6 @@ subgroup_default_originate (struct update_subgroup *subgrp, int withdraw)
}
}
bgp_attr_extra_free (&attr);
aspath_unintern (&aspath);
}

View File

@ -423,12 +423,10 @@ bpacket_reformat_for_peer (struct bpacket *pkt, struct peer_af *paf)
afi_t nhafi = AFI_MAX; /* NH AFI is based on nhlen! */
int route_map_sets_nh;
nhlen = stream_getc_from (s, vec->offset);
if (paf->afi == AFI_IP || paf->afi == AFI_IP6)
{
nhafi = BGP_NEXTHOP_AFI_FROM_NHLEN(nhlen);
if (peer_cap_enhe(peer, paf->afi, paf->safi))
nhafi = AFI_IP6;
}
if (peer_cap_enhe(peer, paf->afi, paf->safi))
nhafi = AFI_IP6;
else
nhafi = BGP_NEXTHOP_AFI_FROM_NHLEN(nhlen);
if (nhafi == AFI_IP)
{
@ -484,6 +482,7 @@ bpacket_reformat_for_peer (struct bpacket *pkt, struct peer_af *paf)
nh_modified = 1;
}
else if (peer->sort == BGP_PEER_EBGP &&
paf->safi != SAFI_EVPN &&
(bgp_multiaccess_check_v4 (v4nh, peer) == 0) &&
!CHECK_FLAG(vec->flags,
BPKT_ATTRVEC_FLAGS_RMAP_NH_UNCHANGED) &&
@ -609,6 +608,30 @@ bpacket_reformat_for_peer (struct bpacket *pkt, struct peer_af *paf)
(nhlen == 24 ? " and RD" : ""));
}
}
else if (paf->afi == AFI_L2VPN)
{
struct in_addr v4nh, *mod_v4nh;
int nh_modified = 0;
stream_get_from (&v4nh, s, vec->offset + 1, 4);
mod_v4nh = &v4nh;
/* No route-map changes allowed for EVPN nexthops. */
if (!v4nh.s_addr)
{
mod_v4nh = &peer->nexthop.v4;
nh_modified = 1;
}
if (nh_modified)
stream_put_in_addr_at (s, vec->offset + 1, mod_v4nh);
if (bgp_debug_update(peer, NULL, NULL, 0))
zlog_debug ("u%" PRIu64 ":s%" PRIu64 " %s send UPDATE w/ nexthop %s",
PAF_SUBGRP(paf)->update_group->id, PAF_SUBGRP(paf)->id,
peer->host, inet_ntoa (*mod_v4nh));
}
}
bgp_packet_add (peer, s);
@ -681,7 +704,7 @@ subgroup_update_packet (struct update_subgroup *subgrp)
int addpath_encode = 0;
u_int32_t addpath_tx_id = 0;
struct prefix_rd *prd = NULL;
char label_buf[20];
mpls_label_t label = MPLS_INVALID_LABEL;
if (!subgrp)
return NULL;
@ -696,7 +719,6 @@ subgroup_update_packet (struct update_subgroup *subgrp)
stream_reset (s);
snlri = subgrp->scratch;
stream_reset (snlri);
label_buf[0] = '\0';
bpacket_attr_vec_arr_reset (&vecarr);
@ -785,8 +807,6 @@ subgroup_update_packet (struct update_subgroup *subgrp)
else
{
/* Encode the prefix in MP_REACH_NLRI attribute */
mpls_label_t label = MPLS_INVALID_LABEL;
if (rn->prn)
prd = (struct prefix_rd *) &rn->prn->p;
@ -796,9 +816,6 @@ subgroup_update_packet (struct update_subgroup *subgrp)
if (binfo && binfo->extra)
label = binfo->extra->label;
if (bgp_labeled_safi(safi))
sprintf (label_buf, "label %u", label_pton(&label));
if (stream_empty (snlri))
mpattrlen_pos = bgp_packet_mpattr_start (snlri, peer, afi, safi,
&vecarr, adv->baa->attr);
@ -831,12 +848,11 @@ subgroup_update_packet (struct update_subgroup *subgrp)
send_attr_printed = 1;
}
zlog_debug ("u%" PRIu64 ":s%" PRIu64 " send UPDATE %s %s",
subgrp->update_group->id, subgrp->id,
bgp_debug_rdpfxpath2str (prd, &rn->p, addpath_encode,
addpath_tx_id,
pfx_buf, sizeof (pfx_buf)),
label_buf);
bgp_debug_rdpfxpath2str (afi, safi, prd, &rn->p, &label,
addpath_encode, addpath_tx_id,
pfx_buf, sizeof (pfx_buf));
zlog_debug ("u%" PRIu64 ":s%" PRIu64 " send UPDATE %s",
subgrp->update_group->id, subgrp->id, pfx_buf);
}
/* Synchnorize attribute. */
@ -989,11 +1005,11 @@ subgroup_withdraw_packet (struct update_subgroup *subgrp)
{
char pfx_buf[BGP_PRD_PATH_STRLEN];
bgp_debug_rdpfxpath2str (afi, safi, prd, &rn->p, NULL,
addpath_encode, addpath_tx_id,
pfx_buf, sizeof (pfx_buf));
zlog_debug ("u%" PRIu64 ":s%" PRIu64 " send UPDATE %s -- unreachable",
subgrp->update_group->id, subgrp->id,
bgp_debug_rdpfxpath2str (prd, &rn->p,
addpath_encode, addpath_tx_id,
pfx_buf, sizeof (pfx_buf)));
subgrp->update_group->id, subgrp->id, pfx_buf);
}
subgrp->scount--;

View File

@ -6711,10 +6711,6 @@ DEFUN (show_bgp_memory,
vty_out (vty, "%ld BGP attributes, using %s of memory\n", count,
mtype_memstr (memstrbuf, sizeof (memstrbuf),
count * sizeof(struct attr)));
if ((count = mtype_stats_alloc (MTYPE_ATTR_EXTRA)))
vty_out (vty, "%ld BGP extra attributes, using %s of memory\n", count,
mtype_memstr (memstrbuf, sizeof (memstrbuf),
count * sizeof(struct attr_extra)));
if ((count = attr_unknown_count()))
vty_out (vty, "%ld unknown attributes\n", count);
@ -7261,7 +7257,7 @@ bgp_show_all_instances_summary_vty (struct vty *vty, afi_t afi, safi_t safi,
}
static int
int
bgp_show_summary_vty (struct vty *vty, const char *name,
afi_t afi, safi_t safi, u_char use_json)
{
@ -10665,6 +10661,13 @@ static struct cmd_node bgp_evpn_node =
1
};
static struct cmd_node bgp_evpn_vni_node =
{
BGP_EVPN_VNI_NODE,
"%s(config-router-af-vni)# ",
1
};
static void community_list_vty (void);
static void
@ -10734,6 +10737,7 @@ bgp_vty_init (void)
install_node (&bgp_vpnv4_node, NULL);
install_node (&bgp_vpnv6_node, NULL);
install_node (&bgp_evpn_node, NULL);
install_node (&bgp_evpn_vni_node, NULL);
/* Install default VTY commands to new nodes. */
install_default (BGP_NODE);
@ -10746,6 +10750,7 @@ bgp_vty_init (void)
install_default (BGP_VPNV4_NODE);
install_default (BGP_VPNV6_NODE);
install_default (BGP_EVPN_NODE);
install_default (BGP_EVPN_VNI_NODE);
/* "bgp multiple-instance" commands. */
install_element (CONFIG_NODE, &bgp_multiple_instance_cmd);
@ -11236,6 +11241,8 @@ bgp_vty_init (void)
install_element (BGP_VPNV4_NODE, &no_neighbor_route_reflector_client_cmd);
install_element (BGP_VPNV6_NODE, &neighbor_route_reflector_client_cmd);
install_element (BGP_VPNV6_NODE, &no_neighbor_route_reflector_client_cmd);
install_element (BGP_EVPN_NODE, &neighbor_route_reflector_client_cmd);
install_element (BGP_EVPN_NODE, &no_neighbor_route_reflector_client_cmd);
/* "neighbor route-server" commands.*/
install_element (BGP_NODE, &neighbor_route_server_client_hidden_cmd);
@ -11609,6 +11616,8 @@ bgp_vty_init (void)
install_element (BGP_VPNV4_NODE, &no_neighbor_allowas_in_cmd);
install_element (BGP_VPNV6_NODE, &neighbor_allowas_in_cmd);
install_element (BGP_VPNV6_NODE, &no_neighbor_allowas_in_cmd);
install_element (BGP_EVPN_NODE, &neighbor_allowas_in_cmd);
install_element (BGP_EVPN_NODE, &no_neighbor_allowas_in_cmd);
/* address-family commands. */
install_element (BGP_NODE, &address_family_ipv4_safi_cmd);

View File

@ -69,4 +69,7 @@ argv_find_and_parse_safi(struct cmd_token **argv, int argc, int *index, safi_t *
extern int
bgp_vty_find_and_parse_afi_safi_bgp (struct vty *vty, struct cmd_token **argv, int argc, int *idx,
afi_t *afi, safi_t *safi, struct bgp **bgp);
extern int
bgp_show_summary_vty (struct vty *vty, const char *name,
afi_t afi, safi_t safi, u_char use_json);
#endif /* _QUAGGA_BGP_VTY_H */

View File

@ -35,6 +35,7 @@
#include "lib/bfd.h"
#include "filter.h"
#include "mpls.h"
#include "vxlan.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_route.h"
@ -52,6 +53,7 @@
# include "bgpd/rfapi/rfapi_backend.h"
# include "bgpd/rfapi/vnc_export_bgp.h"
#endif
#include "bgpd/bgp_evpn.h"
/* All information about zebra. */
struct zclient *zclient = NULL;
@ -71,14 +73,12 @@ struct stream *bgp_label_buf = NULL;
2. use an array to avoid number of mallocs.
Number of supported next-hops are finite, use of arrays should be ok. */
struct attr attr_cp[MULTIPATH_NUM];
struct attr_extra attr_extra_cp[MULTIPATH_NUM];
unsigned int attr_index = 0;
/* Once per address-family initialization of the attribute array */
#define BGP_INFO_ATTR_BUF_INIT()\
do {\
memset(attr_cp, 0, MULTIPATH_NUM * sizeof(struct attr));\
memset(attr_extra_cp, 0, MULTIPATH_NUM * sizeof(struct attr_extra));\
attr_index = 0;\
} while (0)
@ -86,7 +86,6 @@ do {\
do { \
*info_dst = *info_src; \
assert(attr_index != multipath_num);\
attr_cp[attr_index].extra = &attr_extra_cp[attr_index]; \
bgp_attr_dup (&attr_cp[attr_index], info_src->attr); \
bgp_attr_deep_dup (&attr_cp[attr_index], info_src->attr); \
info_dst->attr = &attr_cp[attr_index]; \
@ -1160,23 +1159,23 @@ bgp_info_to_ipv6_nexthop (struct bgp_info *info)
struct in6_addr *nexthop = NULL;
/* Only global address nexthop exists. */
if (info->attr->extra->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL)
nexthop = &info->attr->extra->mp_nexthop_global;
if (info->attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL)
nexthop = &info->attr->mp_nexthop_global;
/* If both global and link-local address present. */
if (info->attr->extra->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL)
if (info->attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL)
{
/* Check if route-map is set to prefer global over link-local */
if (info->attr->extra->mp_nexthop_prefer_global)
nexthop = &info->attr->extra->mp_nexthop_global;
if (info->attr->mp_nexthop_prefer_global)
nexthop = &info->attr->mp_nexthop_global;
else
{
/* Workaround for Cisco's nexthop bug. */
if (IN6_IS_ADDR_UNSPECIFIED (&info->attr->extra->mp_nexthop_global)
if (IN6_IS_ADDR_UNSPECIFIED (&info->attr->mp_nexthop_global)
&& info->peer->su_remote->sa.sa_family == AF_INET6)
nexthop = &info->peer->su_remote->sin6.sin6_addr;
else
nexthop = &info->attr->extra->mp_nexthop_local;
nexthop = &info->attr->mp_nexthop_local;
}
}
@ -1246,10 +1245,7 @@ bgp_zebra_announce (struct bgp_node *rn, struct prefix *p, struct bgp_info *info
flags = 0;
peer = info->peer;
if ((info->attr->extra) && (info->attr->extra->tag != 0))
tag = info->attr->extra->tag;
else
tag = 0;
tag = info->attr->tag;
/* When we create an aggregate route we must also install a Null0 route in
* the RIB */
@ -1303,7 +1299,7 @@ bgp_zebra_announce (struct bgp_node *rn, struct prefix *p, struct bgp_info *info
{
/* Metric is currently based on the best-path only */
metric = info_cp->attr->med;
tag = info_cp->attr->extra->tag;
tag = info_cp->attr->tag;
}
nexthop = &info_cp->attr->nexthop;
}
@ -1418,8 +1414,6 @@ bgp_zebra_announce (struct bgp_node *rn, struct prefix *p, struct bgp_info *info
ifindex = 0;
nexthop = NULL;
assert (info->attr->extra);
if (bgp->table_map[afi][safi].name)
BGP_INFO_ATTR_BUF_INIT();
@ -1439,7 +1433,7 @@ bgp_zebra_announce (struct bgp_node *rn, struct prefix *p, struct bgp_info *info
if (mpinfo == info)
{
metric = info_cp->attr->med;
tag = info_cp->attr->extra->tag;
tag = info_cp->attr->tag;
}
nexthop = bgp_info_to_ipv6_nexthop(info_cp);
}
@ -1452,7 +1446,7 @@ bgp_zebra_announce (struct bgp_node *rn, struct prefix *p, struct bgp_info *info
continue;
if ((mpinfo == info) &&
mpinfo->attr->extra->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL)
mpinfo->attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL)
if (mpinfo->peer->nexthop.ifp)
ifindex = mpinfo->peer->nexthop.ifp->ifindex;
@ -1672,10 +1666,10 @@ bgp_zebra_withdraw (struct prefix *p, struct bgp_info *info, safi_t safi)
api.metric = info->attr->med;
api.tag = 0;
if ((info->attr->extra) && (info->attr->extra->tag != 0))
if (info->attr->tag != 0)
{
SET_FLAG(api.message, ZAPI_MESSAGE_TAG);
api.tag = info->attr->extra->tag;
api.tag = info->attr->tag;
}
if (bgp_debug_zebra(p))
@ -1694,8 +1688,6 @@ bgp_zebra_withdraw (struct prefix *p, struct bgp_info *info, safi_t safi)
if (p->family == AF_INET6)
{
struct zapi_ipv6 api;
assert (info->attr->extra);
api.vrf_id = peer->bgp->vrf_id;
api.flags = flags;
@ -1712,10 +1704,10 @@ bgp_zebra_withdraw (struct prefix *p, struct bgp_info *info, safi_t safi)
api.metric = info->attr->med;
api.tag = 0;
if ((info->attr->extra) && (info->attr->extra->tag != 0))
if (info->attr->tag != 0)
{
SET_FLAG(api.message, ZAPI_MESSAGE_TAG);
api.tag = info->attr->extra->tag;
api.tag = info->attr->tag;
}
if (bgp_debug_zebra(p))
@ -1901,9 +1893,7 @@ bgp_redistribute_metric_set (struct bgp *bgp, struct bgp_redist *red, afi_t afi,
{
struct attr *old_attr;
struct attr new_attr;
struct attr_extra new_extra;
new_attr.extra = &new_extra;
bgp_attr_dup (&new_attr, ri->attr);
new_attr.med = red->redist_metric;
old_attr = ri->attr;
@ -2033,6 +2023,11 @@ bgp_zebra_instance_register (struct bgp *bgp)
/* Register for router-id, interfaces, redistributed routes. */
zclient_send_reg_requests (zclient, bgp->vrf_id);
/* For default instance, register to learn about VNIs, if appropriate. */
if (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT
&& bgp->advertise_all_vni)
bgp_zebra_advertise_all_vni (bgp, 1);
}
/* Deregister this instance with Zebra. Invoked upon the instance
@ -2048,6 +2043,11 @@ bgp_zebra_instance_deregister (struct bgp *bgp)
if (BGP_DEBUG (zebra, ZEBRA))
zlog_debug("Deregistering VRF %u", bgp->vrf_id);
/* For default instance, unregister learning about VNIs, if appropriate. */
if (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT
&& bgp->advertise_all_vni)
bgp_zebra_advertise_all_vni (bgp, 0);
/* Deregister for router-id, interfaces, redistributed routes. */
zclient_send_dereg_requests (zclient, bgp->vrf_id);
}
@ -2080,6 +2080,29 @@ bgp_zebra_terminate_radv (struct bgp *bgp, struct peer *peer)
zclient_send_interface_radv_req (zclient, bgp->vrf_id, peer->ifp, 0, 0);
}
int
bgp_zebra_advertise_all_vni (struct bgp *bgp, int advertise)
{
struct stream *s;
/* Check socket. */
if (!zclient || zclient->sock < 0)
return 0;
/* Don't try to register if Zebra doesn't know of this instance. */
if (!IS_BGP_INST_KNOWN_TO_ZEBRA(bgp))
return 0;
s = zclient->obuf;
stream_reset (s);
zclient_create_header (s, ZEBRA_ADVERTISE_ALL_VNI, bgp->vrf_id);
stream_putc(s, advertise);
stream_putw_at (s, 0, stream_get_endp (s));
return zclient_send_message(zclient);
}
/* BGP has established connection with Zebra. */
static void
bgp_zebra_connected (struct zclient *zclient)
@ -2106,6 +2129,85 @@ bgp_zebra_connected (struct zclient *zclient)
*/
}
static int
bgp_zebra_process_local_vni (int command, struct zclient *zclient,
zebra_size_t length, vrf_id_t vrf_id)
{
struct stream *s;
vni_t vni;
struct bgp *bgp;
struct in_addr vtep_ip;
s = zclient->ibuf;
vni = stream_getl (s);
if (command == ZEBRA_VNI_ADD)
vtep_ip.s_addr = stream_get_ipv4 (s);
bgp = bgp_lookup_by_vrf_id (vrf_id);
if (!bgp)
return 0;
if (BGP_DEBUG (zebra, ZEBRA))
zlog_debug("Rx VNI %s VRF %u VNI %u",
(command == ZEBRA_VNI_ADD) ? "add" : "del", vrf_id, vni);
if (command == ZEBRA_VNI_ADD)
return bgp_evpn_local_vni_add (bgp, vni, vtep_ip.s_addr? vtep_ip : bgp->router_id);
else
return bgp_evpn_local_vni_del (bgp, vni);
}
static int
bgp_zebra_process_local_macip (int command, struct zclient *zclient,
zebra_size_t length, vrf_id_t vrf_id)
{
struct stream *s;
vni_t vni;
struct bgp *bgp;
struct ethaddr mac;
struct ipaddr ip;
int ipa_len;
char buf[ETHER_ADDR_STRLEN];
char buf1[INET6_ADDRSTRLEN];
u_char sticky;
memset (&ip, 0, sizeof (ip));
s = zclient->ibuf;
vni = stream_getl (s);
stream_get (&mac.octet, s, ETHER_ADDR_LEN);
ipa_len = stream_getl (s);
if (ipa_len != 0 &&
ipa_len != IPV4_MAX_BYTELEN &&
ipa_len != IPV6_MAX_BYTELEN)
{
zlog_err ("%u:Recv MACIP %s with invalid IP addr length %d",
vrf_id, (command == ZEBRA_MACIP_ADD) ? "Add" : "Del",
ipa_len);
return -1;
}
if (ipa_len)
{
ip.ipa_type = (ipa_len == IPV4_MAX_BYTELEN) ? IPADDR_V4: IPADDR_V6;
stream_get (&ip.ip.addr, s, ipa_len);
}
sticky = stream_getc (s);
bgp = bgp_lookup_by_vrf_id (vrf_id);
if (!bgp)
return 0;
if (BGP_DEBUG (zebra, ZEBRA))
zlog_debug ("%u:Recv MACIP %s %sMAC %s IP %s VNI %u",
vrf_id, (command == ZEBRA_MACIP_ADD) ? "Add" : "Del",
sticky ? "sticky " : "",
prefix_mac2str (&mac, buf, sizeof (buf)),
ipaddr2str (&ip, buf1, sizeof(buf1)), vni);
if (command == ZEBRA_MACIP_ADD)
return bgp_evpn_local_macip_add (bgp, vni, &mac, &ip, sticky);
else
return bgp_evpn_local_macip_del (bgp, vni, &mac, &ip);
}
void
bgp_zebra_init (struct thread_master *master)
@ -2133,6 +2235,10 @@ bgp_zebra_init (struct thread_master *master)
zclient->nexthop_update = bgp_read_nexthop_update;
zclient->import_check_update = bgp_read_import_check_update;
zclient->fec_update = bgp_read_fec_update;
zclient->local_vni_add = bgp_zebra_process_local_vni;
zclient->local_vni_del = bgp_zebra_process_local_vni;
zclient->local_macip_add = bgp_zebra_process_local_macip;
zclient->local_macip_del = bgp_zebra_process_local_macip;
bgp_nexthop_buf = stream_new(multipath_num * sizeof (struct in6_addr));
bgp_ifindices_buf = stream_new(multipath_num * sizeof (unsigned int));

View File

@ -54,6 +54,8 @@ extern struct interface *if_lookup_by_ipv4_exact (struct in_addr *, vrf_id_t);
extern struct interface *if_lookup_by_ipv6 (struct in6_addr *, ifindex_t, vrf_id_t);
extern struct interface *if_lookup_by_ipv6_exact (struct in6_addr *, ifindex_t, vrf_id_t);
extern int bgp_zebra_advertise_all_vni (struct bgp *, int);
extern int bgp_zebra_num_connects(void);
#endif /* _QUAGGA_BGP_ZEBRA_H */

View File

@ -227,6 +227,10 @@ bgp_router_id_set (struct bgp *bgp, const struct in_addr *id)
if (IPV4_ADDR_SAME (&bgp->router_id, id))
return 0;
/* EVPN uses router id in RD, withdraw them */
if (bgp->advertise_all_vni)
bgp_evpn_handle_router_id_update (bgp, TRUE);
IPV4_ADDR_COPY (&bgp->router_id, id);
/* Set all peer's local identifier with this value. */
@ -241,6 +245,11 @@ bgp_router_id_set (struct bgp *bgp, const struct in_addr *id)
BGP_NOTIFY_CEASE_CONFIG_CHANGE);
}
}
/* EVPN uses router id in RD, update them */
if (bgp->advertise_all_vni)
bgp_evpn_handle_router_id_update (bgp, FALSE);
return 0;
}
@ -3004,6 +3013,7 @@ bgp_create (as_t *as, const char *name, enum bgp_instance_type inst_type)
QOBJ_REG (bgp, bgp);
update_bgp_group_init(bgp);
bgp_evpn_init(bgp);
return bgp;
}
@ -3355,6 +3365,8 @@ bgp_free (struct bgp *bgp)
bgp_scan_finish (bgp);
bgp_address_destroy (bgp);
bgp_evpn_cleanup (bgp);
if (bgp->name)
XFREE(MTYPE_BGP, bgp->name);
@ -7367,6 +7379,9 @@ bgp_config_write_family (struct vty *vty, struct bgp *bgp, afi_t afi,
bgp_config_write_maxpaths (vty, bgp, afi, safi, &write);
bgp_config_write_table_map (vty, bgp, afi, safi, &write);
if (safi == SAFI_EVPN)
bgp_config_write_evpn_info (vty, bgp, afi, safi, &write);
if (write)
vty_out (vty, " exit-address-family\n");

View File

@ -33,6 +33,7 @@
#include "linklist.h"
#include "defaults.h"
#include "bgp_memory.h"
#include "bitfield.h"
#define BGP_MAX_HOSTNAME 64 /* Linux max, is larger than most other sys */
@ -367,6 +368,20 @@ struct bgp
struct rfapi *rfapi;
#endif
/* EVPN related information */
/* EVI hash table */
struct hash *vnihash;
/* EVPN enable - advertise local VNIs and their MACs etc. */
int advertise_all_vni;
/* Hash table of Import RTs to EVIs */
struct hash *import_rt_hash;
/* Id space for automatic RD derivation for an EVI */
bitfield_t rd_idspace;
QOBJ_FIELDS
};
DECLARE_QOBJ_TYPE(bgp)

View File

@ -715,7 +715,6 @@ add_vnc_route (
/* Cripes, the memory management of attributes is byzantine */
bgp_attr_default_set (&attr, BGP_ORIGIN_INCOMPLETE);
assert (attr.extra);
/*
* At this point:
@ -772,7 +771,6 @@ add_vnc_route (
/* Encap SAFI not used with MPLS */
vnc_zlog_debug_verbose ("%s: mpls tunnel type, encap safi omitted", __func__);
aspath_unintern (&attr.aspath); /* Unintern original. */
bgp_attr_extra_free (&attr);
return;
}
}
@ -790,7 +788,7 @@ add_vnc_route (
}
/* override default weight assigned by bgp_attr_default_set() */
attr.extra->weight = rfd->peer ? rfd->peer->weight[afi][safi] : 0;
attr.weight = rfd->peer ? rfd->peer->weight[afi][safi] : 0;
/*
* NB: ticket 81: do not reset attr.aspath here because it would
@ -808,7 +806,7 @@ add_vnc_route (
if (type == ZEBRA_ROUTE_BGP_DIRECT || type == ZEBRA_ROUTE_BGP_DIRECT_EXT)
{
attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID);
attr.extra->originator_id = bgp->router_id;
attr.originator_id = bgp->router_id;
}
@ -825,7 +823,7 @@ add_vnc_route (
encaptlv->length = 4;
lt = htonl (*lifetime);
memcpy (encaptlv->value, &lt, 4);
attr.extra->vnc_subtlvs = encaptlv;
attr.vnc_subtlvs = encaptlv;
vnc_zlog_debug_verbose ("%s: set Encap Attr Prefix Lifetime to %d",
__func__, *lifetime);
}
@ -845,13 +843,13 @@ add_vnc_route (
*/
encaptlv =
encap_tlv_dup ((struct bgp_attr_encap_subtlv *) rfp_options);
if (attr.extra->vnc_subtlvs)
if (attr.vnc_subtlvs)
{
attr.extra->vnc_subtlvs->next = encaptlv;
attr.vnc_subtlvs->next = encaptlv;
}
else
{
attr.extra->vnc_subtlvs = encaptlv;
attr.vnc_subtlvs = encaptlv;
}
}
@ -859,7 +857,7 @@ add_vnc_route (
{
struct bgp_tea_options *hop;
/* XXX max of one tlv present so far from above code */
struct bgp_attr_encap_subtlv *tail = attr.extra->vnc_subtlvs;
struct bgp_attr_encap_subtlv *tail = attr.vnc_subtlvs;
for (hop = rfp_options; hop; hop = hop->next)
{
@ -887,7 +885,7 @@ add_vnc_route (
}
else
{
attr.extra->vnc_subtlvs = encaptlv;
attr.vnc_subtlvs = encaptlv;
}
tail = encaptlv;
}
@ -903,8 +901,8 @@ add_vnc_route (
*/
attr.extra->ecommunity = ecommunity_new ();
assert (attr.extra->ecommunity);
attr.ecommunity = ecommunity_new ();
assert (attr.ecommunity);
if (TunnelType != BGP_ENCAP_TYPE_MPLS &&
TunnelType != BGP_ENCAP_TYPE_RESERVED)
@ -921,7 +919,7 @@ add_vnc_route (
beec.val[1] = ECOMMUNITY_OPAQUE_SUBTYPE_ENCAP;
beec.val[6] = ((TunnelType) >> 8) & 0xff;
beec.val[7] = (TunnelType) & 0xff;
ecommunity_add_val (attr.extra->ecommunity, &beec);
ecommunity_add_val (attr.ecommunity, &beec);
}
/*
@ -929,21 +927,21 @@ add_vnc_route (
*/
if (rt_export_list)
{
attr.extra->ecommunity =
ecommunity_merge (attr.extra->ecommunity, rt_export_list);
attr.ecommunity =
ecommunity_merge (attr.ecommunity, rt_export_list);
}
if (attr.extra->ecommunity->size)
if (attr.ecommunity->size)
{
attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES);
}
else
{
ecommunity_free (&attr.extra->ecommunity);
attr.extra->ecommunity = NULL;
ecommunity_free (&attr.ecommunity);
attr.ecommunity = NULL;
}
vnc_zlog_debug_verbose ("%s: attr.extra->ecommunity=%p", __func__,
attr.extra->ecommunity);
vnc_zlog_debug_verbose ("%s: attr.ecommunity=%p", __func__,
attr.ecommunity);
/*
@ -965,13 +963,13 @@ add_vnc_route (
*/
attr.nexthop.s_addr = nexthop->addr.v4.s_addr;
attr.extra->mp_nexthop_global_in = nexthop->addr.v4;
attr.extra->mp_nexthop_len = 4;
attr.mp_nexthop_global_in = nexthop->addr.v4;
attr.mp_nexthop_len = 4;
break;
case AF_INET6:
attr.extra->mp_nexthop_global = nexthop->addr.v6;
attr.extra->mp_nexthop_len = 16;
attr.mp_nexthop_global = nexthop->addr.v6;
attr.mp_nexthop_len = 16;
break;
default:
@ -1016,7 +1014,6 @@ add_vnc_route (
new_attr = bgp_attr_intern (&attr);
aspath_unintern (&attr.aspath); /* Unintern original. */
bgp_attr_extra_free (&attr);
/*
* At this point:

View File

@ -162,28 +162,24 @@ rfapi_tunneltype_option_to_tlv (
struct rfapi_un_option *
rfapi_encap_tlv_to_un_option (struct attr *attr)
{
struct attr_extra *attre = attr->extra;
struct rfapi_un_option *uo = NULL;
struct rfapi_tunneltype_option *tto;
int rc;
struct bgp_attr_encap_subtlv *stlv;
if (!attre)
return NULL;
/* no tunnel encap attr stored */
if (!attre->encap_tunneltype)
if (!attr->encap_tunneltype)
return NULL;
stlv = attre->encap_subtlvs;
stlv = attr->encap_subtlvs;
uo = XCALLOC (MTYPE_RFAPI_UN_OPTION, sizeof (struct rfapi_un_option));
assert (uo);
uo->type = RFAPI_UN_OPTION_TYPE_TUNNELTYPE;
uo->v.tunnel.type = attre->encap_tunneltype;
uo->v.tunnel.type = attr->encap_tunneltype;
tto = &uo->v.tunnel;
switch (attre->encap_tunneltype)
switch (attr->encap_tunneltype)
{
case BGP_ENCAP_TYPE_L2TPV3_OVER_IP:
rc = tlv_to_bgp_encap_type_l2tpv3overip (stlv, &tto->bgpinfo.l2tpv3_ip);
@ -249,7 +245,7 @@ rfapi_encap_tlv_to_un_option (struct attr *attr)
default:
vnc_zlog_debug_verbose ("%s: unknown tunnel type %d",
__func__, attre->encap_tunneltype);
__func__, attr->encap_tunneltype);
rc = -1;
break;
}

View File

@ -1,4 +1,4 @@
/*
/*
*
* Copyright 2009-2016, LabN Consulting, L.L.C.
*
@ -308,12 +308,12 @@ rfapi_deferred_close_workfunc (struct work_queue *q, void *data)
int
rfapiGetL2o (struct attr *attr, struct rfapi_l2address_option *l2o)
{
if (attr && attr->extra)
if (attr)
{
struct bgp_attr_encap_subtlv *pEncap;
for (pEncap = attr->extra->vnc_subtlvs; pEncap; pEncap = pEncap->next)
for (pEncap = attr->vnc_subtlvs; pEncap; pEncap = pEncap->next)
{
if (pEncap->type == BGP_VNC_SUBTLV_TYPE_RFPOPTION)
@ -358,10 +358,10 @@ rfapiGetVncLifetime (struct attr *attr, uint32_t * lifetime)
*lifetime = RFAPI_INFINITE_LIFETIME; /* default to infinite */
if (attr && attr->extra)
if (attr)
{
for (pEncap = attr->extra->vnc_subtlvs; pEncap; pEncap = pEncap->next)
for (pEncap = attr->vnc_subtlvs; pEncap; pEncap = pEncap->next)
{
if (pEncap->type == BGP_VNC_SUBTLV_TYPE_LIFETIME)
@ -387,9 +387,9 @@ rfapiGetTunnelType (struct attr *attr,
bgp_encap_types *type)
{
*type = BGP_ENCAP_TYPE_MPLS; /* default to MPLS */
if (attr && attr->extra && attr->extra->ecommunity)
if (attr && attr->ecommunity)
{
struct ecommunity *ecom = attr->extra->ecommunity;
struct ecommunity *ecom = attr->ecommunity;
int i;
for (i = 0; i < (ecom->size * ECOMMUNITY_SIZE); i += ECOMMUNITY_SIZE)
@ -431,9 +431,9 @@ rfapiGetVncTunnelUnAddr (struct attr *attr, struct prefix *p)
return ENOENT;
}
if (attr && attr->extra)
if (attr)
{
for (pEncap = attr->extra->encap_subtlvs; pEncap; pEncap = pEncap->next)
for (pEncap = attr->encap_subtlvs; pEncap; pEncap = pEncap->next)
{
if (pEncap->type == BGP_ENCAP_SUBTLV_TYPE_REMOTE_ENDPOINT)
@ -1184,7 +1184,7 @@ rfapiVpnBiNhEqualsPt (struct bgp_info *bi, struct rfapi_ip_addr *hpt)
if (!hpt || !bi)
return 0;
family = BGP_MP_NEXTHOP_FAMILY (bi->attr->extra->mp_nexthop_len);
family = BGP_MP_NEXTHOP_FAMILY (bi->attr->mp_nexthop_len);
if (hpt->addr_family != family)
return 0;
@ -1192,12 +1192,12 @@ rfapiVpnBiNhEqualsPt (struct bgp_info *bi, struct rfapi_ip_addr *hpt)
switch (family)
{
case AF_INET:
if (bi->attr->extra->mp_nexthop_global_in.s_addr != hpt->addr.v4.s_addr)
if (bi->attr->mp_nexthop_global_in.s_addr != hpt->addr.v4.s_addr)
return 0;
break;
case AF_INET6:
if (IPV6_ADDR_CMP (&bi->attr->extra->mp_nexthop_global, &hpt->addr.v6))
if (IPV6_ADDR_CMP (&bi->attr->mp_nexthop_global, &hpt->addr.v6))
return 0;
break;
@ -1225,31 +1225,27 @@ rfapiVpnBiSamePtUn (struct bgp_info *bi1, struct bgp_info *bi2)
if (!bi1->attr || !bi2->attr)
return 0;
if (!bi1->attr->extra || !bi2->attr->extra)
return 0;
/*
* VN address comparisons
*/
if (BGP_MP_NEXTHOP_FAMILY (bi1->attr->extra->mp_nexthop_len) !=
BGP_MP_NEXTHOP_FAMILY (bi2->attr->extra->mp_nexthop_len))
if (BGP_MP_NEXTHOP_FAMILY (bi1->attr->mp_nexthop_len) !=
BGP_MP_NEXTHOP_FAMILY (bi2->attr->mp_nexthop_len))
{
return 0;
}
switch (BGP_MP_NEXTHOP_FAMILY (bi1->attr->extra->mp_nexthop_len))
switch (BGP_MP_NEXTHOP_FAMILY (bi1->attr->mp_nexthop_len))
{
case AF_INET:
if (bi1->attr->extra->mp_nexthop_global_in.s_addr !=
bi2->attr->extra->mp_nexthop_global_in.s_addr)
if (bi1->attr->mp_nexthop_global_in.s_addr !=
bi2->attr->mp_nexthop_global_in.s_addr)
return 0;
break;
case AF_INET6:
if (IPV6_ADDR_CMP (&bi1->attr->extra->mp_nexthop_global,
&bi2->attr->extra->mp_nexthop_global))
if (IPV6_ADDR_CMP (&bi1->attr->mp_nexthop_global,
&bi2->attr->mp_nexthop_global))
return 0;
break;
@ -1419,11 +1415,11 @@ rfapiRouteInfo2NextHopEntry (
memcpy (&vo->v.l2addr.macaddr, &rn->p.u.prefix_eth.octet,
ETHER_ADDR_LEN);
/* only low 3 bytes of this are significant */
if (bi->attr && bi->attr->extra)
if (bi->attr)
{
(void) rfapiEcommunityGetLNI (bi->attr->extra->ecommunity,
(void) rfapiEcommunityGetLNI (bi->attr->ecommunity,
&vo->v.l2addr.logical_net_id);
(void) rfapiEcommunityGetEthernetTag (bi->attr->extra->ecommunity,
(void) rfapiEcommunityGetEthernetTag (bi->attr->ecommunity,
&vo->v.l2addr.tag_id);
}
@ -1451,132 +1447,129 @@ rfapiRouteInfo2NextHopEntry (
bgp_encap_types tun_type;
new->prefix.cost = rfapiRfpCost (bi->attr);
if (bi->attr->extra)
struct bgp_attr_encap_subtlv *pEncap;
switch (BGP_MP_NEXTHOP_FAMILY (bi->attr->mp_nexthop_len))
{
case AF_INET:
new->vn_address.addr_family = AF_INET;
new->vn_address.addr.v4 = bi->attr->mp_nexthop_global_in;
break;
struct bgp_attr_encap_subtlv *pEncap;
case AF_INET6:
new->vn_address.addr_family = AF_INET6;
new->vn_address.addr.v6 = bi->attr->mp_nexthop_global;
break;
switch (BGP_MP_NEXTHOP_FAMILY (bi->attr->extra->mp_nexthop_len))
default:
zlog_warn ("%s: invalid vpn nexthop length: %d",
__func__, bi->attr->mp_nexthop_len);
rfapi_free_next_hop_list (new);
return NULL;
}
for (pEncap = bi->attr->vnc_subtlvs; pEncap;
pEncap = pEncap->next)
{
switch (pEncap->type)
{
case AF_INET:
new->vn_address.addr_family = AF_INET;
new->vn_address.addr.v4 = bi->attr->extra->mp_nexthop_global_in;
break;
case AF_INET6:
new->vn_address.addr_family = AF_INET6;
new->vn_address.addr.v6 = bi->attr->extra->mp_nexthop_global;
case BGP_VNC_SUBTLV_TYPE_LIFETIME:
/* use configured lifetime, not attr lifetime */
break;
default:
zlog_warn ("%s: invalid vpn nexthop length: %d",
__func__, bi->attr->extra->mp_nexthop_len);
rfapi_free_next_hop_list (new);
return NULL;
zlog_warn ("%s: unknown VNC option type %d",
__func__, pEncap->type);
break;
}
}
for (pEncap = bi->attr->extra->vnc_subtlvs; pEncap;
pEncap = pEncap->next)
rfapiGetTunnelType (bi->attr, &tun_type);
if (tun_type == BGP_ENCAP_TYPE_MPLS)
{
struct prefix p;
/* MPLS carries UN address in next hop */
rfapiNexthop2Prefix (bi->attr, &p);
if (p.family != 0)
{
switch (pEncap->type)
{
case BGP_VNC_SUBTLV_TYPE_LIFETIME:
/* use configured lifetime, not attr lifetime */
break;
default:
zlog_warn ("%s: unknown VNC option type %d",
__func__, pEncap->type);
break;
}
rfapiQprefix2Raddr(&p, &new->un_address);
have_vnc_tunnel_un = 1;
}
}
rfapiGetTunnelType (bi->attr, &tun_type);
if (tun_type == BGP_ENCAP_TYPE_MPLS)
for (pEncap = bi->attr->encap_subtlvs; pEncap;
pEncap = pEncap->next)
{
switch (pEncap->type)
{
struct prefix p;
/* MPLS carries UN address in next hop */
rfapiNexthop2Prefix (bi->attr, &p);
if (p.family != 0)
case BGP_ENCAP_SUBTLV_TYPE_REMOTE_ENDPOINT:
/*
* Overrides ENCAP UN address, if any
*/
switch (pEncap->length)
{
rfapiQprefix2Raddr(&p, &new->un_address);
case 8:
new->un_address.addr_family = AF_INET;
memcpy (&new->un_address.addr.v4, pEncap->value, 4);
have_vnc_tunnel_un = 1;
}
}
break;
for (pEncap = bi->attr->extra->encap_subtlvs; pEncap;
pEncap = pEncap->next)
{
switch (pEncap->type)
{
case BGP_ENCAP_SUBTLV_TYPE_REMOTE_ENDPOINT:
/*
* Overrides ENCAP UN address, if any
*/
switch (pEncap->length)
{
case 8:
new->un_address.addr_family = AF_INET;
memcpy (&new->un_address.addr.v4, pEncap->value, 4);
have_vnc_tunnel_un = 1;
break;
case 20:
new->un_address.addr_family = AF_INET6;
memcpy (&new->un_address.addr.v6, pEncap->value, 16);
have_vnc_tunnel_un = 1;
break;
default:
zlog_warn
("%s: invalid tunnel subtlv UN addr length (%d) for bi %p",
__func__, pEncap->length, bi);
}
case 20:
new->un_address.addr_family = AF_INET6;
memcpy (&new->un_address.addr.v6, pEncap->value, 16);
have_vnc_tunnel_un = 1;
break;
default:
zlog_warn ("%s: unknown Encap Attribute option type %d",
__func__, pEncap->type);
break;
zlog_warn
("%s: invalid tunnel subtlv UN addr length (%d) for bi %p",
__func__, pEncap->length, bi);
}
}
break;
new->un_options = rfapi_encap_tlv_to_un_option (bi->attr);
default:
zlog_warn ("%s: unknown Encap Attribute option type %d",
__func__, pEncap->type);
break;
}
}
new->un_options = rfapi_encap_tlv_to_un_option (bi->attr);
#if DEBUG_ENCAP_MONITOR
vnc_zlog_debug_verbose ("%s: line %d: have_vnc_tunnel_un=%d",
__func__, __LINE__, have_vnc_tunnel_un);
vnc_zlog_debug_verbose ("%s: line %d: have_vnc_tunnel_un=%d",
__func__, __LINE__, have_vnc_tunnel_un);
#endif
if (!have_vnc_tunnel_un && bi && bi->extra)
if (!have_vnc_tunnel_un && bi && bi->extra)
{
/*
* use cached UN address from ENCAP route
*/
new->un_address.addr_family = bi->extra->vnc.import.un_family;
switch (new->un_address.addr_family)
{
/*
* use cached UN address from ENCAP route
*/
new->un_address.addr_family = bi->extra->vnc.import.un_family;
switch (new->un_address.addr_family)
{
case AF_INET:
new->un_address.addr.v4 = bi->extra->vnc.import.un.addr4;
break;
case AF_INET6:
new->un_address.addr.v6 = bi->extra->vnc.import.un.addr6;
break;
default:
zlog_warn ("%s: invalid UN addr family (%d) for bi %p",
__func__, new->un_address.addr_family, bi);
rfapi_free_next_hop_list (new);
return NULL;
break;
}
case AF_INET:
new->un_address.addr.v4 = bi->extra->vnc.import.un.addr4;
break;
case AF_INET6:
new->un_address.addr.v6 = bi->extra->vnc.import.un.addr6;
break;
default:
zlog_warn ("%s: invalid UN addr family (%d) for bi %p",
__func__, new->un_address.addr_family, bi);
rfapi_free_next_hop_list (new);
return NULL;
break;
}
}
}
new->lifetime = lifetime;
return new;
}
@ -2121,6 +2114,8 @@ rfapiBgpInfoAttachSorted (
struct bgp *bgp;
struct bgp_info *prev;
struct bgp_info *next;
char pfx_buf[PREFIX2STR_BUFFER];
bgp = bgp_get_default (); /* assume 1 instance for now */
@ -2136,7 +2131,7 @@ rfapiBgpInfoAttachSorted (
if (!bgp ||
(!CHECK_FLAG (info_new->flags, BGP_INFO_REMOVED) &&
CHECK_FLAG (next->flags, BGP_INFO_REMOVED)) ||
bgp_info_cmp_compatible (bgp, info_new, next, afi, safi) == -1)
bgp_info_cmp_compatible (bgp, info_new, next, pfx_buf, afi, safi) == -1)
{ /* -1 if 1st is better */
break;
}
@ -2700,19 +2695,18 @@ rfapiNexthop2Prefix (struct attr *attr, struct prefix *p)
{
assert (p);
assert (attr);
assert (attr->extra);
memset (p, 0, sizeof (struct prefix));
switch (p->family = BGP_MP_NEXTHOP_FAMILY (attr->extra->mp_nexthop_len))
switch (p->family = BGP_MP_NEXTHOP_FAMILY (attr->mp_nexthop_len))
{
case AF_INET:
p->u.prefix4 = attr->extra->mp_nexthop_global_in;
p->u.prefix4 = attr->mp_nexthop_global_in;
p->prefixlen = 32;
break;
case AF_INET6:
p->u.prefix6 = attr->extra->mp_nexthop_global;
p->u.prefix6 = attr->mp_nexthop_global;
p->prefixlen = 128;
break;
@ -2777,9 +2771,7 @@ rfapiAttrNexthopAddrDifferent (struct prefix *p1, struct prefix *p2)
static void
rfapiCopyUnEncap2VPN (struct bgp_info *encap_bi, struct bgp_info *vpn_bi)
{
struct attr_extra *attre;
if (!encap_bi->attr || !encap_bi->attr->extra)
if (!encap_bi->attr)
{
zlog_warn ("%s: no encap bi attr/extra, can't copy UN address",
__func__);
@ -2793,9 +2785,7 @@ rfapiCopyUnEncap2VPN (struct bgp_info *encap_bi, struct bgp_info *vpn_bi)
return;
}
attre = encap_bi->attr->extra;
switch (BGP_MP_NEXTHOP_FAMILY (attre->mp_nexthop_len))
switch (BGP_MP_NEXTHOP_FAMILY (encap_bi->attr->mp_nexthop_len))
{
case AF_INET:
@ -2809,17 +2799,17 @@ rfapiCopyUnEncap2VPN (struct bgp_info *encap_bi, struct bgp_info *vpn_bi)
}
vpn_bi->extra->vnc.import.un_family = AF_INET;
vpn_bi->extra->vnc.import.un.addr4 = attre->mp_nexthop_global_in;
vpn_bi->extra->vnc.import.un.addr4 = encap_bi->attr->mp_nexthop_global_in;
break;
case AF_INET6:
vpn_bi->extra->vnc.import.un_family = AF_INET6;
vpn_bi->extra->vnc.import.un.addr6 = attre->mp_nexthop_global;
vpn_bi->extra->vnc.import.un.addr6 = encap_bi->attr->mp_nexthop_global;
break;
default:
zlog_warn ("%s: invalid encap nexthop length: %d",
__func__, attre->mp_nexthop_len);
__func__, encap_bi->attr->mp_nexthop_len);
vpn_bi->extra->vnc.import.un_family = 0;
break;
}
@ -3100,21 +3090,21 @@ rfapiExpireEncapNow (
static int
rfapiGetNexthop (struct attr *attr, struct prefix *prefix)
{
switch (BGP_MP_NEXTHOP_FAMILY (attr->extra->mp_nexthop_len))
switch (BGP_MP_NEXTHOP_FAMILY (attr->mp_nexthop_len))
{
case AF_INET:
prefix->family = AF_INET;
prefix->prefixlen = 32;
prefix->u.prefix4 = attr->extra->mp_nexthop_global_in;
prefix->u.prefix4 = attr->mp_nexthop_global_in;
break;
case AF_INET6:
prefix->family = AF_INET6;
prefix->prefixlen = 128;
prefix->u.prefix6 = attr->extra->mp_nexthop_global;
prefix->u.prefix6 = attr->mp_nexthop_global;
break;
default:
vnc_zlog_debug_verbose ("%s: unknown attr->extra->mp_nexthop_len %d", __func__,
attr->extra->mp_nexthop_len);
vnc_zlog_debug_verbose ("%s: unknown attr->mp_nexthop_len %d", __func__,
attr->mp_nexthop_len);
return EINVAL;
}
return 0;
@ -3185,7 +3175,7 @@ rfapiBgpInfoFilteredImportEncap (
* On a withdraw, peer and RD are sufficient to determine if
* we should act.
*/
if (!attr || !attr->extra || !attr->extra->ecommunity)
if (!attr || !attr->ecommunity)
{
vnc_zlog_debug_verbose ("%s: attr, extra, or ecommunity missing, not importing",
@ -3193,7 +3183,7 @@ rfapiBgpInfoFilteredImportEncap (
return;
}
#if RFAPI_REQUIRE_ENCAP_BEEC
if (!rfapiEcommunitiesMatchBeec (attr->extra->ecommunity))
if (!rfapiEcommunitiesMatchBeec (attr->ecommunity))
{
vnc_zlog_debug_verbose ("%s: it=%p: no match for BGP Encapsulation ecommunity",
__func__, import_table);
@ -3201,7 +3191,7 @@ rfapiBgpInfoFilteredImportEncap (
}
#endif
if (!rfapiEcommunitiesIntersect (import_table->rt_import_list,
attr->extra->ecommunity))
attr->ecommunity))
{
vnc_zlog_debug_verbose ("%s: it=%p: no ecommunity intersection",
@ -3667,7 +3657,7 @@ rfapiBgpInfoFilteredImportVPN (
*/
if (action == FIF_ACTION_UPDATE)
{
if (!attr || !attr->extra || !attr->extra->ecommunity)
if (!attr || !attr->ecommunity)
{
vnc_zlog_debug_verbose ("%s: attr, extra, or ecommunity missing, not importing",
@ -3676,7 +3666,7 @@ rfapiBgpInfoFilteredImportVPN (
}
if ((import_table != bgp->rfapi->it_ce) &&
!rfapiEcommunitiesIntersect (import_table->rt_import_list,
attr->extra->ecommunity))
attr->ecommunity))
{
vnc_zlog_debug_verbose ("%s: it=%p: no ecommunity intersection",
@ -4160,12 +4150,12 @@ rfapiProcessUpdate (
* Find rt containing LNI (Logical Network ID), which
* _should_ always be present when mac address is present
*/
rc = rfapiEcommunityGetLNI (attr->extra->ecommunity, &lni);
rc = rfapiEcommunityGetLNI (attr->ecommunity, &lni);
vnc_zlog_debug_verbose
("%s: rfapiEcommunityGetLNI returned %d, lni=%d, attr=%p, attr->extra=%p",
__func__, rc, lni, attr, attr->extra);
if (attr && attr->extra && !rc)
("%s: rfapiEcommunityGetLNI returned %d, lni=%d, attr=%p",
__func__, rc, lni, attr);
if (attr && !rc)
{
it = rfapiMacImportTableGet (bgp, lni);

View File

@ -664,7 +664,7 @@ rfapiRibBi2Ri(
ri->lifetime = lifetime;
/* This loop based on rfapiRouteInfo2NextHopEntry() */
for (pEncap = bi->attr->extra->vnc_subtlvs; pEncap; pEncap = pEncap->next)
for (pEncap = bi->attr->vnc_subtlvs; pEncap; pEncap = pEncap->next)
{
struct bgp_tea_options *hop;
@ -723,11 +723,11 @@ rfapiRibBi2Ri(
memcpy (&vo->v.l2addr.macaddr, bi->extra->vnc.import.rd.val+2,
ETHER_ADDR_LEN);
if (bi->attr && bi->attr->extra)
if (bi->attr)
{
(void) rfapiEcommunityGetLNI (bi->attr->extra->ecommunity,
(void) rfapiEcommunityGetLNI (bi->attr->ecommunity,
&vo->v.l2addr.logical_net_id);
(void) rfapiEcommunityGetEthernetTag (bi->attr->extra->ecommunity,
(void) rfapiEcommunityGetEthernetTag (bi->attr->ecommunity,
&vo->v.l2addr.tag_id);
}

View File

@ -469,9 +469,9 @@ rfapi_vty_out_vncinfo (
}
}
if (bi->attr && bi->attr->extra && bi->attr->extra->ecommunity)
if (bi->attr && bi->attr->ecommunity)
{
s = ecommunity_ecom2str (bi->attr->extra->ecommunity,
s = ecommunity_ecom2str (bi->attr->ecommunity,
ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
vty_out (vty, " EC{%s}", s);
XFREE (MTYPE_ECOMMUNITY_STR, s);
@ -499,7 +499,6 @@ rfapiPrintAttrPtrs (void *stream, struct attr *attr)
void *out;
const char *vty_newline;
struct attr_extra *ae;
char buf[BUFSIZ];
if (rfapiStream2Vty (stream, &fp, &vty, &out, &vty_newline) == 0)
@ -518,15 +517,12 @@ rfapiPrintAttrPtrs (void *stream, struct attr *attr)
fp (out, " community=%p, refcnt=%d%s", attr->community,
(attr->community ? attr->community->refcnt : 0), HVTYNL);
if ((ae = attr->extra))
{
fp (out, " ecommunity=%p, refcnt=%d%s", ae->ecommunity,
(ae->ecommunity ? ae->ecommunity->refcnt : 0), HVTYNL);
fp (out, " cluster=%p, refcnt=%d%s", ae->cluster,
(ae->cluster ? ae->cluster->refcnt : 0), HVTYNL);
fp (out, " transit=%p, refcnt=%d%s", ae->transit,
(ae->transit ? ae->transit->refcnt : 0), HVTYNL);
}
fp (out, " ecommunity=%p, refcnt=%d%s", attr->ecommunity,
(attr->ecommunity ? attr->ecommunity->refcnt : 0), HVTYNL);
fp (out, " cluster=%p, refcnt=%d%s", attr->cluster,
(attr->cluster ? attr->cluster->refcnt : 0), HVTYNL);
fp (out, " transit=%p, refcnt=%d%s", attr->transit,
(attr->transit ? attr->transit->refcnt : 0), HVTYNL);
}
/*
@ -593,26 +589,26 @@ rfapiPrintBi (void *stream, struct bgp_info *bi)
* RFP option sizes (they are opaque values)
* extended communities (RTs)
*/
if (bi->attr && bi->attr->extra)
if (bi->attr)
{
uint32_t lifetime;
int printed_1st_gol = 0;
struct bgp_attr_encap_subtlv *pEncap;
struct prefix pfx_un;
int af = BGP_MP_NEXTHOP_FAMILY (bi->attr->extra->mp_nexthop_len);
int af = BGP_MP_NEXTHOP_FAMILY (bi->attr->mp_nexthop_len);
/* Nexthop */
if (af == AF_INET)
{
r = snprintf (p, REMAIN, "%s", inet_ntop (AF_INET,
&bi->attr->extra->mp_nexthop_global_in,
&bi->attr->mp_nexthop_global_in,
buf, BUFSIZ));
INCP;
}
else if (af == AF_INET6)
{
r = snprintf (p, REMAIN, "%s", inet_ntop (AF_INET6,
&bi->attr->extra->mp_nexthop_global,
&bi->attr->mp_nexthop_global,
buf, BUFSIZ));
INCP;
}
@ -650,7 +646,7 @@ rfapiPrintBi (void *stream, struct bgp_info *bi)
}
/* RFP option lengths */
for (pEncap = bi->attr->extra->vnc_subtlvs; pEncap;
for (pEncap = bi->attr->vnc_subtlvs; pEncap;
pEncap = pEncap->next)
{
@ -673,9 +669,9 @@ rfapiPrintBi (void *stream, struct bgp_info *bi)
}
/* RT list */
if (bi->attr->extra->ecommunity)
if (bi->attr->ecommunity)
{
s = ecommunity_ecom2str (bi->attr->extra->ecommunity,
s = ecommunity_ecom2str (bi->attr->ecommunity,
ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
r = snprintf (p, REMAIN, " %s", s);
INCP;
@ -704,9 +700,9 @@ rfapiPrintBi (void *stream, struct bgp_info *bi)
if (bi->attr)
{
if (bi->attr->extra)
if (bi->attr->weight)
{
r = snprintf (p, REMAIN, " W=%d", bi->attr->extra->weight);
r = snprintf (p, REMAIN, " W=%d", bi->attr->weight);
INCP;
}

View File

@ -74,7 +74,6 @@ encap_attr_export_ce (
*/
memset (new, 0, sizeof (struct attr));
bgp_attr_dup (new, orig);
bgp_attr_extra_get (new);
/*
* Set nexthop
@ -83,17 +82,13 @@ encap_attr_export_ce (
{
case AF_INET:
new->nexthop = use_nexthop->u.prefix4;
new->extra->mp_nexthop_len = 4; /* bytes */
new->mp_nexthop_len = 4; /* bytes */
new->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
break;
case AF_INET6:
if (!new->extra)
{
new->extra = XCALLOC (MTYPE_ATTR_EXTRA, sizeof (struct attr_extra));
}
new->extra->mp_nexthop_global = use_nexthop->u.prefix6;
new->extra->mp_nexthop_len = 16; /* bytes */
new->mp_nexthop_global = use_nexthop->u.prefix6;
new->mp_nexthop_len = 16; /* bytes */
break;
default:
@ -133,7 +128,6 @@ encap_attr_export_ce (
*
* Caller should, after using the attr, call:
* - bgp_attr_flush() to free non-interned parts
* - call bgp_attr_extra_free() to free extra
*/
}
@ -144,8 +138,8 @@ getce (struct bgp *bgp, struct attr *attr, struct prefix *pfx_ce)
int i;
uint16_t localadmin = bgp->rfapi_cfg->resolve_nve_roo_local_admin;
for (ecp = attr->extra->ecommunity->val, i = 0;
i < attr->extra->ecommunity->size; ++i, ecp += ECOMMUNITY_SIZE)
for (ecp = attr->ecommunity->val, i = 0;
i < attr->ecommunity->size; ++i, ecp += ECOMMUNITY_SIZE)
{
if (VNC_DEBUG(EXPORT_BGP_GETCE))
@ -309,14 +303,12 @@ vnc_direct_bgp_add_route_ce (
if (ret == RMAP_DENYMATCH)
{
bgp_attr_flush (&hattr);
bgp_attr_extra_free (&hattr);
return;
}
}
iattr = bgp_attr_intern (&hattr);
bgp_attr_flush (&hattr);
bgp_attr_extra_free (&hattr);
/*
* Rule: disallow route-map alteration of next-hop, because it
@ -563,14 +555,14 @@ vnc_route_origin_ecom (struct route_node *rn)
struct ecommunity_val roec;
switch (BGP_MP_NEXTHOP_FAMILY (bi->attr->extra->mp_nexthop_len))
switch (BGP_MP_NEXTHOP_FAMILY (bi->attr->mp_nexthop_len))
{
case AF_INET:
memset (&roec, 0, sizeof (roec));
roec.val[0] = 0x01;
roec.val[1] = 0x03;
memcpy (roec.val + 2,
&bi->attr->extra->mp_nexthop_global_in.s_addr, 4);
&bi->attr->mp_nexthop_global_in.s_addr, 4);
roec.val[6] = 0;
roec.val[7] = 0;
ecommunity_add_val (new, &roec);
@ -642,16 +634,16 @@ encap_attr_export (
{
use_nexthop = &orig_nexthop;
orig_nexthop.family =
BGP_MP_NEXTHOP_FAMILY (orig->extra->mp_nexthop_len);
BGP_MP_NEXTHOP_FAMILY (orig->mp_nexthop_len);
if (orig_nexthop.family == AF_INET)
{
orig_nexthop.prefixlen = 32;
orig_nexthop.u.prefix4 = orig->extra->mp_nexthop_global_in;
orig_nexthop.u.prefix4 = orig->mp_nexthop_global_in;
}
else if (orig_nexthop.family == AF_INET6)
{
orig_nexthop.prefixlen = 128;
orig_nexthop.u.prefix6 = orig->extra->mp_nexthop_global;
orig_nexthop.u.prefix6 = orig->mp_nexthop_global;
}
else
{
@ -673,17 +665,13 @@ encap_attr_export (
{
case AF_INET:
new->nexthop = use_nexthop->u.prefix4;
new->extra->mp_nexthop_len = 4; /* bytes */
new->mp_nexthop_len = 4; /* bytes */
new->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
break;
case AF_INET6:
if (!new->extra)
{
new->extra = XCALLOC (MTYPE_ATTR_EXTRA, sizeof (struct attr_extra));
}
new->extra->mp_nexthop_global = use_nexthop->u.prefix6;
new->extra->mp_nexthop_len = 16; /* bytes */
new->mp_nexthop_global = use_nexthop->u.prefix6;
new->mp_nexthop_len = 16; /* bytes */
break;
default:
@ -691,7 +679,6 @@ encap_attr_export (
break;
}
bgp_attr_extra_get (new);
if (rn)
{
ecom_ro = vnc_route_origin_ecom (rn);
@ -701,17 +688,14 @@ encap_attr_export (
/* TBD test/assert for IPv6 */
ecom_ro = vnc_route_origin_ecom_single (&use_nexthop->u.prefix4);
}
if (new->extra->ecommunity)
if (new->ecommunity)
{
if (ecom_ro)
{
new->extra->ecommunity =
ecommunity_merge (ecom_ro, new->extra->ecommunity);
}
new->ecommunity = ecommunity_merge (ecom_ro, new->ecommunity);
}
else
{
new->extra->ecommunity = ecom_ro;
new->ecommunity = ecom_ro;
}
if (ecom_ro)
{
@ -750,7 +734,6 @@ encap_attr_export (
*
* Caller should, after using the attr, call:
* - bgp_attr_flush() to free non-interned parts
* - call bgp_attr_extra_free() to free extra
*/
return 0;
@ -887,7 +870,6 @@ vnc_direct_bgp_add_prefix (
if (ret == RMAP_DENYMATCH)
{
bgp_attr_flush (&hattr);
bgp_attr_extra_free (&hattr);
vnc_zlog_debug_verbose
("%s: route map says DENY, so not calling bgp_update",
__func__);
@ -903,7 +885,6 @@ vnc_direct_bgp_add_prefix (
iattr = bgp_attr_intern (&hattr);
bgp_attr_flush (&hattr);
bgp_attr_extra_free (&hattr);
bgp_update (irfd->peer, &rn->p, /* prefix */
0, /* addpath_id */
@ -917,7 +898,6 @@ vnc_direct_bgp_add_prefix (
}
aspath_unintern (&attr.aspath);
bgp_attr_extra_free (&attr);
}
/*
@ -1134,7 +1114,6 @@ vnc_direct_bgp_add_nve (struct bgp *bgp, struct rfapi_descriptor *rfd)
if (ret == RMAP_DENYMATCH)
{
bgp_attr_flush (&hattr);
bgp_attr_extra_free (&hattr);
continue;
}
@ -1142,7 +1121,6 @@ vnc_direct_bgp_add_nve (struct bgp *bgp, struct rfapi_descriptor *rfd)
iattr = bgp_attr_intern (&hattr);
bgp_attr_flush (&hattr);
bgp_attr_extra_free (&hattr);
bgp_update (irfd->peer, &rn->p, /* prefix */
0, /* addpath_id */
@ -1157,7 +1135,6 @@ vnc_direct_bgp_add_nve (struct bgp *bgp, struct rfapi_descriptor *rfd)
}
aspath_unintern (&attr.aspath);
bgp_attr_extra_free (&attr);
}
}
}
@ -1361,7 +1338,6 @@ vnc_direct_bgp_add_group_afi (
if (ret == RMAP_DENYMATCH)
{
bgp_attr_flush (&hattr);
bgp_attr_extra_free (&hattr);
continue;
}
@ -1369,7 +1345,6 @@ vnc_direct_bgp_add_group_afi (
iattr = bgp_attr_intern (&hattr);
bgp_attr_flush (&hattr);
bgp_attr_extra_free (&hattr);
bgp_update (irfd->peer, &rn->p, /* prefix */
0, /* addpath_id */
@ -1384,7 +1359,6 @@ vnc_direct_bgp_add_group_afi (
}
aspath_unintern (&attr.aspath);
bgp_attr_extra_free (&attr);
}
@ -1744,14 +1718,12 @@ vnc_direct_bgp_rh_add_route (
if (ret == RMAP_DENYMATCH)
{
bgp_attr_flush (&hattr);
bgp_attr_extra_free (&hattr);
return;
}
}
iattr = bgp_attr_intern (&hattr);
bgp_attr_flush (&hattr);
bgp_attr_extra_free (&hattr);
/*
* record route information that we will need to expire
@ -1983,7 +1955,6 @@ vnc_direct_bgp_rh_vpn_enable (struct bgp *bgp, afi_t afi)
if (ret == RMAP_DENYMATCH)
{
bgp_attr_flush (&hattr);
bgp_attr_extra_free (&hattr);
vnc_zlog_debug_verbose ("%s: route map says DENY", __func__);
continue;
}
@ -1991,7 +1962,6 @@ vnc_direct_bgp_rh_vpn_enable (struct bgp *bgp, afi_t afi)
iattr = bgp_attr_intern (&hattr);
bgp_attr_flush (&hattr);
bgp_attr_extra_free (&hattr);
/*
* record route information that we will need to expire

View File

@ -393,7 +393,6 @@ process_unicast_route (
if (ret == RMAP_DENYMATCH)
{
bgp_attr_flush (&hattr);
bgp_attr_extra_free (&hattr);
vnc_zlog_debug_verbose ("%s: route map \"%s\" says DENY, returning", __func__,
rmap->name);
return -1;
@ -406,8 +405,8 @@ process_unicast_route (
*/
rfapiUnicastNexthop2Prefix (afi, &hattr, unicast_nexthop);
if (hattr.extra && hattr.extra->ecommunity)
*ecom = ecommunity_dup (hattr.extra->ecommunity);
if (hattr.ecommunity)
*ecom = ecommunity_dup (hattr.ecommunity);
else
*ecom = ecommunity_new ();
@ -415,7 +414,6 @@ process_unicast_route (
* Done with hattr, clean up
*/
bgp_attr_flush (&hattr);
bgp_attr_extra_free (&hattr);
/*
* Add EC that carries original NH of iBGP route (2 bytes = magic
@ -510,18 +508,18 @@ vnc_import_bgp_add_route_mode_resolve_nve_one_bi (
plifetime = &lifetime;
}
if (bi->attr && bi->attr->extra)
if (bi->attr)
{
encaptlvs = bi->attr->extra->vnc_subtlvs;
if (bi->attr->extra->encap_tunneltype != BGP_ENCAP_TYPE_RESERVED &&
bi->attr->extra->encap_tunneltype != BGP_ENCAP_TYPE_MPLS)
encaptlvs = bi->attr->vnc_subtlvs;
if (bi->attr->encap_tunneltype != BGP_ENCAP_TYPE_RESERVED &&
bi->attr->encap_tunneltype != BGP_ENCAP_TYPE_MPLS)
{
if (opt != NULL)
opt->next = &optary[cur_opt];
opt = &optary[cur_opt++];
memset (opt, 0, sizeof (struct rfapi_un_option));
opt->type = RFAPI_UN_OPTION_TYPE_TUNNELTYPE;
opt->v.tunnel.type = bi->attr->extra->encap_tunneltype;
opt->v.tunnel.type = bi->attr->encap_tunneltype;
/* TBD parse bi->attr->extra->encap_subtlvs */
}
}
@ -532,8 +530,8 @@ vnc_import_bgp_add_route_mode_resolve_nve_one_bi (
struct ecommunity *new_ecom = ecommunity_dup (ecom);
if (bi->attr && bi->attr->extra && bi->attr->extra->ecommunity)
ecommunity_merge (new_ecom, bi->attr->extra->ecommunity);
if (bi->attr && bi->attr->ecommunity)
ecommunity_merge (new_ecom, bi->attr->ecommunity);
if (bi->extra)
label = decode_label (&bi->extra->label);
@ -891,7 +889,6 @@ vnc_import_bgp_add_route_mode_plain (struct bgp *bgp,
if (ret == RMAP_DENYMATCH)
{
bgp_attr_flush (&hattr);
bgp_attr_extra_free (&hattr);
vnc_zlog_debug_verbose ("%s: route map \"%s\" says DENY, returning", __func__,
rmap->name);
return;
@ -900,7 +897,6 @@ vnc_import_bgp_add_route_mode_plain (struct bgp *bgp,
iattr = bgp_attr_intern (&hattr);
bgp_attr_flush (&hattr);
bgp_attr_extra_free (&hattr);
/* Now iattr is an allocated interned attr */
@ -925,8 +921,8 @@ vnc_import_bgp_add_route_mode_plain (struct bgp *bgp,
memset (&prd, 0, sizeof (prd));
rfapi_set_autord_from_vn (&prd, &vnaddr);
if (iattr && iattr->extra && iattr->extra->ecommunity)
ecom = ecommunity_dup (iattr->extra->ecommunity);
if (iattr && iattr->ecommunity)
ecom = ecommunity_dup (iattr->ecommunity);
}
@ -1103,7 +1099,6 @@ vnc_import_bgp_add_route_mode_nvegroup (struct bgp *bgp,
if (ret == RMAP_DENYMATCH)
{
bgp_attr_flush (&hattr);
bgp_attr_extra_free (&hattr);
vnc_zlog_debug_verbose ("%s: route map \"%s\" says DENY, returning", __func__,
rmap->name);
return;
@ -1112,7 +1107,6 @@ vnc_import_bgp_add_route_mode_nvegroup (struct bgp *bgp,
iattr = bgp_attr_intern (&hattr);
bgp_attr_flush (&hattr);
bgp_attr_extra_free (&hattr);
/* Now iattr is an allocated interned attr */
@ -1139,8 +1133,8 @@ vnc_import_bgp_add_route_mode_nvegroup (struct bgp *bgp,
else
ecom = ecommunity_new ();
if (iattr && iattr->extra && iattr->extra->ecommunity)
ecom = ecommunity_merge (ecom, iattr->extra->ecommunity);
if (iattr && iattr->ecommunity)
ecom = ecommunity_merge (ecom, iattr->ecommunity);
}
local_pref = calc_local_pref (iattr, peer);
@ -1942,7 +1936,6 @@ vnc_import_bgp_exterior_add_route_it (
ZEBRA_ROUTE_BGP_DIRECT_EXT,
BGP_ROUTE_REDISTRIBUTE, &label);
bgp_attr_extra_free (&new_attr);
}
if (have_usable_route)
@ -2273,7 +2266,6 @@ vnc_import_bgp_exterior_add_route_interior (
ZEBRA_ROUTE_BGP_DIRECT_EXT,
BGP_ROUTE_REDISTRIBUTE, &label);
bgp_attr_extra_free (&new_attr);
}
vnc_zlog_debug_verbose
("%s: finished constructing exteriors based on existing monitors",
@ -2412,7 +2404,6 @@ vnc_import_bgp_exterior_add_route_interior (
ZEBRA_ROUTE_BGP_DIRECT_EXT,
BGP_ROUTE_REDISTRIBUTE, &label);
bgp_attr_extra_free (&new_attr);
}
}
@ -2536,7 +2527,6 @@ vnc_import_bgp_exterior_add_route_interior (
ZEBRA_ROUTE_BGP_DIRECT_EXT,
BGP_ROUTE_REDISTRIBUTE, &label);
bgp_attr_extra_free (&new_attr);
}
}
if (list_adopted)
@ -2740,7 +2730,6 @@ vnc_import_bgp_exterior_del_route_interior (
ZEBRA_ROUTE_BGP_DIRECT_EXT,
BGP_ROUTE_REDISTRIBUTE, &label);
bgp_attr_extra_free (&new_attr);
}
}

View File

@ -909,6 +909,9 @@ node_parent ( enum node_type node )
case BGP_IPV6L_NODE:
ret = BGP_NODE;
break;
case BGP_EVPN_VNI_NODE:
ret = BGP_EVPN_NODE;
break;
case KEYCHAIN_KEY_NODE:
ret = KEYCHAIN_NODE;
break;
@ -1278,6 +1281,9 @@ cmd_exit (struct vty *vty)
case BGP_IPV6L_NODE:
vty->node = BGP_NODE;
break;
case BGP_EVPN_VNI_NODE:
vty->node = BGP_EVPN_NODE;
break;
case LDP_IPV4_NODE:
case LDP_IPV6_NODE:
vty->node = LDP_NODE;
@ -1346,6 +1352,7 @@ DEFUN (config_end,
case BGP_IPV6_NODE:
case BGP_IPV6M_NODE:
case BGP_EVPN_NODE:
case BGP_EVPN_VNI_NODE:
case BGP_IPV6L_NODE:
case RMAP_NODE:
case OSPF_NODE:

View File

@ -136,6 +136,7 @@ enum node_type
MPLS_NODE, /* MPLS config node */
VTY_NODE, /* Vty node. */
LINK_PARAMS_NODE, /* Link-parameters node */
BGP_EVPN_VNI_NODE, /* BGP EVPN VNI */
};
/* Node which has some commands and prompt string and configuration

View File

@ -946,6 +946,15 @@ static const struct zebra_desc_table command_types[] = {
DESC_ENTRY (ZEBRA_LABEL_MANAGER_CONNECT),
DESC_ENTRY (ZEBRA_GET_LABEL_CHUNK),
DESC_ENTRY (ZEBRA_RELEASE_LABEL_CHUNK),
DESC_ENTRY (ZEBRA_ADVERTISE_ALL_VNI),
DESC_ENTRY (ZEBRA_VNI_ADD),
DESC_ENTRY (ZEBRA_VNI_DEL),
DESC_ENTRY (ZEBRA_REMOTE_VTEP_ADD),
DESC_ENTRY (ZEBRA_REMOTE_VTEP_DEL),
DESC_ENTRY (ZEBRA_MACIP_ADD),
DESC_ENTRY (ZEBRA_MACIP_DEL),
DESC_ENTRY (ZEBRA_REMOTE_MACIP_ADD),
DESC_ENTRY (ZEBRA_REMOTE_MACIP_DEL),
};
#undef DESC_ENTRY

View File

@ -768,6 +768,7 @@ vty_end_config (struct vty *vty)
case MASC_NODE:
case PIM_NODE:
case VTY_NODE:
case BGP_EVPN_VNI_NODE:
vty_config_unlock (vty);
vty->node = ENABLE_NODE;
break;

View File

@ -2047,6 +2047,22 @@ zclient_read (struct thread *thread)
if (zclient->fec_update)
(*zclient->fec_update) (command, zclient, length);
break;
case ZEBRA_VNI_ADD:
if (zclient->local_vni_add)
(*zclient->local_vni_add) (command, zclient, length, vrf_id);
break;
case ZEBRA_VNI_DEL:
if (zclient->local_vni_del)
(*zclient->local_vni_del) (command, zclient, length, vrf_id);
break;
case ZEBRA_MACIP_ADD:
if (zclient->local_macip_add)
(*zclient->local_macip_add) (command, zclient, length, vrf_id);
break;
case ZEBRA_MACIP_DEL:
if (zclient->local_macip_del)
(*zclient->local_macip_del) (command, zclient, length, vrf_id);
break;
default:
break;
}

View File

@ -96,6 +96,15 @@ typedef enum {
ZEBRA_FEC_REGISTER,
ZEBRA_FEC_UNREGISTER,
ZEBRA_FEC_UPDATE,
ZEBRA_ADVERTISE_ALL_VNI,
ZEBRA_VNI_ADD,
ZEBRA_VNI_DEL,
ZEBRA_REMOTE_VTEP_ADD,
ZEBRA_REMOTE_VTEP_DEL,
ZEBRA_MACIP_ADD,
ZEBRA_MACIP_DEL,
ZEBRA_REMOTE_MACIP_ADD,
ZEBRA_REMOTE_MACIP_DEL,
} zebra_message_types_t;
struct redist_proto
@ -167,6 +176,10 @@ struct zclient
int (*redistribute_route_ipv6_add) (int, struct zclient *, uint16_t, vrf_id_t);
int (*redistribute_route_ipv6_del) (int, struct zclient *, uint16_t, vrf_id_t);
int (*fec_update) (int, struct zclient *, uint16_t);
int (*local_vni_add) (int, struct zclient *, uint16_t, vrf_id_t);
int (*local_vni_del) (int, struct zclient *, uint16_t, vrf_id_t);
int (*local_macip_add) (int, struct zclient *, uint16_t, vrf_id_t);
int (*local_macip_del) (int, struct zclient *, uint16_t, vrf_id_t);
};
/* Zebra API message flag. */

View File

@ -314,6 +314,10 @@ vtysh_execute_func (const char *line, int pager)
{
vtysh_execute("exit-address-family");
}
else if ((saved_node == BGP_EVPN_VNI_NODE) && (tried == 1))
{
vtysh_execute("exit-vni");
}
else if (saved_node == BGP_VRF_POLICY_NODE && (tried == 1))
{
vtysh_execute("exit-vrf-policy");
@ -576,6 +580,10 @@ vtysh_mark_file (const char *filename)
{
fprintf(stdout, "exit-address-family\n");
}
else if ((prev_node == BGP_EVPN_VNI_NODE) && (tried == 1))
{
fprintf(stdout, "exit-vni\n");
}
else if ((prev_node == KEYCHAIN_KEY_NODE) && (tried == 1))
{
fprintf(stdout, "exit\n");
@ -989,6 +997,12 @@ static struct cmd_node bgp_evpn_node =
"%s(config-router-af)# "
};
static struct cmd_node bgp_evpn_vni_node =
{
BGP_EVPN_VNI_NODE,
"%s(config-router-af-vni)# "
};
static struct cmd_node bgp_ipv6l_node =
{
BGP_IPV6L_NODE,
@ -1275,14 +1289,38 @@ DEFUNSH (VTYSH_BGPD,
address_family_evpn,
address_family_evpn_cmd,
"address-family <l2vpn evpn>",
"Enter Address Family command mode\n"
"Address Family\n"
"Address Family modifier\n")
"Enter Address Family command mode\n"
"Address Family\n"
"Address Family modifier\n")
{
vty->node = BGP_EVPN_NODE;
return CMD_SUCCESS;
}
#if defined (HAVE_CUMULUS)
DEFUNSH (VTYSH_BGPD,
address_family_evpn2,
address_family_evpn2_cmd,
"address-family evpn",
"Enter Address Family command mode\n"
"EVPN Address family\n")
{
vty->node = BGP_EVPN_NODE;
return CMD_SUCCESS;
}
#endif
DEFUNSH (VTYSH_BGPD,
bgp_evpn_vni,
bgp_evpn_vni_cmd,
"vni (1-16777215)",
"VXLAN Network Identifier\n"
"VNI number\n")
{
vty->node = BGP_EVPN_VNI_NODE;
return CMD_SUCCESS;
}
#if defined (ENABLE_BGP_VNC)
DEFUNSH (VTYSH_BGPD,
vnc_defaults,
@ -1622,6 +1660,9 @@ vtysh_exit (struct vty *vty)
case BGP_VNC_L2_GROUP_NODE:
vty->node = BGP_NODE;
break;
case BGP_EVPN_VNI_NODE:
vty->node = BGP_EVPN_NODE;
break;
case LDP_IPV4_NODE:
case LDP_IPV6_NODE:
vty->node = LDP_NODE;
@ -1678,11 +1719,23 @@ DEFUNSH (VTYSH_BGPD,
|| vty->node == BGP_VPNV6_NODE
|| vty->node == BGP_IPV6_NODE
|| vty->node == BGP_IPV6L_NODE
|| vty->node == BGP_IPV6M_NODE)
|| vty->node == BGP_IPV6M_NODE
|| vty->node == BGP_EVPN_NODE)
vty->node = BGP_NODE;
return CMD_SUCCESS;
}
DEFUNSH (VTYSH_BGPD,
exit_vni,
exit_vni_cmd,
"exit-vni",
"Exit from VNI mode\n")
{
if (vty->node == BGP_EVPN_VNI_NODE)
vty->node = BGP_EVPN_NODE;
return CMD_SUCCESS;
}
DEFUNSH (VTYSH_BGPD,
exit_vnc_config,
exit_vnc_config_cmd,
@ -3289,6 +3342,7 @@ vtysh_init_vty (void)
install_node (&bgp_ipv6l_node, NULL);
install_node (&bgp_vrf_policy_node, NULL);
install_node (&bgp_evpn_node, NULL);
install_node (&bgp_evpn_vni_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);
@ -3327,6 +3381,7 @@ vtysh_init_vty (void)
vtysh_install_default (BGP_IPV6_NODE);
vtysh_install_default (BGP_IPV6M_NODE);
vtysh_install_default (BGP_EVPN_NODE);
vtysh_install_default (BGP_EVPN_VNI_NODE);
vtysh_install_default (BGP_IPV6L_NODE);
#if ENABLE_BGP_VNC
vtysh_install_default (BGP_VRF_POLICY_NODE);
@ -3405,6 +3460,9 @@ vtysh_init_vty (void)
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);
install_element (BGP_EVPN_NODE, &vtysh_exit_bgpd_cmd);
install_element (BGP_EVPN_VNI_NODE, &vtysh_exit_bgpd_cmd);
install_element (BGP_EVPN_VNI_NODE, &vtysh_quit_bgpd_cmd);
install_element (BGP_IPV6L_NODE, &vtysh_exit_bgpd_cmd);
install_element (BGP_IPV6L_NODE, &vtysh_quit_bgpd_cmd);
#if defined (ENABLE_BGP_VNC)
@ -3455,6 +3513,7 @@ vtysh_init_vty (void)
install_element (BGP_IPV6L_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_EVPN_VNI_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);
@ -3517,6 +3576,9 @@ vtysh_init_vty (void)
install_element (BGP_NODE, &address_family_ipv6_vpn_cmd);
install_element (BGP_NODE, &address_family_ipv6_labeled_unicast_cmd);
install_element (BGP_NODE, &address_family_evpn_cmd);
#if defined (HAVE_CUMULUS)
install_element (BGP_NODE, &address_family_evpn2_cmd);
#endif
install_element (BGP_VPNV4_NODE, &exit_address_family_cmd);
install_element (BGP_VPNV6_NODE, &exit_address_family_cmd);
install_element (BGP_IPV4_NODE, &exit_address_family_cmd);
@ -3527,6 +3589,10 @@ vtysh_init_vty (void)
install_element (BGP_EVPN_NODE, &exit_address_family_cmd);
install_element (BGP_IPV6L_NODE, &exit_address_family_cmd);
/* EVPN commands */
install_element (BGP_EVPN_NODE, &bgp_evpn_vni_cmd);
install_element (BGP_EVPN_VNI_NODE, &exit_vni_cmd);
install_element (BGP_VRF_POLICY_NODE, &exit_vrf_policy_cmd);
install_element (BGP_VNC_DEFAULTS_NODE, &exit_vnc_config_cmd);
install_element (BGP_VNC_NVE_GROUP_NODE, &exit_vnc_config_cmd);

View File

@ -33,6 +33,8 @@ zebra_SOURCES = \
zebra_ns.c zebra_vrf.c zebra_static.c zebra_mpls.c zebra_mpls_vty.c \
zebra_mroute.c \
label_manager.c \
zebra_l2.c \
zebra_vxlan.c \
# end
noinst_HEADERS = \
@ -42,7 +44,8 @@ noinst_HEADERS = \
rt_netlink.h zebra_fpm_private.h zebra_rnh.h \
zebra_ptm_redistribute.h zebra_ptm.h zebra_routemap.h \
zebra_ns.h zebra_vrf.h ioctl_solaris.h zebra_static.h zebra_mpls.h \
kernel_netlink.h if_netlink.h zebra_mroute.h label_manager.h
kernel_netlink.h if_netlink.h zebra_mroute.h label_manager.h \
zebra_l2.h zebra_vxlan_private.h zebra_vxlan.h
zebra_LDADD = $(otherobj) ../lib/libfrr.la $(LIBCAP)

View File

@ -31,6 +31,7 @@ unsigned long zebra_debug_rib;
unsigned long zebra_debug_fpm;
unsigned long zebra_debug_nht;
unsigned long zebra_debug_mpls;
unsigned long zebra_debug_vxlan;
DEFUN (show_debugging_zebra,
show_debugging_zebra_cmd,
@ -118,6 +119,17 @@ DEFUN (debug_zebra_mpls,
return CMD_WARNING_CONFIG_FAILED;
}
DEFUN (debug_zebra_vxlan,
debug_zebra_vxlan_cmd,
"debug zebra vxlan",
DEBUG_STR
"Zebra configuration\n"
"Debug option set for zebra VxLAN (EVPN)\n")
{
zebra_debug_vxlan = ZEBRA_DEBUG_VXLAN;
return CMD_WARNING;
}
DEFUN (debug_zebra_packet,
debug_zebra_packet_cmd,
"debug zebra packet [<recv|send>] [detail]",
@ -248,6 +260,18 @@ DEFUN (no_debug_zebra_mpls,
return CMD_SUCCESS;
}
DEFUN (no_debug_zebra_vxlan,
no_debug_zebra_vxlan_cmd,
"no debug zebra vxlan",
NO_STR
DEBUG_STR
"Zebra configuration\n"
"Debug option set for zebra VxLAN (EVPN)\n")
{
zebra_debug_vxlan = 0;
return CMD_SUCCESS;
}
DEFUN (no_debug_zebra_packet,
no_debug_zebra_packet_cmd,
"no debug zebra packet [<recv|send>]",
@ -413,6 +437,11 @@ config_write_debug (struct vty *vty)
vty_out (vty, "debug zebra mpls\n");
write++;
}
if (IS_ZEBRA_DEBUG_VXLAN)
{
vty_out (vty, "debug zebra vxlan\n");
write++;
}
return write;
}
@ -425,6 +454,7 @@ zebra_debug_init (void)
zebra_debug_rib = 0;
zebra_debug_fpm = 0;
zebra_debug_mpls = 0;
zebra_debug_vxlan = 0;
install_node (&debug_node, config_write_debug);
@ -433,6 +463,7 @@ zebra_debug_init (void)
install_element (ENABLE_NODE, &debug_zebra_events_cmd);
install_element (ENABLE_NODE, &debug_zebra_nht_cmd);
install_element (ENABLE_NODE, &debug_zebra_mpls_cmd);
install_element (ENABLE_NODE, &debug_zebra_vxlan_cmd);
install_element (ENABLE_NODE, &debug_zebra_packet_cmd);
install_element (ENABLE_NODE, &debug_zebra_kernel_cmd);
install_element (ENABLE_NODE, &debug_zebra_kernel_msgdump_cmd);
@ -442,6 +473,7 @@ zebra_debug_init (void)
install_element (ENABLE_NODE, &no_debug_zebra_events_cmd);
install_element (ENABLE_NODE, &no_debug_zebra_nht_cmd);
install_element (ENABLE_NODE, &no_debug_zebra_mpls_cmd);
install_element (ENABLE_NODE, &no_debug_zebra_vxlan_cmd);
install_element (ENABLE_NODE, &no_debug_zebra_packet_cmd);
install_element (ENABLE_NODE, &no_debug_zebra_kernel_cmd);
install_element (ENABLE_NODE, &no_debug_zebra_kernel_msgdump_cmd);
@ -452,6 +484,7 @@ zebra_debug_init (void)
install_element (CONFIG_NODE, &debug_zebra_events_cmd);
install_element (CONFIG_NODE, &debug_zebra_nht_cmd);
install_element (CONFIG_NODE, &debug_zebra_mpls_cmd);
install_element (CONFIG_NODE, &debug_zebra_vxlan_cmd);
install_element (CONFIG_NODE, &debug_zebra_packet_cmd);
install_element (CONFIG_NODE, &debug_zebra_kernel_cmd);
install_element (CONFIG_NODE, &debug_zebra_kernel_msgdump_cmd);
@ -461,6 +494,7 @@ zebra_debug_init (void)
install_element (CONFIG_NODE, &no_debug_zebra_events_cmd);
install_element (CONFIG_NODE, &no_debug_zebra_nht_cmd);
install_element (CONFIG_NODE, &no_debug_zebra_mpls_cmd);
install_element (CONFIG_NODE, &no_debug_zebra_vxlan_cmd);
install_element (CONFIG_NODE, &no_debug_zebra_packet_cmd);
install_element (CONFIG_NODE, &no_debug_zebra_kernel_cmd);
install_element (CONFIG_NODE, &no_debug_zebra_kernel_msgdump_cmd);

View File

@ -42,6 +42,8 @@
#define ZEBRA_DEBUG_MPLS 0x01
#define ZEBRA_DEBUG_VXLAN 0x01
/* Debug related macro. */
#define IS_ZEBRA_DEBUG_EVENT (zebra_debug_event & ZEBRA_DEBUG_EVENT)
@ -63,6 +65,7 @@
#define IS_ZEBRA_DEBUG_FPM (zebra_debug_fpm & ZEBRA_DEBUG_FPM)
#define IS_ZEBRA_DEBUG_NHT (zebra_debug_nht & ZEBRA_DEBUG_NHT)
#define IS_ZEBRA_DEBUG_MPLS (zebra_debug_mpls & ZEBRA_DEBUG_MPLS)
#define IS_ZEBRA_DEBUG_VXLAN (zebra_debug_vxlan & ZEBRA_DEBUG_VXLAN)
extern unsigned long zebra_debug_event;
extern unsigned long zebra_debug_packet;
@ -71,6 +74,7 @@ extern unsigned long zebra_debug_rib;
extern unsigned long zebra_debug_fpm;
extern unsigned long zebra_debug_nht;
extern unsigned long zebra_debug_mpls;
extern unsigned long zebra_debug_vxlan;
extern void zebra_debug_init (void);

View File

@ -20,6 +20,15 @@
*/
#include <zebra.h>
/* The following definition is to workaround an issue in the Linux kernel
* header files with redefinition of 'struct in6_addr' in both
* netinet/in.h and linux/in6.h.
* Reference - https://sourceware.org/ml/libc-alpha/2013-01/msg00599.html
*/
#define _LINUX_IN6_H
#include <linux/if_bridge.h>
#include <net/if_arp.h>
#include <linux/sockios.h>
#include <linux/ethtool.h>
@ -175,6 +184,23 @@ netlink_to_zebra_link_type (unsigned int hwt)
}
}
static void
netlink_determine_zebra_iftype (char *kind, zebra_iftype_t *zif_type)
{
*zif_type = ZEBRA_IF_OTHER;
if (!kind)
return;
if (strcmp(kind, "vrf") == 0)
*zif_type = ZEBRA_IF_VRF;
else if (strcmp(kind, "bridge") == 0)
*zif_type = ZEBRA_IF_BRIDGE;
else if (strcmp(kind, "vlan") == 0)
*zif_type = ZEBRA_IF_VLAN;
else if (strcmp(kind, "vxlan") == 0)
*zif_type = ZEBRA_IF_VXLAN;
}
//Temporary Assignments to compile on older platforms.
#ifndef IFLA_BR_MAX
@ -341,6 +367,173 @@ get_iflink_speed (const char *ifname)
return (ecmd.speed_hi << 16 ) | ecmd.speed;
}
static int
netlink_extract_bridge_info (struct rtattr *link_data,
struct zebra_l2info_bridge *bridge_info)
{
struct rtattr *attr[IFLA_BR_MAX+1];
memset (bridge_info, 0, sizeof (*bridge_info));
memset (attr, 0, sizeof attr);
parse_rtattr_nested(attr, IFLA_BR_MAX, link_data);
if (attr[IFLA_BR_VLAN_FILTERING])
bridge_info->vlan_aware = *(u_char *)RTA_DATA(attr[IFLA_BR_VLAN_FILTERING]);
return 0;
}
static int
netlink_extract_vlan_info (struct rtattr *link_data,
struct zebra_l2info_vlan *vlan_info)
{
struct rtattr *attr[IFLA_VLAN_MAX+1];
vlanid_t vid_in_msg;
memset (vlan_info, 0, sizeof (*vlan_info));
memset (attr, 0, sizeof attr);
parse_rtattr_nested(attr, IFLA_VLAN_MAX, link_data);
if (!attr[IFLA_VLAN_ID])
{
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug ("IFLA_VLAN_ID missing from VLAN IF message");
return -1;
}
vid_in_msg = *(vlanid_t *)RTA_DATA(attr[IFLA_VLAN_ID]);
vlan_info->vid = vid_in_msg;
return 0;
}
static int
netlink_extract_vxlan_info (struct rtattr *link_data,
struct zebra_l2info_vxlan *vxl_info)
{
struct rtattr *attr[IFLA_VXLAN_MAX+1];
vni_t vni_in_msg;
struct in_addr vtep_ip_in_msg;
memset (vxl_info, 0, sizeof (*vxl_info));
memset (attr, 0, sizeof attr);
parse_rtattr_nested(attr, IFLA_VXLAN_MAX, link_data);
if (!attr[IFLA_VXLAN_ID])
{
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug ("IFLA_VXLAN_ID missing from VXLAN IF message");
return -1;
}
vni_in_msg = *(vni_t *)RTA_DATA(attr[IFLA_VXLAN_ID]);
vxl_info->vni = vni_in_msg;
if (!attr[IFLA_VXLAN_LOCAL])
{
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug ("IFLA_VXLAN_LOCAL missing from VXLAN IF message");
}
else
{
vtep_ip_in_msg = *(struct in_addr *)RTA_DATA(attr[IFLA_VXLAN_LOCAL]);
vxl_info->vtep_ip = vtep_ip_in_msg;
}
return 0;
}
/*
* Extract and save L2 params (of interest) for an interface. When a
* bridge interface is added or updated, take further actions to map
* its members. Likewise, for VxLAN interface.
*/
static void
netlink_interface_update_l2info (struct interface *ifp,
struct rtattr *link_data,
int add)
{
if (!link_data)
return;
if (IS_ZEBRA_IF_BRIDGE(ifp))
{
struct zebra_l2info_bridge bridge_info;
netlink_extract_bridge_info (link_data, &bridge_info);
zebra_l2_bridge_add_update (ifp, &bridge_info, add);
}
else if (IS_ZEBRA_IF_VLAN(ifp))
{
struct zebra_l2info_vlan vlan_info;
netlink_extract_vlan_info (link_data, &vlan_info);
zebra_l2_vlanif_update (ifp, &vlan_info);
}
else if (IS_ZEBRA_IF_VXLAN(ifp))
{
struct zebra_l2info_vxlan vxlan_info;
netlink_extract_vxlan_info (link_data, &vxlan_info);
zebra_l2_vxlanif_add_update (ifp, &vxlan_info, add);
}
}
static int
netlink_bridge_interface (struct nlmsghdr *h, int len,
ns_id_t ns_id, int startup)
{
char *name = NULL;
struct ifinfomsg *ifi;
struct rtattr *tb[IFLA_MAX + 1];
struct interface *ifp;
struct rtattr *aftb[IFLA_BRIDGE_MAX + 1];
struct
{
u_int16_t flags;
u_int16_t vid;
} *vinfo;
vlanid_t access_vlan;
/* Fetch name and ifindex */
ifi = NLMSG_DATA (h);
memset (tb, 0, sizeof tb);
netlink_parse_rtattr (tb, IFLA_MAX, IFLA_RTA (ifi), len);
if (tb[IFLA_IFNAME] == NULL)
return -1;
name = (char *) RTA_DATA (tb[IFLA_IFNAME]);
/* The interface should already be known, if not discard. */
ifp = if_lookup_by_index_per_ns (zebra_ns_lookup (ns_id),
ifi->ifi_index);
if (!ifp)
{
zlog_warn ("Cannot find bridge IF %s(%u)",
name, ifi->ifi_index);
return 0;
}
if (!IS_ZEBRA_IF_VXLAN(ifp))
return 0;
/* We are only interested in the access VLAN i.e., AF_SPEC */
if (!tb[IFLA_AF_SPEC])
return 0;
/* There is a 1-to-1 mapping of VLAN to VxLAN - hence
* only 1 access VLAN is accepted.
*/
memset (aftb, 0, sizeof aftb);
parse_rtattr_nested(aftb, IFLA_BRIDGE_MAX, tb[IFLA_AF_SPEC]);
if (!aftb[IFLA_BRIDGE_VLAN_INFO])
return 0;
vinfo = RTA_DATA(aftb[IFLA_BRIDGE_VLAN_INFO]);
if (!(vinfo->flags & BRIDGE_VLAN_INFO_PVID))
return 0;
access_vlan = (vlanid_t) vinfo->vid;
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug ("Access VLAN %u for VxLAN IF %s(%u)",
access_vlan, name, ifi->ifi_index);
zebra_l2_vxlanif_update_access_vlan (ifp, access_vlan);
return 0;
}
/* Called from interface_lookup_netlink(). This function is only used
during bootstrap. */
static int
@ -355,9 +548,12 @@ netlink_interface (struct sockaddr_nl *snl, struct nlmsghdr *h,
char *name = NULL;
char *kind = NULL;
char *slave_kind = NULL;
int vrf_device = 0;
struct zebra_ns *zns;
vrf_id_t vrf_id = VRF_DEFAULT;
zebra_iftype_t zif_type = ZEBRA_IF_OTHER;
zebra_slave_iftype_t zif_slave_type = ZEBRA_IF_SLAVE_NONE;
ifindex_t bridge_ifindex = IFINDEX_INTERNAL;
ifindex_t link_ifindex = IFINDEX_INTERNAL;
zns = zebra_ns_lookup (ns_id);
ifi = NLMSG_DATA (h);
@ -369,11 +565,13 @@ netlink_interface (struct sockaddr_nl *snl, struct nlmsghdr *h,
if (len < 0)
return -1;
/* We are interested in some AF_BRIDGE notifications. */
if (ifi->ifi_family == AF_BRIDGE)
return 0;
return netlink_bridge_interface (h, len, ns_id, startup);
/* Looking up interface name. */
memset (tb, 0, sizeof tb);
memset (linkinfo, 0, sizeof linkinfo);
netlink_parse_rtattr (tb, IFLA_MAX, IFLA_RTA (ifi), len);
#ifdef IFLA_WIRELESS
@ -392,7 +590,6 @@ netlink_interface (struct sockaddr_nl *snl, struct nlmsghdr *h,
if (tb[IFLA_LINKINFO])
{
memset (linkinfo, 0, sizeof linkinfo);
parse_rtattr_nested(linkinfo, IFLA_INFO_MAX, tb[IFLA_LINKINFO]);
if (linkinfo[IFLA_INFO_KIND])
@ -403,37 +600,64 @@ netlink_interface (struct sockaddr_nl *snl, struct nlmsghdr *h,
slave_kind = RTA_DATA(linkinfo[IFLA_INFO_SLAVE_KIND]);
#endif
if (kind && strcmp(kind, "vrf") == 0)
{
vrf_device = 1;
netlink_vrf_change(h, tb[IFLA_LINKINFO], name);
vrf_id = (vrf_id_t)ifi->ifi_index;
}
netlink_determine_zebra_iftype (kind, &zif_type);
}
/* If VRF, create the VRF structure itself. */
if (zif_type == ZEBRA_IF_VRF)
{
netlink_vrf_change(h, tb[IFLA_LINKINFO], name);
vrf_id = (vrf_id_t)ifi->ifi_index;
}
if (tb[IFLA_MASTER])
{
if (slave_kind && (strcmp(slave_kind, "vrf") == 0))
vrf_id = *(u_int32_t *)RTA_DATA(tb[IFLA_MASTER]);
{
zif_slave_type = ZEBRA_IF_SLAVE_VRF;
vrf_id = *(u_int32_t *)RTA_DATA(tb[IFLA_MASTER]);
}
else if (slave_kind && (strcmp(slave_kind, "bridge") == 0))
{
zif_slave_type = ZEBRA_IF_SLAVE_BRIDGE;
bridge_ifindex = *(ifindex_t *)RTA_DATA(tb[IFLA_MASTER]);
}
else
zif_slave_type = ZEBRA_IF_SLAVE_OTHER;
}
/* If linking to another interface, note it. */
if (tb[IFLA_LINK])
link_ifindex = *(ifindex_t *)RTA_DATA(tb[IFLA_LINK]);
/* Add interface. */
ifp = if_get_by_name (name, vrf_id);
set_ifindex(ifp, ifi->ifi_index, zns);
ifp->flags = ifi->ifi_flags & 0x0000fffff;
if (vrf_device)
if (IS_ZEBRA_IF_VRF(ifp))
SET_FLAG(ifp->status, ZEBRA_INTERFACE_VRF_LOOPBACK);
ifp->mtu6 = ifp->mtu = *(uint32_t *) RTA_DATA (tb[IFLA_MTU]);
ifp->metric = 0;
ifp->speed = get_iflink_speed (name);
ifp->ptm_status = ZEBRA_PTM_STATUS_UNKNOWN;
/* Set zebra interface type */
zebra_if_set_ziftype (ifp, zif_type, zif_slave_type);
/* Update link. */
zebra_if_update_link (ifp, link_ifindex);
/* Hardware type and address. */
ifp->ll_type = netlink_to_zebra_link_type (ifi->ifi_type);
netlink_interface_update_hw_addr (tb, ifp);
if_add_update (ifp);
/* Extract and save L2 interface information, take additional actions. */
netlink_interface_update_l2info (ifp, linkinfo[IFLA_INFO_DATA], 1);
if (IS_ZEBRA_IF_BRIDGE_SLAVE (ifp))
zebra_l2if_update_bridge_slave (ifp, bridge_ifindex);
return 0;
}
@ -477,6 +701,24 @@ interface_lookup_netlink (struct zebra_ns *zns)
if (ret < 0)
return ret;
/* Get interface information - for bridge interfaces. */
ret = netlink_request_intf_addr (zns, AF_BRIDGE, RTM_GETLINK,
RTEXT_FILTER_BRVLAN);
if (ret < 0)
return ret;
ret = netlink_parse_info (netlink_interface, &zns->netlink_cmd, zns, 0, 0);
if (ret < 0)
return ret;
/* Get interface information - for bridge interfaces. */
ret = netlink_request_intf_addr (zns, AF_BRIDGE, RTM_GETLINK,
RTEXT_FILTER_BRVLAN);
if (ret < 0)
return ret;
ret = netlink_parse_info (netlink_interface, &zns->netlink_cmd, zns, 0, 0);
if (ret < 0)
return ret;
/* Get IPv4 address of the interfaces. */
ret = netlink_request_intf_addr (zns, AF_INET, RTM_GETADDR, 0);
if (ret < 0)
@ -712,9 +954,13 @@ netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h,
char *name = NULL;
char *kind = NULL;
char *slave_kind = NULL;
int vrf_device = 0;
struct zebra_ns *zns;
vrf_id_t vrf_id = VRF_DEFAULT;
zebra_iftype_t zif_type = ZEBRA_IF_OTHER;
zebra_slave_iftype_t zif_slave_type = ZEBRA_IF_SLAVE_NONE;
ifindex_t bridge_ifindex = IFINDEX_INTERNAL;
ifindex_t link_ifindex = IFINDEX_INTERNAL;
zns = zebra_ns_lookup (ns_id);
ifi = NLMSG_DATA (h);
@ -731,11 +977,13 @@ netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h,
if (len < 0)
return -1;
/* We are interested in some AF_BRIDGE notifications. */
if (ifi->ifi_family == AF_BRIDGE)
return 0;
return netlink_bridge_interface (h, len, ns_id, startup);
/* Looking up interface name. */
memset (tb, 0, sizeof tb);
memset (linkinfo, 0, sizeof linkinfo);
netlink_parse_rtattr (tb, IFLA_MAX, IFLA_RTA (ifi), len);
#ifdef IFLA_WIRELESS
@ -754,7 +1002,6 @@ netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h,
if (tb[IFLA_LINKINFO])
{
memset (linkinfo, 0, sizeof linkinfo);
parse_rtattr_nested(linkinfo, IFLA_INFO_MAX, tb[IFLA_LINKINFO]);
if (linkinfo[IFLA_INFO_KIND])
@ -765,12 +1012,18 @@ netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h,
slave_kind = RTA_DATA(linkinfo[IFLA_INFO_SLAVE_KIND]);
#endif
if (kind && strcmp(kind, "vrf") == 0)
{
vrf_device = 1;
netlink_vrf_change(h, tb[IFLA_LINKINFO], name);
vrf_id = (vrf_id_t)ifi->ifi_index;
}
netlink_determine_zebra_iftype (kind, &zif_type);
}
/* If linking to another interface, note it. */
if (tb[IFLA_LINK])
link_ifindex = *(ifindex_t *)RTA_DATA(tb[IFLA_LINK]);
/* If VRF, create or update the VRF structure itself. */
if (zif_type == ZEBRA_IF_VRF)
{
netlink_vrf_change(h, tb[IFLA_LINKINFO], name);
vrf_id = (vrf_id_t)ifi->ifi_index;
}
/* See if interface is present. */
@ -781,15 +1034,27 @@ netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h,
if (tb[IFLA_MASTER])
{
if (slave_kind && (strcmp(slave_kind, "vrf") == 0))
vrf_id = *(u_int32_t *)RTA_DATA(tb[IFLA_MASTER]);
{
zif_slave_type = ZEBRA_IF_SLAVE_VRF;
vrf_id = *(u_int32_t *)RTA_DATA(tb[IFLA_MASTER]);
}
else if (slave_kind && (strcmp(slave_kind, "bridge") == 0))
{
zif_slave_type = ZEBRA_IF_SLAVE_BRIDGE;
bridge_ifindex = *(ifindex_t *)RTA_DATA(tb[IFLA_MASTER]);
}
else
zif_slave_type = ZEBRA_IF_SLAVE_OTHER;
}
if (ifp == NULL || !CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE))
{
/* Add interface notification from kernel */
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug ("RTM_NEWLINK for %s(%u) (ifp %p) vrf_id %u flags 0x%x",
name, ifi->ifi_index, ifp, vrf_id, ifi->ifi_flags);
zlog_debug ("RTM_NEWLINK ADD for %s(%u) vrf_id %u type %d "
"sl_type %d master %u flags 0x%x",
name, ifi->ifi_index, vrf_id, zif_type, zif_slave_type,
bridge_ifindex, ifi->ifi_flags);
if (ifp == NULL)
{
@ -806,16 +1071,27 @@ netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h,
/* Update interface information. */
set_ifindex(ifp, ifi->ifi_index, zns);
ifp->flags = ifi->ifi_flags & 0x0000fffff;
if (vrf_device)
if (IS_ZEBRA_IF_VRF(ifp))
SET_FLAG(ifp->status, ZEBRA_INTERFACE_VRF_LOOPBACK);
ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]);
ifp->metric = 0;
ifp->ptm_status = ZEBRA_PTM_STATUS_UNKNOWN;
/* Set interface type */
zebra_if_set_ziftype (ifp, zif_type, zif_slave_type);
/* Update link. */
zebra_if_update_link (ifp, link_ifindex);
netlink_interface_update_hw_addr (tb, ifp);
/* Inform clients, install any configured addresses. */
if_add_update (ifp);
/* Extract and save L2 interface information, take additional actions. */
netlink_interface_update_l2info (ifp, linkinfo[IFLA_INFO_DATA], 1);
if (IS_ZEBRA_IF_BRIDGE_SLAVE (ifp))
zebra_l2if_update_bridge_slave (ifp, bridge_ifindex);
}
else if (ifp->vrf_id != vrf_id)
{
@ -830,32 +1106,59 @@ netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h,
}
else
{
/* Interface status change. */
int was_bridge_slave;
/* Interface update. */
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug ("RTM_NEWLINK status for %s(%u) flags 0x%x",
name, ifp->ifindex, ifi->ifi_flags);
zlog_debug ("RTM_NEWLINK update for %s(%u) "
"sl_type %d master %u flags 0x%x",
name, ifp->ifindex, zif_slave_type,
bridge_ifindex, ifi->ifi_flags);
set_ifindex(ifp, ifi->ifi_index, zns);
ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]);
ifp->metric = 0;
/* Update interface type - NOTE: Only slave_type can change. */
was_bridge_slave = IS_ZEBRA_IF_BRIDGE_SLAVE (ifp);
zebra_if_set_ziftype (ifp, zif_type, zif_slave_type);
netlink_interface_update_hw_addr (tb, ifp);
if (if_is_no_ptm_operative (ifp))
{
ifp->flags = ifi->ifi_flags & 0x0000fffff;
if (!if_is_no_ptm_operative (ifp))
if_down (ifp);
{
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug ("Intf %s(%u) has gone DOWN",
name, ifp->ifindex);
if_down (ifp);
}
else if (if_is_operative (ifp))
/* Must notify client daemons of new interface status. */
zebra_interface_up_update (ifp);
{
/* Must notify client daemons of new interface status. */
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug ("Intf %s(%u) PTM up, notifying clients",
name, ifp->ifindex);
zebra_interface_up_update (ifp);
}
}
else
{
ifp->flags = ifi->ifi_flags & 0x0000fffff;
if (if_is_operative (ifp))
if_up (ifp);
{
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug ("Intf %s(%u) has come UP", name, ifp->ifindex);
if_up (ifp);
}
}
/* Extract and save L2 interface information, take additional actions. */
netlink_interface_update_l2info (ifp, linkinfo[IFLA_INFO_DATA], 0);
if (IS_ZEBRA_IF_BRIDGE_SLAVE (ifp) || was_bridge_slave)
zebra_l2if_update_bridge_slave (ifp, bridge_ifindex);
}
}
else
@ -873,7 +1176,13 @@ netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h,
UNSET_FLAG(ifp->status, ZEBRA_INTERFACE_VRF_LOOPBACK);
if (!vrf_device)
/* Special handling for bridge or VxLAN interfaces. */
if (IS_ZEBRA_IF_BRIDGE (ifp))
zebra_l2_bridge_del (ifp);
else if (IS_ZEBRA_IF_VXLAN (ifp))
zebra_l2_vxlanif_del (ifp);
if (!IS_ZEBRA_IF_VRF(ifp))
if_delete_update (ifp);
}

View File

@ -47,6 +47,7 @@
#include "zebra/zebra_ptm.h"
#include "zebra/rt_netlink.h"
#include "zebra/interface.h"
#include "zebra/zebra_vxlan.h"
#define ZEBRA_PTM_SUPPORT
@ -680,6 +681,8 @@ if_delete_connected (struct interface *ifp)
void
if_delete_update (struct interface *ifp)
{
struct zebra_if *zif;
if (if_is_up(ifp))
{
zlog_err ("interface %s vrf %u index %d is still up while being deleted.",
@ -713,6 +716,16 @@ if_delete_update (struct interface *ifp)
/* if the ifp is in a vrf, move it to default so vrf can be deleted if desired */
if (ifp->vrf_id)
if_handle_vrf_change (ifp, VRF_DEFAULT);
/* Reset some zebra interface params to default values. */
zif = ifp->info;
if (zif)
{
zif->zif_type = ZEBRA_IF_OTHER;
zif->zif_slave_type = ZEBRA_IF_SLAVE_NONE;
memset (&zif->l2info, 0, sizeof (union zebra_l2if_info));
memset (&zif->brslave_info, 0, sizeof (struct zebra_l2info_brslave));
}
}
/* VRF change for an interface */
@ -834,6 +847,7 @@ void
if_up (struct interface *ifp)
{
struct zebra_if *zif;
struct interface *link_if;
zif = ifp->info;
zif->up_count++;
@ -868,6 +882,24 @@ if_up (struct interface *ifp)
rib_update (ifp->vrf_id, RIB_UPDATE_IF_CHANGE);
zebra_vrf_static_route_interface_fixup (ifp);
/* Handle interface up for specific types for EVPN. Non-VxLAN interfaces
* are checked to see if (remote) neighbor entries need to be installed
* on them for ARP suppression.
*/
if (IS_ZEBRA_IF_VXLAN (ifp))
zebra_vxlan_if_up (ifp);
else if (IS_ZEBRA_IF_BRIDGE (ifp))
{
link_if = ifp;
zebra_vxlan_svi_up (ifp, link_if);
}
else if (IS_ZEBRA_IF_VLAN (ifp))
{
link_if = zif->link;
if (link_if)
zebra_vxlan_svi_up (ifp, link_if);
}
}
/* Interface goes down. We have to manage different behavior of based
@ -876,11 +908,31 @@ void
if_down (struct interface *ifp)
{
struct zebra_if *zif;
struct interface *link_if;
zif = ifp->info;
zif->down_count++;
quagga_timestamp (2, zif->down_last, sizeof (zif->down_last));
/* Handle interface down for specific types for EVPN. Non-VxLAN interfaces
* are checked to see if (remote) neighbor entries need to be purged
* for ARP suppression.
*/
if (IS_ZEBRA_IF_VXLAN (ifp))
zebra_vxlan_if_down (ifp);
else if (IS_ZEBRA_IF_BRIDGE (ifp))
{
link_if = ifp;
zebra_vxlan_svi_down (ifp, link_if);
}
else if (IS_ZEBRA_IF_VLAN (ifp))
{
link_if = zif->link;
if (link_if)
zebra_vxlan_svi_down (ifp, link_if);
}
/* Notify to the protocol daemons. */
zebra_interface_down_update (ifp);
@ -904,6 +956,17 @@ if_refresh (struct interface *ifp)
if_get_flags (ifp);
}
void
zebra_if_update_link (struct interface *ifp, ifindex_t link_ifindex)
{
struct zebra_if *zif;
zif = (struct zebra_if *)ifp->info;
zif->link_ifindex = link_ifindex;
zif->link = if_lookup_by_index_per_ns (zebra_ns_lookup (NS_DEFAULT),
link_ifindex);
}
/* Output prefix string to vty. */
static int
@ -1020,6 +1083,37 @@ nd_dump_vty (struct vty *vty, struct interface *ifp)
}
#endif /* HAVE_RTADV */
static const char *
zebra_ziftype_2str (zebra_iftype_t zif_type)
{
switch (zif_type)
{
case ZEBRA_IF_OTHER:
return "Other";
break;
case ZEBRA_IF_BRIDGE:
return "Bridge";
break;
case ZEBRA_IF_VLAN:
return "Vlan";
break;
case ZEBRA_IF_VXLAN:
return "Vxlan";
break;
case ZEBRA_IF_VRF:
return "VRF";
break;
default:
return "Unknown";
break;
}
}
/* Interface's information print out to vty interface. */
static void
if_dump_vty (struct vty *vty, struct interface *ifp)
@ -1115,6 +1209,51 @@ if_dump_vty (struct vty *vty, struct interface *ifp)
connected_dump_vty (vty, connected);
}
vty_out(vty, " Interface Type %s\n",
zebra_ziftype_2str (zebra_if->zif_type));
if (IS_ZEBRA_IF_BRIDGE (ifp))
{
struct zebra_l2info_bridge *bridge_info;
bridge_info = &zebra_if->l2info.br;
vty_out(vty, " Bridge VLAN-aware: %s\n",
bridge_info->vlan_aware ? "yes" : "no");
}
else if (IS_ZEBRA_IF_VLAN(ifp))
{
struct zebra_l2info_vlan *vlan_info;
vlan_info = &zebra_if->l2info.vl;
vty_out(vty, " VLAN Id %u\n",
vlan_info->vid);
}
else if (IS_ZEBRA_IF_VXLAN (ifp))
{
struct zebra_l2info_vxlan *vxlan_info;
vxlan_info = &zebra_if->l2info.vxl;
vty_out(vty, " VxLAN Id %u", vxlan_info->vni);
if (vxlan_info->vtep_ip.s_addr != INADDR_ANY)
vty_out(vty, " VTEP IP: %s", inet_ntoa (vxlan_info->vtep_ip));
if (vxlan_info->access_vlan)
vty_out(vty, " Access VLAN Id %u", vxlan_info->access_vlan);
vty_out(vty, "\n");
}
if (IS_ZEBRA_IF_BRIDGE_SLAVE (ifp))
{
struct zebra_l2info_brslave *br_slave;
br_slave = &zebra_if->brslave_info;
if (br_slave->bridge_ifindex != IFINDEX_INTERNAL)
vty_out(vty, " Master (bridge) ifindex %u\n",
br_slave->bridge_ifindex);
}
if (zebra_if->link_ifindex != IFINDEX_INTERNAL)
vty_out(vty, " Link ifindex %u\n",
zebra_if->link_ifindex);
if (HAS_LINK_PARAMS(ifp))
{
int i;

View File

@ -28,6 +28,8 @@
#include "zebra/irdp.h"
#endif
#include "zebra/zebra_l2.h"
/* For interface multicast configuration. */
#define IF_ZEBRA_MULTICAST_UNSPEC 0
#define IF_ZEBRA_MULTICAST_ON 1
@ -180,6 +182,25 @@ struct rtadvconf
#endif /* HAVE_RTADV */
/* Zebra interface type - ones of interest. */
typedef enum
{
ZEBRA_IF_VXLAN, /* VxLAN interface */
ZEBRA_IF_VRF, /* VRF device */
ZEBRA_IF_BRIDGE, /* bridge device */
ZEBRA_IF_VLAN, /* VLAN sub-interface */
ZEBRA_IF_OTHER, /* Anything else */
} zebra_iftype_t;
/* Zebra "slave" interface type */
typedef enum
{
ZEBRA_IF_SLAVE_NONE, /* Not a slave */
ZEBRA_IF_SLAVE_VRF, /* Member of a VRF */
ZEBRA_IF_SLAVE_BRIDGE, /* Member of a bridge */
ZEBRA_IF_SLAVE_OTHER, /* Something else - e.g., bond slave */
} zebra_slave_iftype_t;
/* `zebra' daemon local interface structure. */
struct zebra_if
{
@ -231,8 +252,53 @@ struct zebra_if
/* ptm enable configuration */
u_char ptm_enable;
/* Zebra interface and "slave" interface type */
zebra_iftype_t zif_type;
zebra_slave_iftype_t zif_slave_type;
/* Additional L2 info, depends on zif_type */
union zebra_l2if_info l2info;
/* For members of a bridge, link to bridge. */
/* Note: If additional fields become necessary, this can be modified to
* be a pointer to a dynamically allocd struct.
*/
struct zebra_l2info_brslave brslave_info;
/* Link fields - for sub-interfaces. */
ifindex_t link_ifindex;
struct interface *link;
};
static inline void
zebra_if_set_ziftype (struct interface *ifp, zebra_iftype_t zif_type,
zebra_slave_iftype_t zif_slave_type)
{
struct zebra_if *zif;
zif = (struct zebra_if *)ifp->info;
zif->zif_type = zif_type;
zif->zif_slave_type = zif_slave_type;
}
#define IS_ZEBRA_IF_VRF(ifp) \
(((struct zebra_if *)(ifp->info))->zif_type == ZEBRA_IF_VRF)
#define IS_ZEBRA_IF_BRIDGE(ifp) \
(((struct zebra_if *)(ifp->info))->zif_type == ZEBRA_IF_BRIDGE)
#define IS_ZEBRA_IF_VLAN(ifp) \
(((struct zebra_if *)(ifp->info))->zif_type == ZEBRA_IF_VLAN)
#define IS_ZEBRA_IF_VXLAN(ifp) \
(((struct zebra_if *)(ifp->info))->zif_type == ZEBRA_IF_VXLAN)
#define IS_ZEBRA_IF_BRIDGE_SLAVE(ifp) \
(((struct zebra_if *)(ifp->info))->zif_slave_type == ZEBRA_IF_SLAVE_BRIDGE)
#define IS_ZEBRA_IF_VRF_SLAVE(ifp) \
(((struct zebra_if *)(ifp->info))->zif_slave_type == ZEBRA_IF_SLAVE_VRF)
extern struct interface *if_lookup_by_index_per_ns (struct zebra_ns *, u_int32_t);
extern struct interface *if_lookup_by_name_per_ns (struct zebra_ns *, const char *);
@ -253,6 +319,7 @@ extern int if_subnet_add (struct interface *, struct connected *);
extern int if_subnet_delete (struct interface *, struct connected *);
extern int ipv6_address_configured (struct interface *ifp);
extern void if_handle_vrf_change (struct interface *ifp, vrf_id_t vrf_id);
extern void zebra_if_update_link (struct interface *ifp, ifindex_t link_ifindex);
extern void vrf_add_update (struct vrf *vrfp);

View File

@ -269,6 +269,12 @@ netlink_information_fetch (struct sockaddr_nl *snl, struct nlmsghdr *h,
case RTM_DELADDR:
return netlink_interface_addr (snl, h, ns_id, startup);
break;
case RTM_NEWNEIGH:
return netlink_neigh_change (snl, h, ns_id);
break;
case RTM_DELNEIGH:
return netlink_neigh_change (snl, h, ns_id);
break;
default:
zlog_warn ("Unknown netlink nlmsg_type %d vrf %u\n", h->nlmsg_type,
ns_id);
@ -297,17 +303,21 @@ static void netlink_install_filter (int sock, __u32 pid)
struct sock_filter filter[] = {
/* 0: ldh [4] */
BPF_STMT(BPF_LD|BPF_ABS|BPF_H, offsetof(struct nlmsghdr, nlmsg_type)),
/* 1: jeq 0x18 jt 3 jf 6 */
BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, htons(RTM_NEWROUTE), 1, 0),
/* 2: jeq 0x19 jt 3 jf 6 */
BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, htons(RTM_DELROUTE), 0, 3),
/* 3: ldw [12] */
/* 1: jeq 0x18 jt 5 jf next */
BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, htons(RTM_NEWROUTE), 3, 0),
/* 2: jeq 0x19 jt 5 jf next */
BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, htons(RTM_DELROUTE), 2, 0),
/* 3: jeq 0x19 jt 5 jf next */
BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, htons(RTM_NEWNEIGH), 1, 0),
/* 4: jeq 0x19 jt 5 jf 8 */
BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, htons(RTM_DELNEIGH), 0, 3),
/* 5: ldw [12] */
BPF_STMT(BPF_LD|BPF_ABS|BPF_W, offsetof(struct nlmsghdr, nlmsg_pid)),
/* 4: jeq XX jt 5 jf 6 */
/* 6: jeq XX jt 7 jf 8 */
BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, htonl(pid), 0, 1),
/* 5: ret 0 (skip) */
/* 7: ret 0 (skip) */
BPF_STMT(BPF_RET|BPF_K, 0),
/* 6: ret 0xffff (keep) */
/* 8: ret 0xffff (keep) */
BPF_STMT(BPF_RET|BPF_K, 0xffff),
};
@ -786,7 +796,7 @@ kernel_init (struct zebra_ns *zns)
/* Initialize netlink sockets */
groups = RTMGRP_LINK | RTMGRP_IPV4_ROUTE | RTMGRP_IPV4_IFADDR |
RTMGRP_IPV6_ROUTE | RTMGRP_IPV6_IFADDR |
RTMGRP_IPV4_MROUTE;
RTMGRP_IPV4_MROUTE | RTMGRP_NEIGH;
snprintf (zns->netlink.name, sizeof (zns->netlink.name),
"netlink-listen (NS %u)", zns->ns_id);

View File

@ -24,6 +24,8 @@
#include "prefix.h"
#include "if.h"
#include "vlan.h"
#include "vxlan.h"
#include "zebra/rib.h"
#include "zebra/zebra_ns.h"
#include "zebra/zebra_mpls.h"
@ -41,4 +43,18 @@ extern int kernel_del_lsp (zebra_lsp_t *);
extern int mpls_kernel_init (void);
extern int kernel_get_ipmr_sg_stats (void *mroute);
extern int kernel_add_vtep (vni_t vni, struct interface *ifp,
struct in_addr *vtep_ip);
extern int kernel_del_vtep (vni_t vni, struct interface *ifp,
struct in_addr *vtep_ip);
extern int kernel_add_mac (struct interface *ifp, vlanid_t vid,
struct ethaddr *mac, struct in_addr vtep_ip,
u_char sticky);
extern int kernel_del_mac (struct interface *ifp, vlanid_t vid,
struct ethaddr *mac, struct in_addr vtep_ip, int local);
extern int kernel_add_neigh (struct interface *ifp, struct ipaddr *ip,
struct ethaddr *mac);
extern int kernel_del_neigh (struct interface *ifp, struct ipaddr *ip);
#endif /* _ZEBRA_RT_H */

View File

@ -41,6 +41,7 @@
#include "vrf.h"
#include "vty.h"
#include "mpls.h"
#include "vxlan.h"
#include "zebra/zserv.h"
#include "zebra/zebra_ns.h"
@ -55,6 +56,7 @@
#include "zebra/kernel_netlink.h"
#include "zebra/rt_netlink.h"
#include "zebra/zebra_mroute.h"
#include "zebra/zebra_vxlan.h"
/* TODO - Temporary definitions, need to refine. */
@ -93,8 +95,30 @@
#ifndef NDA_MASTER
#define NDA_MASTER 9
#endif
#ifndef NTF_MASTER
#define NTF_MASTER 0x04
#endif
#ifndef NTF_SELF
#define NTF_SELF 0x02
#endif
#ifndef NTF_EXT_LEARNED
#define NTF_EXT_LEARNED 0x10
#endif
#ifndef NDA_IFINDEX
#define NDA_IFINDEX 8
#endif
#ifndef NDA_VLAN
#define NDA_VLAN 5
#endif
/* End of temporary definitions */
static vlanid_t filter_vlan = 0;
struct gw_family_t
{
u_int16_t filler;
@ -1554,6 +1578,712 @@ kernel_neigh_update (int add, int ifindex, uint32_t addr, char *lla, int llalen)
lla, llalen);
}
/*
* Add remote VTEP to the flood list for this VxLAN interface (VNI). This
* is done by adding an FDB entry with a MAC of 00:00:00:00:00:00.
*/
static int
netlink_vxlan_flood_list_update (struct interface *ifp,
struct in_addr *vtep_ip,
int cmd)
{
struct zebra_ns *zns = zebra_ns_lookup (NS_DEFAULT);
struct
{
struct nlmsghdr n;
struct ndmsg ndm;
char buf[256];
} req;
u_char dst_mac[6] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
memset(&req.n, 0, sizeof(req.n));
memset(&req.ndm, 0, sizeof(req.ndm));
req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg));
req.n.nlmsg_flags = NLM_F_REQUEST;
if (cmd == RTM_NEWNEIGH)
req.n.nlmsg_flags |= (NLM_F_CREATE | NLM_F_APPEND);
req.n.nlmsg_type = cmd;
req.ndm.ndm_family = PF_BRIDGE;
req.ndm.ndm_state = NUD_NOARP | NUD_PERMANENT;
req.ndm.ndm_flags |= NTF_SELF; // Handle by "self", not "master"
addattr_l (&req.n, sizeof (req), NDA_LLADDR, &dst_mac, 6);
req.ndm.ndm_ifindex = ifp->ifindex;
addattr_l (&req.n, sizeof (req), NDA_DST, &vtep_ip->s_addr, 4);
return netlink_talk (netlink_talk_filter, &req.n, &zns->netlink_cmd, zns, 0);
}
/*
* Add remote VTEP for this VxLAN interface (VNI). In Linux, this involves adding
* a "flood" MAC FDB entry.
*/
int
kernel_add_vtep (vni_t vni, struct interface *ifp, struct in_addr *vtep_ip)
{
if (IS_ZEBRA_DEBUG_VXLAN)
zlog_debug ("Install %s into flood list for VNI %u intf %s(%u)",
inet_ntoa (*vtep_ip), vni, ifp->name, ifp->ifindex);
return netlink_vxlan_flood_list_update (ifp, vtep_ip, RTM_NEWNEIGH);
}
/*
* Remove remote VTEP for this VxLAN interface (VNI). In Linux, this involves
* deleting the "flood" MAC FDB entry.
*/
int
kernel_del_vtep (vni_t vni, struct interface *ifp, struct in_addr *vtep_ip)
{
if (IS_ZEBRA_DEBUG_VXLAN)
zlog_debug ("Uninstall %s from flood list for VNI %u intf %s(%u)",
inet_ntoa (*vtep_ip), vni, ifp->name, ifp->ifindex);
return netlink_vxlan_flood_list_update (ifp, vtep_ip, RTM_DELNEIGH);
}
#ifndef NDA_RTA
#define NDA_RTA(r) \
((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ndmsg))))
#endif
static int
netlink_macfdb_change (struct sockaddr_nl *snl, struct nlmsghdr *h, int len)
{
struct ndmsg *ndm;
struct interface *ifp;
struct zebra_if *zif;
struct zebra_vrf *zvrf;
struct rtattr *tb[NDA_MAX + 1];
struct interface *br_if;
struct ethaddr mac;
vlanid_t vid = 0;
struct prefix vtep_ip;
int vid_present = 0, dst_present = 0;
char buf[ETHER_ADDR_STRLEN];
char vid_buf[20];
char dst_buf[30];
u_char sticky = 0;
ndm = NLMSG_DATA (h);
/* The interface should exist. */
ifp = if_lookup_by_index_per_ns (zebra_ns_lookup (NS_DEFAULT), ndm->ndm_ifindex);
if (!ifp)
return 0;
/* Locate VRF corresponding to interface. We only process MAC notifications
* if EVPN is enabled on this VRF.
*/
zvrf = vrf_info_lookup(ifp->vrf_id);
if (!zvrf || !EVPN_ENABLED(zvrf))
return 0;
if (!ifp->info)
return 0;
/* The interface should be something we're interested in. */
if (!IS_ZEBRA_IF_BRIDGE_SLAVE(ifp))
return 0;
/* Drop "permanent" entries. */
if (ndm->ndm_state & NUD_PERMANENT)
return 0;
zif = (struct zebra_if *)ifp->info;
if ((br_if = zif->brslave_info.br_if) == NULL)
{
zlog_warn ("%s family %s IF %s(%u) brIF %u - no bridge master",
nl_msg_type_to_str (h->nlmsg_type),
nl_family_to_str (ndm->ndm_family),
ifp->name, ndm->ndm_ifindex,
zif->brslave_info.bridge_ifindex);
return 0;
}
/* Parse attributes and extract fields of interest. */
memset (tb, 0, sizeof tb);
netlink_parse_rtattr (tb, NDA_MAX, NDA_RTA (ndm), len);
if (!tb[NDA_LLADDR])
{
zlog_warn ("%s family %s IF %s(%u) brIF %u - no LLADDR",
nl_msg_type_to_str (h->nlmsg_type),
nl_family_to_str (ndm->ndm_family),
ifp->name, ndm->ndm_ifindex,
zif->brslave_info.bridge_ifindex);
return 0;
}
if (RTA_PAYLOAD (tb[NDA_LLADDR]) != ETHER_ADDR_LEN)
{
zlog_warn ("%s family %s IF %s(%u) brIF %u - LLADDR is not MAC, len %ld",
nl_msg_type_to_str (h->nlmsg_type),
nl_family_to_str (ndm->ndm_family),
ifp->name, ndm->ndm_ifindex,
zif->brslave_info.bridge_ifindex,
RTA_PAYLOAD (tb[NDA_LLADDR]));
return 0;
}
memcpy (&mac, RTA_DATA (tb[NDA_LLADDR]), ETHER_ADDR_LEN);
if ((NDA_VLAN <= NDA_MAX) && tb[NDA_VLAN])
{
vid_present = 1;
vid = *(u_int16_t *) RTA_DATA(tb[NDA_VLAN]);
sprintf (vid_buf, " VLAN %u", vid);
}
if (tb[NDA_DST])
{
/* TODO: Only IPv4 supported now. */
dst_present = 1;
vtep_ip.family = AF_INET;
vtep_ip.prefixlen = IPV4_MAX_BITLEN;
memcpy (&(vtep_ip.u.prefix4.s_addr), RTA_DATA (tb[NDA_DST]), IPV4_MAX_BYTELEN);
sprintf (dst_buf, " dst %s", inet_ntoa (vtep_ip.u.prefix4));
}
sticky = (ndm->ndm_state & NUD_NOARP) ? 1 : 0;
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug ("Rx %s family %s IF %s(%u)%s %sMAC %s%s",
nl_msg_type_to_str (h->nlmsg_type),
nl_family_to_str (ndm->ndm_family),
ifp->name, ndm->ndm_ifindex,
vid_present ? vid_buf : "",
sticky ? "sticky " : "",
prefix_mac2str (&mac, buf, sizeof (buf)),
dst_present ? dst_buf: "");
if (filter_vlan && vid != filter_vlan)
return 0;
/* If add or update, do accordingly if learnt on a "local" interface; if
* the notification is over VxLAN, this has to be related to multi-homing,
* so perform an implicit delete of any local entry (if it exists).
*/
if (h->nlmsg_type == RTM_NEWNEIGH)
{
/* Drop "permanent" entries. */
if (ndm->ndm_state & NUD_PERMANENT)
return 0;
if (IS_ZEBRA_IF_VXLAN(ifp))
return zebra_vxlan_check_del_local_mac (ifp, br_if, &mac, vid);
return zebra_vxlan_local_mac_add_update (ifp, br_if, &mac, vid, sticky);
}
/* This is a delete notification.
* 1. For a MAC over VxLan, check if it needs to be refreshed(readded)
* 2. For a MAC over "local" interface, delete the mac
* Note: We will get notifications from both bridge driver and VxLAN driver.
* Ignore the notification from VxLan driver as it is also generated
* when mac moves from remote to local.
*/
if (dst_present)
return 0;
if (IS_ZEBRA_IF_VXLAN(ifp))
return zebra_vxlan_check_readd_remote_mac (ifp, br_if, &mac, vid);
return zebra_vxlan_local_mac_del (ifp, br_if, &mac, vid);
}
static int
netlink_macfdb_table (struct sockaddr_nl *snl, struct nlmsghdr *h,
ns_id_t ns_id, int startup)
{
int len;
struct ndmsg *ndm;
if (h->nlmsg_type != RTM_NEWNEIGH)
return 0;
/* Length validity. */
len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ndmsg));
if (len < 0)
return -1;
/* We are interested only in AF_BRIDGE notifications. */
ndm = NLMSG_DATA (h);
if (ndm->ndm_family != AF_BRIDGE)
return 0;
return netlink_macfdb_change (snl, h, len);
}
/* Request for MAC FDB information from the kernel */
static int
netlink_request_macs (struct zebra_ns *zns, int family, int type,
ifindex_t master_ifindex)
{
struct
{
struct nlmsghdr n;
struct ifinfomsg ifm;
char buf[256];
} req;
/* Form the request, specifying filter (rtattr) if needed. */
memset (&req, 0, sizeof (req));
req.n.nlmsg_type = type;
req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
req.ifm.ifi_family = family;
if (master_ifindex)
addattr32 (&req.n, sizeof(req), IFLA_MASTER, master_ifindex);
return netlink_request (&zns->netlink_cmd, &req.n);
}
/*
* MAC forwarding database read using netlink interface. This is invoked
* at startup.
*/
int
netlink_macfdb_read (struct zebra_ns *zns)
{
int ret;
/* Get bridge FDB table. */
ret = netlink_request_macs (zns, AF_BRIDGE, RTM_GETNEIGH, 0);
if (ret < 0)
return ret;
/* We are reading entire table. */
filter_vlan = 0;
ret = netlink_parse_info (netlink_macfdb_table, &zns->netlink_cmd, zns, 0, 1);
return ret;
}
/*
* MAC forwarding database read using netlink interface. This is for a
* specific bridge and matching specific access VLAN (if VLAN-aware bridge).
*/
int
netlink_macfdb_read_for_bridge (struct zebra_ns *zns, struct interface *ifp,
struct interface *br_if)
{
struct zebra_if *br_zif;
struct zebra_if *zif;
struct zebra_l2info_vxlan *vxl;
int ret = 0;
/* Save VLAN we're filtering on, if needed. */
br_zif = (struct zebra_if *) br_if->info;
zif = (struct zebra_if *) ifp->info;
vxl = &zif->l2info.vxl;
if (IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(br_zif))
filter_vlan = vxl->access_vlan;
/* Get bridge FDB table for specific bridge - we do the VLAN filtering. */
ret = netlink_request_macs (zns, AF_BRIDGE, RTM_GETNEIGH, br_if->ifindex);
if (ret < 0)
return ret;
ret = netlink_parse_info (netlink_macfdb_table, &zns->netlink_cmd, zns, 0, 0);
/* Reset VLAN filter. */
filter_vlan = 0;
return ret;
}
static int
netlink_macfdb_update (struct interface *ifp, vlanid_t vid,
struct ethaddr *mac,
struct in_addr vtep_ip,
int local, int cmd,
u_char sticky)
{
struct zebra_ns *zns = zebra_ns_lookup (NS_DEFAULT);
struct
{
struct nlmsghdr n;
struct ndmsg ndm;
char buf[256];
} req;
int dst_alen;
struct zebra_if *zif;
struct interface *br_if;
struct zebra_if *br_zif;
char buf[ETHER_ADDR_STRLEN];
int vid_present = 0, dst_present = 0;
char vid_buf[20];
char dst_buf[30];
zif = ifp->info;
if ((br_if = zif->brslave_info.br_if) == NULL)
{
zlog_warn ("MAC %s on IF %s(%u) - no mapping to bridge",
(cmd == RTM_NEWNEIGH) ? "add" : "del",
ifp->name, ifp->ifindex);
return -1;
}
memset(&req.n, 0, sizeof(req.n));
memset(&req.ndm, 0, sizeof(req.ndm));
req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg));
req.n.nlmsg_flags = NLM_F_REQUEST;
if (cmd == RTM_NEWNEIGH)
req.n.nlmsg_flags |= (NLM_F_CREATE | NLM_F_REPLACE);
req.n.nlmsg_type = cmd;
req.ndm.ndm_family = AF_BRIDGE;
req.ndm.ndm_flags |= NTF_SELF | NTF_MASTER;
req.ndm.ndm_state = NUD_REACHABLE;
if (sticky)
req.ndm.ndm_state |= NUD_NOARP;
else
req.ndm.ndm_flags |= NTF_EXT_LEARNED;
addattr_l (&req.n, sizeof (req), NDA_LLADDR, mac, 6);
req.ndm.ndm_ifindex = ifp->ifindex;
if (!local)
{
dst_alen = 4; // TODO: hardcoded
addattr_l (&req.n, sizeof (req), NDA_DST, &vtep_ip, dst_alen);
dst_present = 1;
sprintf (dst_buf, " dst %s", inet_ntoa (vtep_ip));
}
br_zif = (struct zebra_if *) br_if->info;
if (IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(br_zif) && vid > 0)
{
addattr16 (&req.n, sizeof (req), NDA_VLAN, vid);
vid_present = 1;
sprintf (vid_buf, " VLAN %u", vid);
}
addattr32 (&req.n, sizeof (req), NDA_MASTER, br_if->ifindex);
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug ("Tx %s family %s IF %s(%u)%s %sMAC %s%s",
nl_msg_type_to_str (cmd),
nl_family_to_str (req.ndm.ndm_family),
ifp->name, ifp->ifindex,
vid_present ? vid_buf : "",
sticky ? "sticky " : "",
prefix_mac2str (mac, buf, sizeof (buf)),
dst_present ? dst_buf : "");
return netlink_talk (netlink_talk_filter, &req.n, &zns->netlink_cmd, zns, 0);
}
#define NUD_VALID (NUD_PERMANENT | NUD_NOARP | NUD_REACHABLE | \
NUD_PROBE | NUD_STALE | NUD_DELAY)
static int
netlink_ipneigh_change (struct sockaddr_nl *snl, struct nlmsghdr *h, int len)
{
struct ndmsg *ndm;
struct interface *ifp;
struct zebra_if *zif;
struct zebra_vrf *zvrf;
struct rtattr *tb[NDA_MAX + 1];
struct interface *link_if;
struct ethaddr mac;
struct ipaddr ip;
char buf[ETHER_ADDR_STRLEN];
char buf2[INET6_ADDRSTRLEN];
int mac_present = 0;
u_char ext_learned;
ndm = NLMSG_DATA (h);
/* The interface should exist. */
ifp = if_lookup_by_index_per_ns (zebra_ns_lookup (NS_DEFAULT), ndm->ndm_ifindex);
if (!ifp)
return 0;
/* Locate VRF corresponding to interface. We only process neigh notifications
* if EVPN is enabled on this VRF.
*/
zvrf = vrf_info_lookup(ifp->vrf_id);
if (!zvrf || !EVPN_ENABLED(zvrf))
return 0;
if (!ifp->info)
return 0;
/* Drop "permanent" entries. */
if (ndm->ndm_state & NUD_PERMANENT)
return 0;
zif = (struct zebra_if *)ifp->info;
/* The neighbor is present on an SVI. From this, we locate the underlying
* bridge because we're only interested in neighbors on a VxLAN bridge.
* The bridge is located based on the nature of the SVI:
* (a) In the case of a VLAN-aware bridge, the SVI is a L3 VLAN interface
* and is linked to the bridge
* (b) In the case of a VLAN-unaware bridge, the SVI is the bridge inteface
* itself
*/
if (IS_ZEBRA_IF_VLAN(ifp))
{
link_if = zif->link;
if (!link_if)
return 0;
}
else if (IS_ZEBRA_IF_BRIDGE(ifp))
link_if = ifp;
else
return 0;
/* Parse attributes and extract fields of interest. */
memset (tb, 0, sizeof tb);
netlink_parse_rtattr (tb, NDA_MAX, NDA_RTA (ndm), len);
if (!tb[NDA_DST])
{
zlog_warn ("%s family %s IF %s(%u) - no DST",
nl_msg_type_to_str (h->nlmsg_type),
nl_family_to_str (ndm->ndm_family),
ifp->name, ndm->ndm_ifindex);
return 0;
}
memset (&mac, 0, sizeof (struct ethaddr));
memset (&ip, 0, sizeof (struct ipaddr));
ip.ipa_type = (ndm->ndm_family == AF_INET) ? IPADDR_V4 : IPADDR_V6;
memcpy (&ip.ip.addr, RTA_DATA(tb[NDA_DST]), RTA_PAYLOAD(tb[NDA_DST]));
if (h->nlmsg_type == RTM_NEWNEIGH)
{
if (tb[NDA_LLADDR])
{
if (RTA_PAYLOAD (tb[NDA_LLADDR]) != ETHER_ADDR_LEN)
{
zlog_warn ("%s family %s IF %s(%u) - LLADDR is not MAC, len %ld",
nl_msg_type_to_str (h->nlmsg_type),
nl_family_to_str (ndm->ndm_family),
ifp->name, ndm->ndm_ifindex,
RTA_PAYLOAD (tb[NDA_LLADDR]));
return 0;
}
mac_present = 1;
memcpy (&mac, RTA_DATA (tb[NDA_LLADDR]), ETHER_ADDR_LEN);
}
ext_learned = (ndm->ndm_flags & NTF_EXT_LEARNED) ? 1 : 0;
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug ("Rx %s family %s IF %s(%u) IP %s MAC %s state 0x%x flags 0x%x",
nl_msg_type_to_str (h->nlmsg_type),
nl_family_to_str (ndm->ndm_family),
ifp->name, ndm->ndm_ifindex,
ipaddr2str (&ip, buf2, sizeof(buf2)),
mac_present ? prefix_mac2str (&mac, buf, sizeof (buf)) : "",
ndm->ndm_state, ndm->ndm_flags);
/* If the neighbor state is valid for use, process as an add or update
* else process as a delete. Note that the delete handling may result
* in re-adding the neighbor if it is a valid "remote" neighbor.
*/
if (ndm->ndm_state & NUD_VALID)
return zebra_vxlan_local_neigh_add_update (ifp, link_if,
&ip, &mac,
ndm->ndm_state, ext_learned);
return zebra_vxlan_local_neigh_del (ifp, link_if, &ip);
}
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug ("Rx %s family %s IF %s(%u) IP %s",
nl_msg_type_to_str (h->nlmsg_type),
nl_family_to_str (ndm->ndm_family),
ifp->name, ndm->ndm_ifindex,
ipaddr2str (&ip, buf2, sizeof(buf2)));
/* Process the delete - it may result in re-adding the neighbor if it is
* a valid "remote" neighbor.
*/
return zebra_vxlan_local_neigh_del (ifp, link_if, &ip);
}
static int
netlink_neigh_table (struct sockaddr_nl *snl, struct nlmsghdr *h,
ns_id_t ns_id, int startup)
{
int len;
struct ndmsg *ndm;
if (h->nlmsg_type != RTM_NEWNEIGH)
return 0;
/* Length validity. */
len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ndmsg));
if (len < 0)
return -1;
/* We are interested only in AF_INET or AF_INET6 notifications. */
ndm = NLMSG_DATA (h);
if (ndm->ndm_family != AF_INET && ndm->ndm_family != AF_INET6)
return 0;
return netlink_neigh_change (snl, h, len);
}
/* Request for IP neighbor information from the kernel */
static int
netlink_request_neigh (struct zebra_ns *zns, int family, int type,
ifindex_t ifindex)
{
struct
{
struct nlmsghdr n;
struct ndmsg ndm;
char buf[256];
} req;
/* Form the request, specifying filter (rtattr) if needed. */
memset (&req, 0, sizeof (req));
req.n.nlmsg_type = type;
req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg));
req.ndm.ndm_family = family;
if (ifindex)
addattr32 (&req.n, sizeof(req), NDA_IFINDEX, ifindex);
return netlink_request (&zns->netlink_cmd, &req.n);
}
/*
* IP Neighbor table read using netlink interface. This is invoked
* at startup.
*/
int
netlink_neigh_read (struct zebra_ns *zns)
{
int ret;
/* Get IP neighbor table. */
ret = netlink_request_neigh (zns, AF_UNSPEC, RTM_GETNEIGH, 0);
if (ret < 0)
return ret;
ret = netlink_parse_info (netlink_neigh_table, &zns->netlink_cmd, zns, 0, 1);
return ret;
}
/*
* IP Neighbor table read using netlink interface. This is for a specific
* VLAN device.
*/
int
netlink_neigh_read_for_vlan (struct zebra_ns *zns, struct interface *vlan_if)
{
int ret = 0;
ret = netlink_request_neigh (zns, AF_UNSPEC, RTM_GETNEIGH, vlan_if->ifindex);
if (ret < 0)
return ret;
ret = netlink_parse_info (netlink_neigh_table, &zns->netlink_cmd, zns, 0, 0);
return ret;
}
int
netlink_neigh_change (struct sockaddr_nl *snl, struct nlmsghdr *h,
ns_id_t ns_id)
{
int len;
struct ndmsg *ndm;
if (!(h->nlmsg_type == RTM_NEWNEIGH || h->nlmsg_type == RTM_DELNEIGH))
return 0;
/* Length validity. */
len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ndmsg));
if (len < 0)
return -1;
/* Is this a notification for the MAC FDB or IP neighbor table? */
ndm = NLMSG_DATA (h);
if (ndm->ndm_family == AF_BRIDGE)
return netlink_macfdb_change (snl, h, len);
if (ndm->ndm_type != RTN_UNICAST)
return 0;
if (ndm->ndm_family == AF_INET || ndm->ndm_family == AF_INET6)
return netlink_ipneigh_change (snl, h, len);
return 0;
}
static int
netlink_neigh_update2 (struct interface *ifp, struct ipaddr *ip,
struct ethaddr *mac, u_int32_t flags, int cmd)
{
struct {
struct nlmsghdr n;
struct ndmsg ndm;
char buf[256];
} req;
int ipa_len;
struct zebra_ns *zns = zebra_ns_lookup (NS_DEFAULT);
char buf[INET6_ADDRSTRLEN];
char buf2[ETHER_ADDR_STRLEN];
memset(&req.n, 0, sizeof(req.n));
memset(&req.ndm, 0, sizeof(req.ndm));
req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg));
req.n.nlmsg_flags = NLM_F_REQUEST;
if (cmd == RTM_NEWNEIGH)
req.n.nlmsg_flags |= (NLM_F_CREATE | NLM_F_REPLACE);
req.n.nlmsg_type = cmd; //RTM_NEWNEIGH or RTM_DELNEIGH
req.ndm.ndm_family = IS_IPADDR_V4(ip) ? AF_INET : AF_INET6;
req.ndm.ndm_state = flags;
req.ndm.ndm_ifindex = ifp->ifindex;
req.ndm.ndm_type = RTN_UNICAST;
req.ndm.ndm_flags = NTF_EXT_LEARNED;
ipa_len = IS_IPADDR_V4(ip) ? IPV4_MAX_BYTELEN : IPV6_MAX_BYTELEN;
addattr_l(&req.n, sizeof(req), NDA_DST, &ip->ip.addr, ipa_len);
if (mac)
addattr_l (&req.n, sizeof (req), NDA_LLADDR, mac, 6);
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug ("Tx %s family %s IF %s(%u) Neigh %s MAC %s",
nl_msg_type_to_str (cmd),
nl_family_to_str (req.ndm.ndm_family),
ifp->name, ifp->ifindex,
ipaddr2str (ip, buf, sizeof(buf)),
mac ? prefix_mac2str (mac, buf2, sizeof (buf2)) : "null");
return netlink_talk (netlink_talk_filter, &req.n, &zns->netlink_cmd, zns, 0);
}
int
kernel_add_mac (struct interface *ifp, vlanid_t vid,
struct ethaddr *mac, struct in_addr vtep_ip,
u_char sticky)
{
return netlink_macfdb_update (ifp, vid, mac, vtep_ip, 0, RTM_NEWNEIGH, sticky);
}
int
kernel_del_mac (struct interface *ifp, vlanid_t vid,
struct ethaddr *mac, struct in_addr vtep_ip, int local)
{
return netlink_macfdb_update (ifp, vid, mac, vtep_ip, local, RTM_DELNEIGH, 0);
}
int kernel_add_neigh (struct interface *ifp, struct ipaddr *ip,
struct ethaddr *mac)
{
return netlink_neigh_update2 (ifp, ip, mac, NUD_REACHABLE,
RTM_NEWNEIGH);
}
int kernel_del_neigh (struct interface *ifp, struct ipaddr *ip)
{
return netlink_neigh_update2 (ifp, ip, NULL, 0, RTM_DELNEIGH);
}
/*
* MPLS label forwarding table change via netlink interface.
*/

View File

@ -51,6 +51,15 @@ extern int netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h,
ns_id_t ns_id, int startup);
extern int netlink_route_read (struct zebra_ns *zns);
extern int netlink_neigh_change (struct sockaddr_nl *snl, struct nlmsghdr *h,
ns_id_t ns_id);
extern int netlink_macfdb_read (struct zebra_ns *zns);
extern int netlink_macfdb_read_for_bridge (struct zebra_ns *zns,
struct interface *ifp, struct interface *br_if);
extern int netlink_neigh_read (struct zebra_ns *zns);
extern int netlink_neigh_read_for_vlan (struct zebra_ns *zns,
struct interface *vlan_if);
#endif /* HAVE_NETLINK */
#endif /* _ZEBRA_RT_NETLINK_H */

View File

@ -29,6 +29,7 @@
#include "sockunion.h"
#include "log.h"
#include "privs.h"
#include "vxlan.h"
#include "zebra/debug.h"
#include "zebra/rib.h"
@ -426,3 +427,41 @@ kernel_get_ipmr_sg_stats (void *mroute)
{
return 0;
}
int
kernel_add_vtep (vni_t vni, struct interface *ifp, struct in_addr *vtep_ip)
{
return 0;
}
int
kernel_del_vtep (vni_t vni, struct interface *ifp, struct in_addr *vtep_ip)
{
return 0;
}
int
kernel_add_mac (struct interface *ifp, vlanid_t vid,
struct ethaddr *mac, struct in_addr vtep_ip,
u_char sticky)
{
return 0;
}
int
kernel_del_mac (struct interface *ifp, vlanid_t vid,
struct ethaddr *mac, struct in_addr vtep_ip, int local)
{
return 0;
}
int kernel_add_neigh (struct interface *ifp, struct ipaddr *ip,
struct ethaddr *mac)
{
return 0;
}
int kernel_del_neigh (struct interface *ifp, struct ipaddr *ip)
{
return 0;
}

View File

@ -237,3 +237,23 @@ route_read (struct zebra_ns *zns)
exit:
close (dev);
}
/* Only implemented for netlink method */
void
macfdb_read (struct zebra_ns *zns)
{
}
void macfdb_read_for_bridge (struct zebra_ns *zns, struct interface *ifp,
struct interface *br_if)
{
}
void
neigh_read (struct zebra_ns *zns)
{
}
void neigh_read_for_vlan (struct zebra_ns *zns, struct interface *vlan_if)
{
}

View File

@ -29,3 +29,24 @@ void route_read (struct zebra_ns *zns)
{
netlink_route_read (zns);
}
void macfdb_read (struct zebra_ns *zns)
{
netlink_macfdb_read (zns);
}
void macfdb_read_for_bridge (struct zebra_ns *zns, struct interface *ifp,
struct interface *br_if)
{
netlink_macfdb_read_for_bridge (zns, ifp, br_if);
}
void neigh_read (struct zebra_ns *zns)
{
netlink_neigh_read (zns);
}
void neigh_read_for_vlan (struct zebra_ns *zns, struct interface *vlan_if)
{
netlink_neigh_read_for_vlan (zns, vlan_if);
}

View File

@ -83,3 +83,23 @@ route_read (struct zebra_ns *zns)
return;
}
/* Only implemented for the netlink method. */
void
macfdb_read (struct zebra_ns *zns)
{
}
void macfdb_read_for_bridge (struct zebra_ns *zns, struct interface *ifp,
struct interface *br_if)
{
}
void
neigh_read (struct zebra_ns *zns)
{
}
void neigh_read_for_vlan (struct zebra_ns *zns, struct interface *vlan_if)
{
}

251
zebra/zebra_l2.c Normal file
View File

@ -0,0 +1,251 @@
/*
* Zebra Layer-2 interface handling code
* Copyright (C) 2016, 2017 Cumulus Networks, Inc.
*
* This file is part of FRR.
*
* FRR 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.
*
* FRR 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 FRR; 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 "if.h"
#include "prefix.h"
#include "table.h"
#include "memory.h"
#include "log.h"
#include "linklist.h"
#include "stream.h"
#include "hash.h"
#include "jhash.h"
#include "zebra/rib.h"
#include "zebra/rt.h"
#include "zebra/zebra_ns.h"
#include "zebra/zserv.h"
#include "zebra/debug.h"
#include "zebra/interface.h"
#include "zebra/zebra_memory.h"
#include "zebra/zebra_vrf.h"
#include "zebra/rt_netlink.h"
#include "zebra/zebra_l2.h"
#include "zebra/zebra_vxlan.h"
/* definitions */
/* static function declarations */
/* Private functions */
static void
map_slaves_to_bridge (struct interface *br_if, int link)
{
struct vrf *vrf;
struct listnode *node;
struct interface *ifp;
RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name)
{
for (ALL_LIST_ELEMENTS_RO (vrf->iflist, node, ifp))
{
struct zebra_if *zif;
struct zebra_l2info_brslave *br_slave;
if (ifp->ifindex == IFINDEX_INTERNAL ||
!ifp->info)
continue;
if (!IS_ZEBRA_IF_BRIDGE_SLAVE (ifp))
continue;
/* NOTE: This assumes 'zebra_l2info_brslave' is the first field
* for any L2 interface.
*/
zif = (struct zebra_if *) ifp->info;
br_slave = &zif->brslave_info;
if (link)
{
if (br_slave->bridge_ifindex == br_if->ifindex)
br_slave->br_if = br_if;
}
else
{
if (br_slave->br_if == br_if)
br_slave->br_if = NULL;
}
}
}
}
/* Public functions */
void
zebra_l2_map_slave_to_bridge (struct zebra_l2info_brslave *br_slave)
{
struct interface *br_if;
/* TODO: Handle change of master */
br_if = if_lookup_by_index_per_ns (zebra_ns_lookup (NS_DEFAULT),
br_slave->bridge_ifindex);
if (br_if)
br_slave->br_if = br_if;
}
void
zebra_l2_unmap_slave_from_bridge (struct zebra_l2info_brslave *br_slave)
{
br_slave->br_if = NULL;
}
/*
* Handle Bridge interface add or update. Update relevant info,
* map slaves (if any) to the bridge.
*/
void
zebra_l2_bridge_add_update (struct interface *ifp,
struct zebra_l2info_bridge *bridge_info,
int add)
{
struct zebra_if *zif;
zif = ifp->info;
assert(zif);
/* Copy over the L2 information. */
memcpy (&zif->l2info.br, bridge_info, sizeof (*bridge_info));
/* Link all slaves to this bridge */
map_slaves_to_bridge (ifp, 1);
}
/*
* Handle Bridge interface delete.
*/
void
zebra_l2_bridge_del (struct interface *ifp)
{
/* Unlink all slaves to this bridge */
map_slaves_to_bridge (ifp, 0);
}
/*
* Update L2 info for a VLAN interface. Only relevant parameter is the
* VLAN Id and this cannot change.
*/
void
zebra_l2_vlanif_update (struct interface *ifp,
struct zebra_l2info_vlan *vlan_info)
{
struct zebra_if *zif;
zif = ifp->info;
assert(zif);
/* Copy over the L2 information. */
memcpy (&zif->l2info.vl, vlan_info, sizeof (*vlan_info));
}
/*
* Update L2 info for a VxLAN interface. This is called upon interface
* addition as well as update. Upon add, need to invoke the VNI create
* function. Upon update, the params of interest are the local tunnel
* IP and VLAN mapping, but the latter is handled separately.
*/
void
zebra_l2_vxlanif_add_update (struct interface *ifp,
struct zebra_l2info_vxlan *vxlan_info,
int add)
{
struct zebra_if *zif;
struct in_addr old_vtep_ip;
zif = ifp->info;
assert(zif);
if (add)
{
memcpy (&zif->l2info.vxl, vxlan_info, sizeof (*vxlan_info));
zebra_vxlan_if_add (ifp);
return;
}
old_vtep_ip = zif->l2info.vxl.vtep_ip;
if (IPV4_ADDR_SAME(&old_vtep_ip, &vxlan_info->vtep_ip))
return;
zif->l2info.vxl.vtep_ip = vxlan_info->vtep_ip;
zebra_vxlan_if_update (ifp, ZEBRA_VXLIF_LOCAL_IP_CHANGE);
}
/*
* Handle change to VLAN to VNI mapping.
*/
void
zebra_l2_vxlanif_update_access_vlan (struct interface *ifp,
vlanid_t access_vlan)
{
struct zebra_if *zif;
vlanid_t old_access_vlan;
zif = ifp->info;
assert(zif);
old_access_vlan = zif->l2info.vxl.access_vlan;
if (old_access_vlan == access_vlan)
return;
zif->l2info.vxl.access_vlan = access_vlan;
zebra_vxlan_if_update (ifp, ZEBRA_VXLIF_VLAN_CHANGE);
}
/*
* Handle VxLAN interface delete.
*/
void
zebra_l2_vxlanif_del (struct interface *ifp)
{
zebra_vxlan_if_del (ifp);
}
/*
* Map or unmap interface from bridge.
* NOTE: It is currently assumped that an interface has to be unmapped
* from a bridge before it can be mapped to another bridge.
*/
void
zebra_l2if_update_bridge_slave (struct interface *ifp,
ifindex_t bridge_ifindex)
{
struct zebra_if *zif;
ifindex_t old_bridge_ifindex;
zif = ifp->info;
assert(zif);
old_bridge_ifindex = zif->brslave_info.bridge_ifindex;
if (old_bridge_ifindex == bridge_ifindex)
return;
zif->brslave_info.bridge_ifindex = bridge_ifindex;
/* Set up or remove link with master */
if (bridge_ifindex != IFINDEX_INTERNAL)
zebra_l2_map_slave_to_bridge (&zif->brslave_info);
else if (old_bridge_ifindex != IFINDEX_INTERNAL)
zebra_l2_unmap_slave_from_bridge (&zif->brslave_info);
/* In the case of VxLAN, invoke the handler for EVPN. */
if (zif->zif_type == ZEBRA_IF_VXLAN)
zebra_vxlan_if_update (ifp, ZEBRA_VXLIF_MASTER_CHANGE);
}

94
zebra/zebra_l2.h Normal file
View File

@ -0,0 +1,94 @@
/*
* Zebra Layer-2 interface Data structures and definitions
* Copyright (C) 2016, 2017 Cumulus Networks, Inc.
*
* This file is part of FRR.
*
* FRR 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.
*
* FRR 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 FRR; see the file COPYING. If not, write to the Free
* Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/
#ifndef _ZEBRA_L2_H
#define _ZEBRA_L2_H
#include <zebra.h>
#include "if.h"
#include "vlan.h"
#include "vxlan.h"
/* zebra L2 interface information - bridge slave (linkage to bridge) */
struct zebra_l2info_brslave
{
ifindex_t bridge_ifindex; /* Bridge Master */
struct interface *br_if; /* Pointer to master */
};
/* zebra L2 interface information - bridge interface */
struct zebra_l2info_bridge
{
u_char vlan_aware; /* VLAN-aware bridge? */
};
/* zebra L2 interface information - VLAN interface */
struct zebra_l2info_vlan
{
vlanid_t vid; /* VLAN id */
};
/* zebra L2 interface information - VXLAN interface */
struct zebra_l2info_vxlan
{
vni_t vni; /* VNI */
struct in_addr vtep_ip; /* Local tunnel IP */
vlanid_t access_vlan; /* Access VLAN - for VLAN-aware bridge. */
};
union zebra_l2if_info
{
struct zebra_l2info_bridge br;
struct zebra_l2info_vlan vl;
struct zebra_l2info_vxlan vxl;
};
/* NOTE: These macros are to be invoked only in the "correct" context.
* IOW, the macro VNI_FROM_ZEBRA_IF() will assume the interface is
* of type ZEBRA_IF_VXLAN.
*/
#define VNI_FROM_ZEBRA_IF(zif) (zif)->l2info.vxl.vni
#define VLAN_ID_FROM_ZEBRA_IF(zif) (zif)->l2info.vl.vid
#define IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(zif) \
((zif)->l2info.br.vlan_aware == 1)
extern void zebra_l2_map_slave_to_bridge (struct zebra_l2info_brslave *br_slave);
extern void zebra_l2_unmap_slave_from_bridge (struct zebra_l2info_brslave *br_slave);
extern void zebra_l2_bridge_add_update (struct interface *ifp,
struct zebra_l2info_bridge *bridge_info,
int add);
extern void zebra_l2_bridge_del (struct interface *ifp);
extern void zebra_l2_vlanif_update (struct interface *ifp,
struct zebra_l2info_vlan *vlan_info);
extern void zebra_l2_vxlanif_add_update (struct interface *ifp,
struct zebra_l2info_vxlan *vxlan_info,
int add);
extern void zebra_l2_vxlanif_update_access_vlan (struct interface *ifp,
vlanid_t access_vlan);
extern void zebra_l2_vxlanif_del (struct interface *ifp);
extern void zebra_l2if_update_bridge_slave (struct interface *ifp,
ifindex_t bridge_ifindex);
#endif /* _ZEBRA_L2_H */

76
zebra/zebra_l2_null.c Normal file
View File

@ -0,0 +1,76 @@
/*
* Zebra Layer-2 interface Data structures and definitions
* Copyright (C) 2016, 2017 Cumulus Networks, Inc.
*
* This file is part of FRR.
*
* FRR 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.
*
* FRR 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 FRR; 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 "if.h"
#include "zebra/debug.h"
#include "zebra/zserv.h"
#include "zebra/rib.h"
#include "zebra/zebra_vrf.h"
#include "zebra/zebra_l2.h"
void zebra_l2_map_slave_to_bridge (struct zebra_l2info_brslave *br_slave)
{
}
void
zebra_l2_unmap_slave_from_bridge (struct zebra_l2info_brslave *br_slave)
{
}
void zebra_l2_bridge_add_update (struct interface *ifp,
struct zebra_l2info_bridge *bridge_info,
int add)
{
}
void zebra_l2_bridge_del (struct interface *ifp)
{
}
void zebra_l2_vlanif_update (struct interface *ifp,
struct zebra_l2info_vlan *vlan_info)
{
}
void zebra_l2_vxlanif_add_update (struct interface *ifp,
struct zebra_l2info_vxlan *vxlan_info,
int add)
{
}
void
zebra_l2_vxlanif_update_access_vlan (struct interface *ifp,
vlanid_t access_vlan)
{
}
void zebra_l2_vxlanif_del (struct interface *ifp)
{
}
void
zebra_l2if_update_bridge_slave (struct interface *ifp,
ifindex_t bridge_ifindex)
{
}

View File

@ -37,6 +37,7 @@
#include "zebra/zebra_static.h"
#include "zebra/interface.h"
#include "zebra/zebra_mpls.h"
#include "zebra/zebra_vxlan.h"
extern struct zebra_t zebrad;
@ -244,6 +245,9 @@ zebra_vrf_delete (struct vrf *vrf)
rib_close_table (zvrf->other_table[afi][table_id]);
}
/* Cleanup Vxlan table and update kernel */
zebra_vxlan_close_tables (zvrf);
zebra_mpls_close_tables (zvrf);
for (ALL_LIST_ELEMENTS_RO (vrf->iflist, node, ifp))
@ -421,6 +425,7 @@ zebra_vrf_alloc (void)
zvrf->import_check_table[afi] = table;
}
zebra_vxlan_init_tables (zvrf);
zebra_mpls_init_tables (zvrf);
return zvrf;

View File

@ -95,6 +95,15 @@ struct zebra_vrf
u_int16_t mpls_flags;
#define MPLS_FLAG_SCHEDULE_LSPS (1 << 0)
/*
* VNI hash table (for EVPN). Only in default instance.
*/
struct hash *vni_table;
/*
* Whether EVPN is enabled or not.
*/
int advertise_all_vni;
/* Route Installs */
uint64_t installs;
uint64_t removals;

View File

@ -32,6 +32,7 @@
#include "mpls.h"
#include "routemap.h"
#include "srcdest_table.h"
#include "vxlan.h"
#include "zebra/zserv.h"
#include "zebra/zebra_vrf.h"
@ -41,6 +42,7 @@
#include "zebra/zebra_routemap.h"
#include "zebra/zebra_static.h"
#include "lib/json.h"
#include "zebra/zebra_vxlan.h"
extern int allow_delete;
@ -54,6 +56,9 @@ static void vty_show_ip_route_detail (struct vty *vty, struct route_node *rn,
#define ONE_DAY_SECOND 60*60*24
#define ONE_WEEK_SECOND 60*60*24*7
/* VNI range as per RFC 7432 */
#define CMD_VNI_RANGE "(1-16777215)"
/* General function for static route. */
int
zebra_static_ipv4 (struct vty *vty, safi_t safi, int add_cmd,
@ -3044,6 +3049,237 @@ DEFUN (show_vrf,
return CMD_SUCCESS;
}
DEFUN (show_evpn_vni,
show_evpn_vni_cmd,
"show evpn vni",
SHOW_STR
"EVPN\n"
"VxLAN information\n")
{
struct zebra_vrf *zvrf;
zvrf = vrf_info_lookup(VRF_DEFAULT);
zebra_vxlan_print_vnis(vty, zvrf);
return CMD_SUCCESS;
}
DEFUN (show_evpn_vni_vni,
show_evpn_vni_vni_cmd,
"show evpn vni " CMD_VNI_RANGE,
SHOW_STR
"EVPN\n"
"VxLAN Network Identifier\n"
"VNI number\n")
{
struct zebra_vrf *zvrf;
vni_t vni;
vni = strtoul(argv[3]->arg, NULL, 10);
zvrf = vrf_info_lookup(VRF_DEFAULT);
zebra_vxlan_print_vni(vty, zvrf, vni);
return CMD_SUCCESS;
}
DEFUN (show_evpn_mac_vni,
show_evpn_mac_vni_cmd,
"show evpn mac vni " CMD_VNI_RANGE,
SHOW_STR
"EVPN\n"
"MAC addresses\n"
"VxLAN Network Identifier\n"
"VNI number\n")
{
struct zebra_vrf *zvrf;
vni_t vni;
vni = strtoul(argv[4]->arg, NULL, 10);
zvrf = vrf_info_lookup(VRF_DEFAULT);
zebra_vxlan_print_macs_vni(vty, zvrf, vni);
return CMD_SUCCESS;
}
DEFUN (show_evpn_mac_vni_all,
show_evpn_mac_vni_all_cmd,
"show evpn mac vni all",
SHOW_STR
"EVPN\n"
"MAC addresses\n"
"VxLAN Network Identifier\n"
"All VNIs\n")
{
struct zebra_vrf *zvrf;
zvrf = vrf_info_lookup(VRF_DEFAULT);
zebra_vxlan_print_macs_all_vni(vty, zvrf);
return CMD_SUCCESS;
}
DEFUN (show_evpn_mac_vni_all_vtep,
show_evpn_mac_vni_all_vtep_cmd,
"show evpn mac vni all vtep A.B.C.D",
SHOW_STR
"EVPN\n"
"MAC addresses\n"
"VxLAN Network Identifier\n"
"All VNIs\n"
"Remote VTEP\n"
"Remote VTEP IP address\n")
{
struct zebra_vrf *zvrf;
struct in_addr vtep_ip;
if (!inet_aton (argv[6]->arg, &vtep_ip))
{
vty_out (vty, "%% Malformed VTEP IP address\n");
return CMD_WARNING;
}
zvrf = vrf_info_lookup(VRF_DEFAULT);
zebra_vxlan_print_macs_all_vni_vtep(vty, zvrf, vtep_ip);
return CMD_SUCCESS;
}
DEFUN (show_evpn_mac_vni_mac,
show_evpn_mac_vni_mac_cmd,
"show evpn mac vni " CMD_VNI_RANGE " mac WORD",
SHOW_STR
"EVPN\n"
"MAC addresses\n"
"VxLAN Network Identifier\n"
"VNI number\n"
"MAC\n"
"MAC address (e.g., 00:e0:ec:20:12:62)\n")
{
struct zebra_vrf *zvrf;
vni_t vni;
struct ethaddr mac;
vni = strtoul(argv[4]->arg, NULL, 10);
if (!prefix_str2mac (argv[6]->arg, &mac))
{
vty_out (vty, "%% Malformed MAC address");
return CMD_WARNING;
}
zvrf = vrf_info_lookup(VRF_DEFAULT);
zebra_vxlan_print_specific_mac_vni(vty, zvrf, vni, &mac);
return CMD_SUCCESS;
}
DEFUN (show_evpn_mac_vni_vtep,
show_evpn_mac_vni_vtep_cmd,
"show evpn mac vni " CMD_VNI_RANGE " vtep A.B.C.D",
SHOW_STR
"EVPN\n"
"MAC addresses\n"
"VxLAN Network Identifier\n"
"VNI number\n"
"Remote VTEP\n"
"Remote VTEP IP address\n")
{
struct zebra_vrf *zvrf;
vni_t vni;
struct in_addr vtep_ip;
vni = strtoul(argv[4]->arg, NULL, 10);
if (!inet_aton (argv[6]->arg, &vtep_ip))
{
vty_out (vty, "%% Malformed VTEP IP address\n");
return CMD_WARNING;
}
zvrf = vrf_info_lookup(VRF_DEFAULT);
zebra_vxlan_print_macs_vni_vtep(vty, zvrf, vni, vtep_ip);
return CMD_SUCCESS;
}
DEFUN (show_evpn_neigh_vni,
show_evpn_neigh_vni_cmd,
"show evpn arp-cache vni " CMD_VNI_RANGE,
SHOW_STR
"EVPN\n"
"ARP and ND cache\n"
"VxLAN Network Identifier\n"
"VNI number\n")
{
struct zebra_vrf *zvrf;
vni_t vni;
vni = strtoul(argv[4]->arg, NULL, 10);
zvrf = vrf_info_lookup(VRF_DEFAULT);
zebra_vxlan_print_neigh_vni(vty, zvrf, vni);
return CMD_SUCCESS;
}
DEFUN (show_evpn_neigh_vni_all,
show_evpn_neigh_vni_all_cmd,
"show evpn arp-cache vni all",
SHOW_STR
"EVPN\n"
"ARP and ND cache\n"
"VxLAN Network Identifier\n"
"All VNIs\n")
{
struct zebra_vrf *zvrf;
zvrf = vrf_info_lookup(VRF_DEFAULT);
zebra_vxlan_print_neigh_all_vni(vty, zvrf);
return CMD_SUCCESS;
}
DEFUN (show_evpn_neigh_vni_neigh,
show_evpn_neigh_vni_neigh_cmd,
"show evpn arp-cache vni " CMD_VNI_RANGE " ip WORD",
SHOW_STR
"EVPN\n"
"ARP and ND cache\n"
"VxLAN Network Identifier\n"
"VNI number\n"
"Neighbor\n"
"Neighbor address (IPv4 or IPv6 address)\n")
{
struct zebra_vrf *zvrf;
vni_t vni;
struct ipaddr ip;
vni = strtoul(argv[4]->arg, NULL, 10);
if (str2ipaddr (argv[6]->arg, &ip) != 0)
{
vty_out (vty, "%% Malformed Neighbor address\n");
return CMD_WARNING;
}
zvrf = vrf_info_lookup(VRF_DEFAULT);
zebra_vxlan_print_specific_neigh_vni(vty, zvrf, vni, &ip);
return CMD_SUCCESS;
}
DEFUN (show_evpn_neigh_vni_vtep,
show_evpn_neigh_vni_vtep_cmd,
"show evpn arp-cache vni " CMD_VNI_RANGE " vtep A.B.C.D",
SHOW_STR
"EVPN\n"
"ARP and ND cache\n"
"VxLAN Network Identifier\n"
"VNI number\n"
"Remote VTEP\n"
"Remote VTEP IP address\n")
{
struct zebra_vrf *zvrf;
vni_t vni;
struct in_addr vtep_ip;
vni = strtoul(argv[4]->arg, NULL, 10);
if (!inet_aton (argv[6]->arg, &vtep_ip))
{
vty_out (vty, "%% Malformed VTEP IP address\n");
return CMD_WARNING;
}
zvrf = vrf_info_lookup(VRF_DEFAULT);
zebra_vxlan_print_neigh_vni_vtep(vty, zvrf, vni, vtep_ip);
return CMD_SUCCESS;
}
/* Static ip route configuration write function. */
static int
zebra_ip_config (struct vty *vty)
@ -3234,4 +3470,16 @@ zebra_vty_init (void)
install_element (VIEW_NODE, &show_ipv6_route_vrf_all_prefix_cmd);
install_element (VIEW_NODE, &show_ipv6_mroute_vrf_all_cmd);
install_element (VIEW_NODE, &show_evpn_vni_cmd);
install_element (VIEW_NODE, &show_evpn_vni_vni_cmd);
install_element (VIEW_NODE, &show_evpn_mac_vni_cmd);
install_element (VIEW_NODE, &show_evpn_mac_vni_all_cmd);
install_element (VIEW_NODE, &show_evpn_mac_vni_all_vtep_cmd);
install_element (VIEW_NODE, &show_evpn_mac_vni_mac_cmd);
install_element (VIEW_NODE, &show_evpn_mac_vni_vtep_cmd);
install_element (VIEW_NODE, &show_evpn_neigh_vni_cmd);
install_element (VIEW_NODE, &show_evpn_neigh_vni_all_cmd);
install_element (VIEW_NODE, &show_evpn_neigh_vni_neigh_cmd);
install_element (VIEW_NODE, &show_evpn_neigh_vni_vtep_cmd);
}

3380
zebra/zebra_vxlan.c Normal file

File diff suppressed because it is too large Load Diff

108
zebra/zebra_vxlan.h Normal file
View File

@ -0,0 +1,108 @@
/*
* Zebra VxLAN (EVPN) Data structures and definitions
* These are public definitions referenced by other files.
* Copyright (C) 2016, 2017 Cumulus Networks, Inc.
*
* This file is part of FRR.
*
* FRR 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.
*
* FRR 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 FRR; see the file COPYING. If not, write to the Free
* Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/
#ifndef _ZEBRA_VXLAN_H
#define _ZEBRA_VXLAN_H
#include <zebra.h>
#include "linklist.h"
#include "if.h"
#include "vlan.h"
#include "vxlan.h"
#include "zebra/zebra_vrf.h"
/* Is EVPN enabled? */
#define EVPN_ENABLED(zvrf) (zvrf)->advertise_all_vni
/* VxLAN interface change flags of interest. */
#define ZEBRA_VXLIF_LOCAL_IP_CHANGE 0x1
#define ZEBRA_VXLIF_MASTER_CHANGE 0x2
#define ZEBRA_VXLIF_VLAN_CHANGE 0x4
extern void zebra_vxlan_print_macs_vni (struct vty *vty, struct zebra_vrf *zvrf,
vni_t vni);
extern void zebra_vxlan_print_macs_all_vni (struct vty *vty,
struct zebra_vrf *zvrf);
extern void zebra_vxlan_print_macs_all_vni_vtep (struct vty *vty,
struct zebra_vrf *zvrf,
struct in_addr vtep_ip);
extern void zebra_vxlan_print_specific_mac_vni (struct vty *vty,
struct zebra_vrf *zvrf, vni_t vni, struct ethaddr *mac);
extern void zebra_vxlan_print_macs_vni_vtep (struct vty *vty,
struct zebra_vrf *zvrf, vni_t vni, struct in_addr vtep_ip);
extern void zebra_vxlan_print_neigh_vni (struct vty *vty, struct zebra_vrf *zvrf,
vni_t vni);
extern void zebra_vxlan_print_neigh_all_vni (struct vty *vty,
struct zebra_vrf *zvrf);
extern void zebra_vxlan_print_specific_neigh_vni (struct vty *vty,
struct zebra_vrf *zvrf, vni_t vni, struct ipaddr *ip);
extern void zebra_vxlan_print_neigh_vni_vtep (struct vty *vty,
struct zebra_vrf *zvrf, vni_t vni, struct in_addr vtep_ip);
extern void zebra_vxlan_print_vni (struct vty *vty, struct zebra_vrf *zvrf, vni_t vni);
extern void zebra_vxlan_print_vnis (struct vty *vty, struct zebra_vrf *zvrf);
extern int zebra_vxlan_svi_up (struct interface *ifp, struct interface *link_if);
extern int zebra_vxlan_svi_down (struct interface *ifp, struct interface *link_if);
extern int zebra_vxlan_local_neigh_add_update (struct interface *ifp,
struct interface *link_if,
struct ipaddr *ip,
struct ethaddr *macaddr,
u_int16_t state,
u_char ext_learned);
extern int zebra_vxlan_local_neigh_del (struct interface *ifp,
struct interface *link_if,
struct ipaddr *ip);
extern int zebra_vxlan_remote_macip_add (struct zserv *client, int sock,
u_short length, struct zebra_vrf *zvrf);
extern int zebra_vxlan_remote_macip_del (struct zserv *client, int sock,
u_short length, struct zebra_vrf *zvrf);
extern int zebra_vxlan_local_mac_add_update (struct interface *ifp,
struct interface *br_if,
struct ethaddr *mac, vlanid_t vid,
u_char sticky);
extern int zebra_vxlan_local_mac_del (struct interface *ifp,
struct interface *br_if,
struct ethaddr *mac, vlanid_t vid);
extern int zebra_vxlan_check_readd_remote_mac (struct interface *ifp,
struct interface *br_if,
struct ethaddr *mac, vlanid_t vid);
extern int zebra_vxlan_check_del_local_mac (struct interface *ifp,
struct interface *br_if,
struct ethaddr *mac, vlanid_t vid);
extern int zebra_vxlan_if_up (struct interface *ifp);
extern int zebra_vxlan_if_down (struct interface *ifp);
extern int zebra_vxlan_if_add (struct interface *ifp);
extern int zebra_vxlan_if_update (struct interface *ifp, u_int16_t chgflags);
extern int zebra_vxlan_if_del (struct interface *ifp);
extern int zebra_vxlan_remote_vtep_add (struct zserv *client, int sock,
u_short length, struct zebra_vrf *zvrf);
extern int zebra_vxlan_remote_vtep_del (struct zserv *client, int sock,
u_short length, struct zebra_vrf *zvrf);
extern int zebra_vxlan_advertise_all_vni (struct zserv *client, int sock,
u_short length, struct zebra_vrf *zvrf);
extern void zebra_vxlan_init_tables (struct zebra_vrf *zvrf);
extern void zebra_vxlan_close_tables (struct zebra_vrf *);
#endif /* _ZEBRA_VXLAN_H */

197
zebra/zebra_vxlan_null.c Normal file
View File

@ -0,0 +1,197 @@
/*
* Zebra VxLAN (EVPN)
* Copyright (C) 2016, 2017 Cumulus Networks, Inc.
*
* This file is part of FRR.
*
* FRR 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.
*
* FRR 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 FRR; 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 "if.h"
#include "zebra/debug.h"
#include "zebra/zserv.h"
#include "zebra/rib.h"
#include "zebra/zebra_vrf.h"
#include "zebra/zebra_l2.h"
#include "zebra/zebra_vxlan.h"
void
zebra_vxlan_print_macs_vni (struct vty *vty, struct zebra_vrf *zvrf, vni_t vni)
{
}
void zebra_vxlan_print_macs_all_vni (struct vty *vty, struct zebra_vrf *zvrf)
{
}
void zebra_vxlan_print_macs_all_vni_vtep (struct vty *vty, struct zebra_vrf *zvrf, struct in_addr vtep_ip)
{
}
void
zebra_vxlan_print_specific_mac_vni (struct vty *vty, struct zebra_vrf *zvrf,
vni_t vni, struct ethaddr *mac)
{
}
void
zebra_vxlan_print_macs_vni_vtep (struct vty *vty, struct zebra_vrf *zvrf,
vni_t vni, struct in_addr vtep_ip)
{
}
void
zebra_vxlan_print_neigh_vni (struct vty *vty, struct zebra_vrf *zvrf,
vni_t vni)
{
}
void
zebra_vxlan_print_neigh_all_vni (struct vty *vty, struct zebra_vrf *zvrf)
{
}
void
zebra_vxlan_print_specific_neigh_vni (struct vty *vty, struct zebra_vrf *zvrf,
vni_t vni, struct ipaddr *ip)
{
}
void zebra_vxlan_print_neigh_vni_vtep (struct vty *vty, struct zebra_vrf *zvrf,
vni_t vni, struct in_addr vtep_ip)
{
}
void
zebra_vxlan_print_vni (struct vty *vty, struct zebra_vrf *zvrf, vni_t vni)
{
}
void
zebra_vxlan_print_vnis (struct vty *vty, struct zebra_vrf *zvrf)
{
}
int zebra_vxlan_svi_up (struct interface *ifp, struct interface *link_if)
{
return 0;
}
int zebra_vxlan_svi_down (struct interface *ifp, struct interface *link_if)
{
return 0;
}
int zebra_vxlan_remote_macip_add (struct zserv *client, int sock,
u_short length, struct zebra_vrf *zvrf)
{
return 0;
}
int zebra_vxlan_remote_macip_del (struct zserv *client, int sock,
u_short length, struct zebra_vrf *zvrf)
{
return 0;
}
int zebra_vxlan_local_mac_add_update (struct interface *ifp,
struct interface *br_if,
struct ethaddr *mac, vlanid_t vid,
u_char sticky)
{
return 0;
}
int zebra_vxlan_local_mac_del (struct interface *ifp,
struct interface *br_if,
struct ethaddr *mac, vlanid_t vid)
{
return 0;
}
int zebra_vxlan_check_readd_remote_mac (struct interface *ifp,
struct interface *br_if,
struct ethaddr *mac, vlanid_t vid)
{
return 0;
}
int zebra_vxlan_check_del_local_mac (struct interface *ifp,
struct interface *br_if,
struct ethaddr *mac, vlanid_t vid)
{
return 0;
}
int
zebra_vxlan_if_up (struct interface *ifp)
{
return 0;
}
int
zebra_vxlan_if_down (struct interface *ifp)
{
return 0;
}
int
zebra_vxlan_if_add (struct interface *ifp)
{
return 0;
}
int
zebra_vxlan_if_update (struct interface *ifp, u_int16_t chgflags)
{
return 0;
}
int
zebra_vxlan_if_del (struct interface *ifp)
{
return 0;
}
int zebra_vxlan_remote_vtep_add (struct zserv *client, int sock,
u_short length, struct zebra_vrf *zvrf)
{
return 0;
}
int zebra_vxlan_remote_vtep_del (struct zserv *client, int sock,
u_short length, struct zebra_vrf *zvrf)
{
return 0;
}
int zebra_vxlan_advertise_all_vni (struct zserv *client, int sock,
u_short length, struct zebra_vrf *zvrf)
{
return 0;
}
void
zebra_vxlan_init_tables (struct zebra_vrf *zvrf)
{
}
void
zebra_vxlan_close_tables (struct zebra_vrf *zvrf)
{
}

199
zebra/zebra_vxlan_private.h Normal file
View File

@ -0,0 +1,199 @@
/*
* Zebra VxLAN (EVPN) Data structures and definitions
* These are "internal" to this function.
* Copyright (C) 2016, 2017 Cumulus Networks, Inc.
*
* This file is part of FRR.
*
* FRR 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.
*
* FRR 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 FRR; see the file COPYING. If not, write to the Free
* Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/
#ifndef _ZEBRA_VXLAN_PRIVATE_H
#define _ZEBRA_VXLAN_PRIVATE_H
#include <zebra.h>
#include <zebra.h>
#include "if.h"
#include "linklist.h"
/* definitions */
typedef struct zebra_vni_t_ zebra_vni_t;
typedef struct zebra_vtep_t_ zebra_vtep_t;
typedef struct zebra_mac_t_ zebra_mac_t;
typedef struct zebra_neigh_t_ zebra_neigh_t;
/*
* VTEP info
*
* Right now, this just has each remote VTEP's IP address.
*/
struct zebra_vtep_t_
{
/* Remote IP. */
/* NOTE: Can only be IPv4 right now. */
struct in_addr vtep_ip;
/* Links. */
struct zebra_vtep_t_ *next;
struct zebra_vtep_t_ *prev;
};
/*
* VNI hash table
*
* Contains information pertaining to a VNI:
* - the list of remote VTEPs (with this VNI)
*/
struct zebra_vni_t_
{
/* VNI - key */
vni_t vni;
/* Corresponding VxLAN interface. */
struct interface *vxlan_if;
/* List of remote VTEPs */
zebra_vtep_t *vteps;
/* Local IP */
struct in_addr local_vtep_ip;
/* List of local or remote MAC */
struct hash *mac_table;
/* List of local or remote neighbors (MAC+IP) */
struct hash *neigh_table;
};
/*
* MAC hash table.
*
* This table contains the MAC addresses pertaining to this VNI.
* This includes local MACs learnt on an attached VLAN that maps
* to this VNI as well as remote MACs learnt and installed by BGP.
* Local MACs will be known either on a VLAN sub-interface or
* on (port, VLAN); however, it is sufficient for zebra to maintain
* against the VNI i.e., it does not need to retain the local "port"
* information. The correct VNI will be obtained as zebra maintains
* the mapping (of VLAN to VNI).
*/
struct zebra_mac_t_
{
/* MAC address. */
struct ethaddr macaddr;
u_int32_t flags;
#define ZEBRA_MAC_LOCAL 0x01
#define ZEBRA_MAC_REMOTE 0x02
#define ZEBRA_MAC_AUTO 0x04 /* Auto created for neighbor. */
#define ZEBRA_MAC_STICKY 0x08 /* Static MAC */
/* Local or remote info. */
union
{
struct
{
ifindex_t ifindex;
vlanid_t vid;
} local;
struct in_addr r_vtep_ip;
} fwd_info;
u_int32_t neigh_refcnt;
};
/*
* Context for MAC hash walk - used by callbacks.
*/
struct mac_walk_ctx
{
zebra_vni_t *zvni; /* VNI hash */
struct zebra_vrf *zvrf; /* VRF - for client notification. */
int uninstall; /* uninstall from kernel? */
int upd_client; /* uninstall from client? */
u_int32_t flags;
#define DEL_LOCAL_MAC 0x1
#define DEL_REMOTE_MAC 0x2
#define DEL_ALL_MAC (DEL_LOCAL_MAC | DEL_REMOTE_MAC)
#define DEL_REMOTE_MAC_FROM_VTEP 0x4
#define SHOW_REMOTE_MAC_FROM_VTEP 0x8
struct in_addr r_vtep_ip; /* To walk MACs from specific VTEP */
struct vty *vty; /* Used by VTY handlers */
u_int32_t count; /* Used by VTY handlers */
};
/*
* Neighbor hash table.
*
* This table contains the neighbors (IP to MAC bindings) pertaining to
* this VNI. This includes local neighbors learnt on the attached VLAN
* device that maps to this VNI as well as remote neighbors learnt and
* installed by BGP.
* Local neighbors will be known against the VLAN device (SVI); however,
* it is sufficient for zebra to maintain against the VNI. The correct
* VNI will be obtained as zebra maintains the mapping (of VLAN to VNI).
*/
struct zebra_neigh_t_
{
/* IP address. */
struct ipaddr ip;
/* MAC address. */
struct ethaddr emac;
/* Underlying interface. */
ifindex_t ifindex;
u_int32_t flags;
#define ZEBRA_NEIGH_LOCAL 0x01
#define ZEBRA_NEIGH_REMOTE 0x02
/* Remote VTEP IP - applicable only for remote neighbors. */
struct in_addr r_vtep_ip;
};
/*
* Context for neighbor hash walk - used by callbacks.
*/
struct neigh_walk_ctx
{
zebra_vni_t *zvni; /* VNI hash */
struct zebra_vrf *zvrf; /* VRF - for client notification. */
int uninstall; /* uninstall from kernel? */
int upd_client; /* uninstall from client? */
u_int32_t flags;
#define DEL_LOCAL_NEIGH 0x1
#define DEL_REMOTE_NEIGH 0x2
#define DEL_ALL_NEIGH (DEL_LOCAL_NEIGH | DEL_REMOTE_NEIGH)
#define DEL_REMOTE_NEIGH_FROM_VTEP 0x4
#define SHOW_REMOTE_NEIGH_FROM_VTEP 0x8
struct in_addr r_vtep_ip; /* To walk neighbors from specific VTEP */
struct vty *vty; /* Used by VTY handlers */
u_int32_t count; /* Used by VTY handlers */
u_char addr_width; /* Used by VTY handlers */
};
#endif /* _ZEBRA_VXLAN_PRIVATE_H */

View File

@ -54,6 +54,7 @@
#include "zebra/zebra_mpls.h"
#include "zebra/zebra_mroute.h"
#include "zebra/label_manager.h"
#include "zebra/zebra_vxlan.h"
/* Event list of zebra. */
enum event { ZEBRA_SERV, ZEBRA_READ, ZEBRA_WRITE };
@ -2434,6 +2435,21 @@ zebra_client_read (struct thread *thread)
case ZEBRA_FEC_UNREGISTER:
zserv_fec_unregister (client, sock, length);
break;
case ZEBRA_ADVERTISE_ALL_VNI:
zebra_vxlan_advertise_all_vni (client, sock, length, zvrf);
break;
case ZEBRA_REMOTE_VTEP_ADD:
zebra_vxlan_remote_vtep_add (client, sock, length, zvrf);
break;
case ZEBRA_REMOTE_VTEP_DEL:
zebra_vxlan_remote_vtep_del (client, sock, length, zvrf);
break;
case ZEBRA_REMOTE_MACIP_ADD:
zebra_vxlan_remote_macip_add (client, sock, length, zvrf);
break;
case ZEBRA_REMOTE_MACIP_DEL:
zebra_vxlan_remote_macip_del (client, sock, length, zvrf);
break;
default:
zlog_info ("Zebra received unknown command %d", command);
break;
@ -2725,6 +2741,10 @@ zebra_show_client_detail (struct vty *vty, struct zserv *client)
client->bfd_peer_upd8_cnt, client->bfd_peer_del_cnt);
vty_out (vty, "Interface Up Notifications: %d\n",client->ifup_cnt);
vty_out (vty, "Interface Down Notifications: %d\n",client->ifdown_cnt);
vty_out (vty, "VNI add notifications: %d\n", client->vniadd_cnt);
vty_out (vty, "VNI delete notifications: %d\n", client->vnidel_cnt);
vty_out (vty, "MAC-IP add notifications: %d\n", client->macipadd_cnt);
vty_out (vty, "MAC-IP delete notifications: %d\n", client->macipdel_cnt);
vty_out (vty, "\n");
return;

View File

@ -105,6 +105,10 @@ struct zserv
u_int32_t vrfdel_cnt;
u_int32_t if_vrfchg_cnt;
u_int32_t bfd_client_reg_cnt;
u_int32_t vniadd_cnt;
u_int32_t vnidel_cnt;
u_int32_t macipadd_cnt;
u_int32_t macipdel_cnt;
time_t connect_time;
time_t last_read_time;
@ -145,6 +149,11 @@ extern void hostinfo_get (void);
extern void rib_init (void);
extern void interface_list (struct zebra_ns *);
extern void route_read (struct zebra_ns *);
extern void macfdb_read (struct zebra_ns *);
extern void macfdb_read_for_bridge (struct zebra_ns *, struct interface *,
struct interface *);
extern void neigh_read (struct zebra_ns *);
extern void neigh_read_for_vlan (struct zebra_ns *, struct interface *);
extern void kernel_init (struct zebra_ns *);
extern void kernel_terminate (struct zebra_ns *);
extern void zebra_route_map_init (void);