mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-07-27 03:33:43 +00:00
Merge pull request #809 from donaldsharp/evpn_plus_struct_attr
Evpn plus struct attr
This commit is contained in:
commit
805d1ca6b0
@ -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@
|
||||
|
859
bgpd/bgp_attr.c
859
bgpd/bgp_attr.c
File diff suppressed because it is too large
Load Diff
@ -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 */
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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 **);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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 */
|
||||
|
2959
bgpd/bgp_evpn.c
2959
bgpd/bgp_evpn.c
File diff suppressed because it is too large
Load Diff
@ -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
232
bgpd/bgp_evpn_private.h
Normal 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 */
|
1967
bgpd/bgp_evpn_vty.c
1967
bgpd/bgp_evpn_vty.c
File diff suppressed because it is too large
Load Diff
@ -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"
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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")
|
||||
|
@ -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 */
|
||||
|
@ -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))
|
||||
{
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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
232
bgpd/bgp_rd.c
Normal 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
74
bgpd/bgp_rd.h
Normal 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 */
|
786
bgpd/bgp_route.c
786
bgpd/bgp_route.c
File diff suppressed because it is too large
Load Diff
@ -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 */
|
||||
|
@ -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))
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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--;
|
||||
|
@ -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);
|
||||
|
@ -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 */
|
||||
|
160
bgpd/bgp_zebra.c
160
bgpd/bgp_zebra.c
@ -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));
|
||||
|
@ -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 */
|
||||
|
15
bgpd/bgpd.c
15
bgpd/bgpd.c
@ -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");
|
||||
|
||||
|
15
bgpd/bgpd.h
15
bgpd/bgpd.h
@ -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)
|
||||
|
@ -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, <, 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:
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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. */
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
16
zebra/rt.h
16
zebra/rt.h
@ -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 */
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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)
|
||||
{
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
251
zebra/zebra_l2.c
Normal 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
94
zebra/zebra_l2.h
Normal 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
76
zebra/zebra_l2_null.c
Normal 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)
|
||||
{
|
||||
}
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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
3380
zebra/zebra_vxlan.c
Normal file
File diff suppressed because it is too large
Load Diff
108
zebra/zebra_vxlan.h
Normal file
108
zebra/zebra_vxlan.h
Normal 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
197
zebra/zebra_vxlan_null.c
Normal 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
199
zebra/zebra_vxlan_private.h
Normal 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 */
|
@ -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;
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user