mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-04-28 21:20:48 +00:00
Merge pull request #1654 from mkanjari/evpn-symm-routing-enhancements
Evpn symmetric routing enhancements
This commit is contained in:
commit
8e71b98f72
@ -1876,6 +1876,9 @@ bgp_attr_ext_communities(struct bgp_attr_parser_args *args)
|
||||
attr->mm_seqnum = bgp_attr_mac_mobility_seqnum(attr, &sticky);
|
||||
attr->sticky = sticky;
|
||||
|
||||
/* Check if this is a Gateway MAC-IP advertisement */
|
||||
attr->default_gw = bgp_attr_default_gw(attr);
|
||||
|
||||
/* Extract the Rmac, if any */
|
||||
bgp_attr_rmac(attr, &attr->rmac);
|
||||
|
||||
@ -2698,8 +2701,9 @@ size_t bgp_packet_mpattr_start(struct stream *s, struct peer *peer, afi_t afi,
|
||||
|
||||
void bgp_packet_mpattr_prefix(struct stream *s, afi_t afi, safi_t safi,
|
||||
struct prefix *p, struct prefix_rd *prd,
|
||||
mpls_label_t *label, int addpath_encode,
|
||||
u_int32_t addpath_tx_id, struct attr *attr)
|
||||
mpls_label_t *label, u_int32_t num_labels,
|
||||
int addpath_encode, u_int32_t addpath_tx_id,
|
||||
struct attr *attr)
|
||||
{
|
||||
if (safi == SAFI_MPLS_VPN) {
|
||||
if (addpath_encode)
|
||||
@ -2711,8 +2715,8 @@ void bgp_packet_mpattr_prefix(struct stream *s, afi_t afi, safi_t safi,
|
||||
stream_put(s, &p->u.prefix, PSIZE(p->prefixlen));
|
||||
} else if (afi == AFI_L2VPN && safi == SAFI_EVPN) {
|
||||
/* EVPN prefix - contents depend on type */
|
||||
bgp_evpn_encode_prefix(s, p, prd, label, attr, addpath_encode,
|
||||
addpath_tx_id);
|
||||
bgp_evpn_encode_prefix(s, p, prd, label, num_labels,
|
||||
attr, addpath_encode, addpath_tx_id);
|
||||
} else if (safi == SAFI_LABELED_UNICAST) {
|
||||
/* Prefix write with label. */
|
||||
stream_put_labeled_prefix(s, p, label);
|
||||
@ -2840,8 +2844,8 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer,
|
||||
struct bpacket_attr_vec_arr *vecarr,
|
||||
struct prefix *p, afi_t afi, safi_t safi,
|
||||
struct peer *from, struct prefix_rd *prd,
|
||||
mpls_label_t *label, int addpath_encode,
|
||||
u_int32_t addpath_tx_id)
|
||||
mpls_label_t *label, u_int32_t num_labels,
|
||||
int addpath_encode, u_int32_t addpath_tx_id)
|
||||
{
|
||||
size_t cp;
|
||||
size_t aspath_sizep;
|
||||
@ -2863,7 +2867,8 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer,
|
||||
|
||||
mpattrlen_pos = bgp_packet_mpattr_start(s, peer, afi, safi,
|
||||
vecarr, attr);
|
||||
bgp_packet_mpattr_prefix(s, afi, safi, p, prd, label,
|
||||
bgp_packet_mpattr_prefix(s, afi, safi, p, prd,
|
||||
label, num_labels,
|
||||
addpath_encode, addpath_tx_id, attr);
|
||||
bgp_packet_mpattr_end(s, mpattrlen_pos);
|
||||
}
|
||||
@ -3295,15 +3300,19 @@ size_t bgp_packet_mpunreach_start(struct stream *s, afi_t afi, safi_t safi)
|
||||
|
||||
void bgp_packet_mpunreach_prefix(struct stream *s, struct prefix *p, afi_t afi,
|
||||
safi_t safi, struct prefix_rd *prd,
|
||||
mpls_label_t *label, int addpath_encode,
|
||||
u_int32_t addpath_tx_id, struct attr *attr)
|
||||
mpls_label_t *label, u_int32_t num_labels,
|
||||
int addpath_encode, u_int32_t addpath_tx_id,
|
||||
struct attr *attr)
|
||||
{
|
||||
u_char wlabel[3] = {0x80, 0x00, 0x00};
|
||||
|
||||
if (safi == SAFI_LABELED_UNICAST)
|
||||
if (safi == SAFI_LABELED_UNICAST) {
|
||||
label = (mpls_label_t *)wlabel;
|
||||
num_labels = 1;
|
||||
}
|
||||
|
||||
return bgp_packet_mpattr_prefix(s, afi, safi, p, prd, label,
|
||||
return bgp_packet_mpattr_prefix(s, afi, safi, p, prd,
|
||||
label, num_labels,
|
||||
addpath_encode, addpath_tx_id, attr);
|
||||
}
|
||||
|
||||
|
@ -162,6 +162,9 @@ struct attr {
|
||||
/* Static MAC for EVPN */
|
||||
u_char sticky;
|
||||
|
||||
/* Flag for default gateway extended community in EVPN */
|
||||
u_char default_gw;
|
||||
|
||||
/* route tag */
|
||||
route_tag_t tag;
|
||||
|
||||
@ -257,7 +260,8 @@ extern bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *,
|
||||
struct bpacket_attr_vec_arr *vecarr,
|
||||
struct prefix *, afi_t, safi_t,
|
||||
struct peer *, struct prefix_rd *,
|
||||
mpls_label_t *, int, u_int32_t);
|
||||
mpls_label_t *, u_int32_t,
|
||||
int, u_int32_t);
|
||||
extern void bgp_dump_routes_attr(struct stream *, struct attr *,
|
||||
struct prefix *);
|
||||
extern int attrhash_cmp(const void *, const void *);
|
||||
@ -305,7 +309,8 @@ extern size_t bgp_packet_mpattr_start(struct stream *s, struct peer *peer,
|
||||
struct attr *attr);
|
||||
extern void bgp_packet_mpattr_prefix(struct stream *s, afi_t afi, safi_t safi,
|
||||
struct prefix *p, struct prefix_rd *prd,
|
||||
mpls_label_t *label, int addpath_encode,
|
||||
mpls_label_t *label, u_int32_t num_labels,
|
||||
int addpath_encode,
|
||||
u_int32_t addpath_tx_id, struct attr *);
|
||||
extern size_t bgp_packet_mpattr_prefix_size(afi_t afi, safi_t safi,
|
||||
struct prefix *p);
|
||||
@ -315,7 +320,8 @@ extern size_t bgp_packet_mpunreach_start(struct stream *s, afi_t afi,
|
||||
safi_t safi);
|
||||
extern void bgp_packet_mpunreach_prefix(struct stream *s, struct prefix *p,
|
||||
afi_t afi, safi_t safi,
|
||||
struct prefix_rd *prd, mpls_label_t *,
|
||||
struct prefix_rd *prd,
|
||||
mpls_label_t *, u_int32_t,
|
||||
int, u_int32_t, struct attr *);
|
||||
extern void bgp_packet_mpunreach_end(struct stream *s, size_t attrlen_pnt);
|
||||
|
||||
|
@ -134,6 +134,36 @@ void bgp_attr_rmac(struct attr *attr,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* return true if attr contains default gw extended community
|
||||
*/
|
||||
uint8_t bgp_attr_default_gw(struct attr *attr)
|
||||
{
|
||||
struct ecommunity *ecom;
|
||||
int i;
|
||||
|
||||
ecom = attr->ecommunity;
|
||||
if (!ecom || !ecom->size)
|
||||
return 0;
|
||||
|
||||
/* If there is a default gw extendd community return true otherwise
|
||||
* return 0 */
|
||||
for (i = 0; i < ecom->size; i++) {
|
||||
u_char *pnt;
|
||||
u_char type, sub_type;
|
||||
|
||||
pnt = (ecom->val + (i * ECOMMUNITY_SIZE));
|
||||
type = *pnt++;
|
||||
sub_type = *pnt++;
|
||||
|
||||
if ((type == ECOMMUNITY_ENCODE_OPAQUE
|
||||
&& sub_type == ECOMMUNITY_EVPN_SUBTYPE_DEF_GW))
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Fetch and return the sequence number from MAC Mobility extended
|
||||
* community, if present, else 0.
|
||||
|
@ -62,5 +62,6 @@ extern int bgp_build_evpn_prefix(int type, uint32_t eth_tag,
|
||||
extern void bgp_attr_rmac(struct attr *attr, struct ethaddr *rmac);
|
||||
extern u_int32_t bgp_attr_mac_mobility_seqnum(struct attr *attr,
|
||||
u_char *sticky);
|
||||
extern uint8_t bgp_attr_default_gw(struct attr *attr);
|
||||
|
||||
#endif /* _QUAGGA_BGP_ATTR_EVPN_H */
|
||||
|
@ -2017,8 +2017,9 @@ int bgp_debug_zebra(struct prefix *p)
|
||||
const char *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)
|
||||
mpls_label_t *label, u_int32_t num_labels,
|
||||
int addpath_valid, u_int32_t addpath_id,
|
||||
char *str, int size)
|
||||
{
|
||||
char rd_buf[RD_ADDRSTRLEN];
|
||||
char pfx_buf[PREFIX_STRLEN];
|
||||
@ -2041,11 +2042,19 @@ const char *bgp_debug_rdpfxpath2str(afi_t afi, safi_t safi,
|
||||
addpath_id);
|
||||
|
||||
tag_buf[0] = '\0';
|
||||
if (bgp_labeled_safi(safi) && label) {
|
||||
u_int32_t label_value;
|
||||
if (bgp_labeled_safi(safi) && num_labels) {
|
||||
|
||||
label_value = decode_label(label);
|
||||
sprintf(tag_buf, " label %u", label_value);
|
||||
if (safi == SAFI_EVPN) {
|
||||
char tag_buf2[20];
|
||||
|
||||
bgp_evpn_label2str(label, num_labels, tag_buf2, 20);
|
||||
sprintf(tag_buf, " label %s", tag_buf2);
|
||||
} else {
|
||||
u_int32_t label_value;
|
||||
|
||||
label_value = decode_label(label);
|
||||
sprintf(tag_buf, " label %u", label_value);
|
||||
}
|
||||
}
|
||||
|
||||
if (prd)
|
||||
|
@ -153,7 +153,8 @@ extern int bgp_debug_zebra(struct prefix *p);
|
||||
|
||||
extern int bgp_debug_count(void);
|
||||
extern const char *bgp_debug_rdpfxpath2str(afi_t, safi_t, struct prefix_rd *,
|
||||
union prefixconstptr, mpls_label_t *,
|
||||
union prefixconstptr,
|
||||
mpls_label_t *, u_int32_t,
|
||||
int, u_int32_t, char *, int);
|
||||
const char *bgp_notify_admin_message(char *buf, size_t bufsz, u_char *data,
|
||||
size_t datalen);
|
||||
|
@ -690,6 +690,9 @@ char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter)
|
||||
tunneltype = ntohs(tunneltype);
|
||||
len = sprintf(str_buf + str_pnt, "ET:%d",
|
||||
tunneltype);
|
||||
} else if (*pnt == ECOMMUNITY_EVPN_SUBTYPE_DEF_GW) {
|
||||
len = sprintf(str_buf + str_pnt,
|
||||
"Default Gateway");
|
||||
} else
|
||||
unk_ecom = 1;
|
||||
} else if (type == ECOMMUNITY_ENCODE_EVPN) {
|
||||
|
327
bgpd/bgp_evpn.c
327
bgpd/bgp_evpn.c
@ -484,7 +484,7 @@ static void derive_rd_rt_for_vni(struct bgp *bgp, struct bgpevpn *vpn)
|
||||
static int bgp_zebra_send_remote_macip(struct bgp *bgp, struct bgpevpn *vpn,
|
||||
struct prefix_evpn *p,
|
||||
struct in_addr remote_vtep_ip, int add,
|
||||
u_char sticky)
|
||||
u_char flags)
|
||||
{
|
||||
struct stream *s;
|
||||
int ipa_len;
|
||||
@ -519,18 +519,18 @@ static int bgp_zebra_send_remote_macip(struct bgp *bgp, struct bgpevpn *vpn,
|
||||
}
|
||||
stream_put_in_addr(s, &remote_vtep_ip);
|
||||
|
||||
/* TX MAC sticky status */
|
||||
/* TX flags - MAC sticky status and/or gateway mac */
|
||||
if (add)
|
||||
stream_putc(s, sticky);
|
||||
stream_putc(s, flags);
|
||||
|
||||
stream_putw_at(s, 0, stream_get_endp(s));
|
||||
|
||||
if (bgp_debug_zebra(NULL))
|
||||
zlog_debug("Tx %s MACIP, VNI %u %sMAC %s IP %s remote VTEP %s",
|
||||
zlog_debug("Tx %s MACIP, VNI %u MAC %s IP %s (flags: 0x%x) remote VTEP %s",
|
||||
add ? "ADD" : "DEL", vpn->vni,
|
||||
sticky ? "sticky " : "",
|
||||
prefix_mac2str(&p->prefix.mac, buf1, sizeof(buf1)),
|
||||
ipaddr2str(&p->prefix.ip, buf3, sizeof(buf3)),
|
||||
flags,
|
||||
inet_ntop(AF_INET, &remote_vtep_ip, buf2,
|
||||
sizeof(buf2)));
|
||||
|
||||
@ -640,9 +640,11 @@ static void build_evpn_route_extcomm(struct bgpevpn *vpn, struct attr *attr,
|
||||
{
|
||||
struct ecommunity ecom_encap;
|
||||
struct ecommunity ecom_sticky;
|
||||
struct ecommunity ecom_default_gw;
|
||||
struct ecommunity ecom_rmac;
|
||||
struct ecommunity_val eval;
|
||||
struct ecommunity_val eval_sticky;
|
||||
struct ecommunity_val eval_default_gw;
|
||||
struct ecommunity_val eval_rmac;
|
||||
bgp_encap_types tnl_type;
|
||||
struct listnode *node, *nnode;
|
||||
@ -697,6 +699,15 @@ static void build_evpn_route_extcomm(struct bgpevpn *vpn, struct attr *attr,
|
||||
&ecom_rmac);
|
||||
}
|
||||
|
||||
if (attr->default_gw) {
|
||||
memset(&ecom_default_gw, 0, sizeof(ecom_default_gw));
|
||||
encode_default_gw_extcomm(&eval_default_gw);
|
||||
ecom_default_gw.size = 1;
|
||||
ecom_default_gw.val = (uint8_t *)eval_default_gw.val;
|
||||
attr->ecommunity = ecommunity_merge(attr->ecommunity,
|
||||
&ecom_default_gw);
|
||||
}
|
||||
|
||||
attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES);
|
||||
}
|
||||
|
||||
@ -754,13 +765,13 @@ static void add_mac_mobility_to_attr(u_int32_t seq_num, struct attr *attr)
|
||||
/* Install EVPN route into zebra. */
|
||||
static int evpn_zebra_install(struct bgp *bgp, struct bgpevpn *vpn,
|
||||
struct prefix_evpn *p,
|
||||
struct in_addr remote_vtep_ip, u_char sticky)
|
||||
struct in_addr remote_vtep_ip, u_char flags)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE)
|
||||
ret = bgp_zebra_send_remote_macip(bgp, vpn, p, remote_vtep_ip,
|
||||
1, sticky);
|
||||
1, flags);
|
||||
else
|
||||
ret = bgp_zebra_send_remote_vtep(bgp, vpn, p, 1);
|
||||
|
||||
@ -831,6 +842,7 @@ static int evpn_route_select_install(struct bgp *bgp, struct bgpevpn *vpn,
|
||||
afi_t afi = AFI_L2VPN;
|
||||
safi_t safi = SAFI_EVPN;
|
||||
int ret = 0;
|
||||
u_char flags = 0;
|
||||
|
||||
/* Compute the best path. */
|
||||
bgp_best_selection(bgp, rn, &bgp->maxpaths[afi][safi], &old_and_new,
|
||||
@ -848,11 +860,16 @@ static int evpn_route_select_install(struct bgp *bgp, struct bgpevpn *vpn,
|
||||
&& !CHECK_FLAG(rn->flags, BGP_NODE_USER_CLEAR)
|
||||
&& !CHECK_FLAG(old_select->flags, BGP_INFO_ATTR_CHANGED)
|
||||
&& !bgp->addpath_tx_used[afi][safi]) {
|
||||
if (bgp_zebra_has_route_changed(rn, old_select))
|
||||
if (bgp_zebra_has_route_changed(rn, old_select)) {
|
||||
if (old_select->attr->sticky)
|
||||
SET_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY);
|
||||
if (old_select->attr->default_gw)
|
||||
SET_FLAG(flags, ZEBRA_MACIP_TYPE_GW);
|
||||
ret = evpn_zebra_install(bgp, vpn,
|
||||
(struct prefix_evpn *)&rn->p,
|
||||
old_select->attr->nexthop,
|
||||
old_select->attr->sticky);
|
||||
flags);
|
||||
}
|
||||
UNSET_FLAG(old_select->flags, BGP_INFO_MULTIPATH_CHG);
|
||||
bgp_zebra_clear_route_change_flags(rn);
|
||||
return ret;
|
||||
@ -877,9 +894,14 @@ static int evpn_route_select_install(struct bgp *bgp, struct bgpevpn *vpn,
|
||||
|
||||
if (new_select && new_select->type == ZEBRA_ROUTE_BGP
|
||||
&& new_select->sub_type == BGP_ROUTE_NORMAL) {
|
||||
flags = 0;
|
||||
if (new_select->attr->sticky)
|
||||
SET_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY);
|
||||
if (new_select->attr->default_gw)
|
||||
SET_FLAG(flags, ZEBRA_MACIP_TYPE_GW);
|
||||
ret = evpn_zebra_install(bgp, vpn, (struct prefix_evpn *)&rn->p,
|
||||
new_select->attr->nexthop,
|
||||
new_select->attr->sticky);
|
||||
flags);
|
||||
/* If an old best existed and it was a "local" route, the only
|
||||
* reason
|
||||
* it would be supplanted is due to MAC mobility procedures. So,
|
||||
@ -909,6 +931,28 @@ static int evpn_route_select_install(struct bgp *bgp, struct bgpevpn *vpn,
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return true if the local ri for this rn is of type gateway mac
|
||||
*/
|
||||
static int evpn_route_is_def_gw(struct bgp *bgp, struct bgp_node *rn)
|
||||
{
|
||||
struct bgp_info *tmp_ri = NULL;
|
||||
struct bgp_info *local_ri = NULL;
|
||||
|
||||
local_ri = NULL;
|
||||
for (tmp_ri = rn->info; tmp_ri; tmp_ri = tmp_ri->next) {
|
||||
if (tmp_ri->peer == bgp->peer_self
|
||||
&& tmp_ri->type == ZEBRA_ROUTE_BGP
|
||||
&& tmp_ri->sub_type == BGP_ROUTE_STATIC)
|
||||
local_ri = tmp_ri;
|
||||
}
|
||||
|
||||
if (!local_ri)
|
||||
return 0;
|
||||
|
||||
return local_ri->attr->default_gw;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Return true if the local ri for this rn has sticky set
|
||||
@ -968,10 +1012,11 @@ static int update_evpn_type5_route_entry(struct bgp *bgp_def,
|
||||
bgp_def->peer_self, attr_new, rn);
|
||||
SET_FLAG(ri->flags, BGP_INFO_VALID);
|
||||
|
||||
/* L3-VNI goes in the label2 field */
|
||||
/* Type-5 routes advertise the L3-VNI */
|
||||
bgp_info_extra_get(ri);
|
||||
vni2label(bgp_vrf->l3vni, &label);
|
||||
memcpy(&ri->extra->label2, &label, BGP_LABEL_BYTES);
|
||||
memcpy(&ri->extra->label, &label, sizeof(label));
|
||||
ri->extra->num_labels = 1;
|
||||
|
||||
/* add the route entry to route node*/
|
||||
bgp_info_add(rn, ri);
|
||||
@ -1003,7 +1048,8 @@ static int update_evpn_type5_route_entry(struct bgp *bgp_def,
|
||||
|
||||
/* update evpn type-5 route entry */
|
||||
static int update_evpn_type5_route(struct bgp *bgp_vrf,
|
||||
struct prefix_evpn *evp)
|
||||
struct prefix_evpn *evp,
|
||||
struct attr* src_attr)
|
||||
{
|
||||
afi_t afi = AFI_L2VPN;
|
||||
safi_t safi = SAFI_EVPN;
|
||||
@ -1014,11 +1060,18 @@ static int update_evpn_type5_route(struct bgp *bgp_vrf,
|
||||
|
||||
bgp_def = bgp_get_default();
|
||||
if (!bgp_def)
|
||||
return -1;
|
||||
return 0;
|
||||
|
||||
/* build path attribute for this route */
|
||||
memset(&attr, 0, sizeof(struct attr));
|
||||
bgp_attr_default_set(&attr, BGP_ORIGIN_IGP);
|
||||
/* Build path attribute for this route - use the source attr, if
|
||||
* present, else treat as locally originated.
|
||||
*/
|
||||
if (src_attr)
|
||||
bgp_attr_dup(&attr, src_attr);
|
||||
else {
|
||||
memset(&attr, 0, sizeof(struct attr));
|
||||
bgp_attr_default_set(&attr, BGP_ORIGIN_IGP);
|
||||
}
|
||||
/* Set nexthop to ourselves and fill in the Router MAC. */
|
||||
attr.nexthop = bgp_vrf->originator_ip;
|
||||
attr.mp_nexthop_global_in = bgp_vrf->originator_ip;
|
||||
attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4;
|
||||
@ -1045,7 +1098,8 @@ static int update_evpn_type5_route(struct bgp *bgp_vrf,
|
||||
}
|
||||
|
||||
/* uninten temporary */
|
||||
aspath_unintern(&attr.aspath);
|
||||
if (!src_attr)
|
||||
aspath_unintern(&attr.aspath);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1061,11 +1115,15 @@ static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
|
||||
struct bgp_info *tmp_ri;
|
||||
struct bgp_info *local_ri, *remote_ri;
|
||||
struct attr *attr_new;
|
||||
mpls_label_t label = MPLS_INVALID_LABEL;
|
||||
mpls_label_t label[BGP_MAX_LABELS];
|
||||
u_int32_t num_labels = 1;
|
||||
int route_change = 1;
|
||||
u_char sticky = 0;
|
||||
struct prefix_evpn *evp;
|
||||
|
||||
*ri = NULL;
|
||||
evp = (struct prefix_evpn *)&rn->p;
|
||||
memset(&label, 0, sizeof(label));
|
||||
|
||||
/* See if this is an update of an existing route, or a new add. Also,
|
||||
* identify if already known from remote, and if so, the one with the
|
||||
@ -1107,7 +1165,7 @@ static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
|
||||
* SVI) advertised in EVPN.
|
||||
* This will ensure that local routes are preferred for g/w macs
|
||||
*/
|
||||
if (remote_ri && !CHECK_FLAG(flags, ZEBRA_MAC_TYPE_GW)) {
|
||||
if (remote_ri && !CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_GW)) {
|
||||
u_int32_t cur_seqnum;
|
||||
|
||||
/* Add MM extended community to route. */
|
||||
@ -1130,9 +1188,20 @@ static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
|
||||
bgp_info_extra_get(tmp_ri);
|
||||
|
||||
/* The VNI goes into the 'label' field of the route */
|
||||
vni2label(vpn->vni, &label);
|
||||
vni2label(vpn->vni, &label[0]);
|
||||
/* Type-2 routes may carry a second VNI - the L3-VNI */
|
||||
if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) {
|
||||
vni_t l3vni;
|
||||
|
||||
memcpy(&tmp_ri->extra->label, &label, BGP_LABEL_BYTES);
|
||||
l3vni = bgpevpn_get_l3vni(vpn);
|
||||
if (l3vni) {
|
||||
vni2label(l3vni, &label[1]);
|
||||
num_labels++;
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(&tmp_ri->extra->label, label, sizeof(label));
|
||||
tmp_ri->extra->num_labels = num_labels;
|
||||
bgp_info_add(rn, tmp_ri);
|
||||
} else {
|
||||
tmp_ri = local_ri;
|
||||
@ -1183,8 +1252,9 @@ static int update_evpn_route(struct bgp *bgp, struct bgpevpn *vpn,
|
||||
attr.nexthop = vpn->originator_ip;
|
||||
attr.mp_nexthop_global_in = vpn->originator_ip;
|
||||
attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4;
|
||||
attr.sticky = CHECK_FLAG(flags, ZEBRA_MAC_TYPE_STICKY) ? 1 : 0;
|
||||
attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_PMSI_TUNNEL);
|
||||
attr.sticky = CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY) ? 1 : 0;
|
||||
attr.default_gw = CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_GW) ? 1 : 0;
|
||||
attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_PMSI_TUNNEL);
|
||||
bgpevpn_get_rmac(vpn, &attr.rmac);
|
||||
vni2label(vpn->vni, &(attr.label));
|
||||
|
||||
@ -1270,7 +1340,7 @@ static int delete_evpn_type5_route(struct bgp *bgp_vrf,
|
||||
|
||||
bgp_def = bgp_get_default();
|
||||
if (!bgp_def)
|
||||
return -1;
|
||||
return 0;
|
||||
|
||||
/* locate the global route entry for this type-5 prefix */
|
||||
rn = bgp_afi_node_lookup(bgp_def->rib[afi][safi], afi, safi,
|
||||
@ -1372,22 +1442,27 @@ static int update_all_type2_routes(struct bgp *bgp, struct bgpevpn *vpn)
|
||||
struct bgp_info *ri;
|
||||
struct attr attr;
|
||||
struct attr attr_sticky;
|
||||
struct attr attr_def_gw;
|
||||
struct attr attr_ip6;
|
||||
struct attr attr_sticky_ip6;
|
||||
struct attr attr_def_gw_ip6;
|
||||
struct attr *attr_new;
|
||||
|
||||
afi = AFI_L2VPN;
|
||||
safi = SAFI_EVPN;
|
||||
memset(&attr, 0, sizeof(struct attr));
|
||||
memset(&attr_sticky, 0, sizeof(struct attr));
|
||||
memset(&attr_def_gw, 0, sizeof(struct attr));
|
||||
memset(&attr_ip6, 0, sizeof(struct attr));
|
||||
memset(&attr_sticky_ip6, 0, sizeof(struct attr));
|
||||
memset(&attr_def_gw_ip6, 0, sizeof(struct attr));
|
||||
|
||||
/* Build path-attribute - all type-2 routes for this VNI will share the
|
||||
* same path attribute.
|
||||
*/
|
||||
bgp_attr_default_set(&attr, BGP_ORIGIN_IGP);
|
||||
bgp_attr_default_set(&attr_sticky, BGP_ORIGIN_IGP);
|
||||
bgp_attr_default_set(&attr_def_gw, BGP_ORIGIN_IGP);
|
||||
attr.nexthop = vpn->originator_ip;
|
||||
attr.mp_nexthop_global_in = vpn->originator_ip;
|
||||
attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4;
|
||||
@ -1397,8 +1472,14 @@ static int update_all_type2_routes(struct bgp *bgp, struct bgpevpn *vpn)
|
||||
attr_sticky.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4;
|
||||
attr_sticky.sticky = 1;
|
||||
bgpevpn_get_rmac(vpn, &attr_sticky.rmac);
|
||||
attr_def_gw.nexthop = vpn->originator_ip;
|
||||
attr_def_gw.mp_nexthop_global_in = vpn->originator_ip;
|
||||
attr_def_gw.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4;
|
||||
attr_def_gw.default_gw = 1;
|
||||
bgpevpn_get_rmac(vpn, &attr_def_gw.rmac);
|
||||
bgp_attr_default_set(&attr_ip6, BGP_ORIGIN_IGP);
|
||||
bgp_attr_default_set(&attr_sticky_ip6, BGP_ORIGIN_IGP);
|
||||
bgp_attr_default_set(&attr_def_gw_ip6, BGP_ORIGIN_IGP);
|
||||
attr_ip6.nexthop = vpn->originator_ip;
|
||||
attr_ip6.mp_nexthop_global_in = vpn->originator_ip;
|
||||
attr_ip6.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4;
|
||||
@ -1408,12 +1489,19 @@ static int update_all_type2_routes(struct bgp *bgp, struct bgpevpn *vpn)
|
||||
attr_sticky_ip6.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4;
|
||||
attr_sticky_ip6.sticky = 1;
|
||||
bgpevpn_get_rmac(vpn, &attr_sticky_ip6.rmac);
|
||||
attr_def_gw_ip6.nexthop = vpn->originator_ip;
|
||||
attr_def_gw_ip6.mp_nexthop_global_in = vpn->originator_ip;
|
||||
attr_def_gw_ip6.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4;
|
||||
attr_def_gw_ip6.default_gw = 1;
|
||||
bgpevpn_get_rmac(vpn, &attr_def_gw_ip6.rmac);
|
||||
|
||||
/* Set up RT, ENCAP and sticky MAC extended community. */
|
||||
build_evpn_route_extcomm(vpn, &attr, AFI_IP);
|
||||
build_evpn_route_extcomm(vpn, &attr_sticky, AFI_IP);
|
||||
build_evpn_route_extcomm(vpn, &attr_def_gw, AFI_IP);
|
||||
build_evpn_route_extcomm(vpn, &attr_ip6, AFI_IP6);
|
||||
build_evpn_route_extcomm(vpn, &attr_sticky_ip6, AFI_IP6);
|
||||
build_evpn_route_extcomm(vpn, &attr_def_gw_ip6, AFI_IP);
|
||||
|
||||
/* Walk this VNI's route table and update local type-2 routes. For any
|
||||
* routes updated, update corresponding entry in the global table too.
|
||||
@ -1432,6 +1520,10 @@ static int update_all_type2_routes(struct bgp *bgp, struct bgpevpn *vpn)
|
||||
update_evpn_route_entry(bgp, vpn, afi, safi, rn,
|
||||
&attr_sticky, 0, 1,
|
||||
&ri, 0);
|
||||
else if (evpn_route_is_def_gw(bgp, rn))
|
||||
update_evpn_route_entry(bgp, vpn, afi, safi, rn,
|
||||
&attr_def_gw, 0, 1,
|
||||
&ri, 0);
|
||||
else
|
||||
update_evpn_route_entry(bgp, vpn, afi, safi, rn,
|
||||
&attr, 0, 1, &ri, 0);
|
||||
@ -1440,6 +1532,10 @@ static int update_all_type2_routes(struct bgp *bgp, struct bgpevpn *vpn)
|
||||
update_evpn_route_entry(bgp, vpn, afi, safi, rn,
|
||||
&attr_sticky_ip6, 0, 1,
|
||||
&ri, 0);
|
||||
else if (evpn_route_is_def_gw(bgp, rn))
|
||||
update_evpn_route_entry(bgp, vpn, afi, safi, rn,
|
||||
&attr_def_gw_ip6, 0, 1,
|
||||
&ri, 0);
|
||||
else
|
||||
update_evpn_route_entry(bgp, vpn, afi, safi, rn,
|
||||
&attr_ip6, 0, 1,
|
||||
@ -1474,7 +1570,11 @@ static int update_all_type2_routes(struct bgp *bgp, struct bgpevpn *vpn)
|
||||
|
||||
/* Unintern temporary. */
|
||||
aspath_unintern(&attr.aspath);
|
||||
aspath_unintern(&attr_ip6.aspath);
|
||||
aspath_unintern(&attr_sticky.aspath);
|
||||
aspath_unintern(&attr_sticky_ip6.aspath);
|
||||
aspath_unintern(&attr_def_gw.aspath);
|
||||
aspath_unintern(&attr_def_gw_ip6.aspath);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1717,9 +1817,11 @@ static int install_evpn_route_entry_in_vrf(struct bgp *bgp_vrf,
|
||||
SET_FLAG(ri->flags, BGP_INFO_VALID);
|
||||
bgp_info_extra_get(ri);
|
||||
ri->extra->parent = parent_ri;
|
||||
if (parent_ri->extra)
|
||||
if (parent_ri->extra) {
|
||||
memcpy(&ri->extra->label, &parent_ri->extra->label,
|
||||
BGP_LABEL_BYTES);
|
||||
sizeof(ri->extra->label));
|
||||
ri->extra->num_labels = parent_ri->extra->num_labels;
|
||||
}
|
||||
bgp_info_add(rn, ri);
|
||||
} else {
|
||||
if (attrhash_cmp(ri->attr, parent_ri->attr)
|
||||
@ -1783,9 +1885,11 @@ static int install_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
|
||||
SET_FLAG(ri->flags, BGP_INFO_VALID);
|
||||
bgp_info_extra_get(ri);
|
||||
ri->extra->parent = parent_ri;
|
||||
if (parent_ri->extra)
|
||||
if (parent_ri->extra) {
|
||||
memcpy(&ri->extra->label, &parent_ri->extra->label,
|
||||
BGP_LABEL_BYTES);
|
||||
sizeof(ri->extra->label));
|
||||
ri->extra->num_labels = parent_ri->extra->num_labels;
|
||||
}
|
||||
bgp_info_add(rn, ri);
|
||||
} else {
|
||||
if (attrhash_cmp(ri->attr, parent_ri->attr)
|
||||
@ -2675,7 +2779,8 @@ static int process_type2_route(struct peer *peer, afi_t afi, safi_t safi,
|
||||
struct prefix_evpn p;
|
||||
u_char ipaddr_len;
|
||||
u_char macaddr_len;
|
||||
mpls_label_t *label_pnt;
|
||||
mpls_label_t label[BGP_MAX_LABELS]; /* holds the VNI(s) as in packet */
|
||||
u_int32_t num_labels = 0;
|
||||
int ret;
|
||||
|
||||
/* Type-2 route should be either 33, 37 or 49 bytes or an
|
||||
@ -2743,19 +2848,31 @@ static int process_type2_route(struct peer *peer, afi_t afi, safi_t safi,
|
||||
}
|
||||
pfx += ipaddr_len;
|
||||
|
||||
/* Get the VNI (in MPLS label field). */
|
||||
/* Note: We ignore the second VNI, if any. */
|
||||
label_pnt = (mpls_label_t *)pfx;
|
||||
/* Get the VNI(s). Stored as bytes here. */
|
||||
num_labels++;
|
||||
memset(label, 0, sizeof(label));
|
||||
memcpy(&label[0], pfx, BGP_LABEL_BYTES);
|
||||
pfx += BGP_LABEL_BYTES;
|
||||
psize -= (33 + ipaddr_len);
|
||||
/* Do we have a second VNI? */
|
||||
if (psize) {
|
||||
num_labels++;
|
||||
memcpy(&label[1], pfx, BGP_LABEL_BYTES);
|
||||
/*
|
||||
* If in future, we are required to access additional fields,
|
||||
* we MUST increment pfx by BGP_LABEL_BYTES in before reading the next field
|
||||
*/
|
||||
}
|
||||
|
||||
/* Process the route. */
|
||||
if (attr)
|
||||
ret = bgp_update(peer, (struct prefix *)&p, addpath_id, attr,
|
||||
afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL,
|
||||
&prd, label_pnt, 0, NULL);
|
||||
&prd, &label[0], num_labels, 0, NULL);
|
||||
else
|
||||
ret = bgp_withdraw(peer, (struct prefix *)&p, addpath_id, attr,
|
||||
afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL,
|
||||
&prd, label_pnt, NULL);
|
||||
&prd, &label[0], num_labels, NULL);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -2811,11 +2928,11 @@ static int process_type3_route(struct peer *peer, afi_t afi, safi_t safi,
|
||||
if (attr)
|
||||
ret = bgp_update(peer, (struct prefix *)&p, addpath_id, attr,
|
||||
afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL,
|
||||
&prd, NULL, 0, NULL);
|
||||
&prd, NULL, 0, 0, NULL);
|
||||
else
|
||||
ret = bgp_withdraw(peer, (struct prefix *)&p, addpath_id, attr,
|
||||
afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL,
|
||||
&prd, NULL, NULL);
|
||||
&prd, NULL, 0, NULL);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -2831,7 +2948,7 @@ static int process_type5_route(struct peer *peer, afi_t afi, safi_t safi,
|
||||
struct bgp_route_evpn evpn;
|
||||
u_char ippfx_len;
|
||||
u_int32_t eth_tag;
|
||||
mpls_label_t *label_pnt;
|
||||
mpls_label_t label; /* holds the VNI as in the packet */
|
||||
int ret;
|
||||
|
||||
/* Type-5 route should be 34 or 58 bytes:
|
||||
@ -2897,23 +3014,31 @@ static int process_type5_route(struct peer *peer, afi_t afi, safi_t safi,
|
||||
pfx += 16;
|
||||
}
|
||||
|
||||
label_pnt = (mpls_label_t *)pfx;
|
||||
/* Get the VNI (in MPLS label field). Stored as bytes here. */
|
||||
memset(&label, 0, sizeof(label));
|
||||
memcpy(&label, pfx, BGP_LABEL_BYTES);
|
||||
|
||||
/*
|
||||
* If in future, we are required to access additional fields,
|
||||
* we MUST increment pfx by BGP_LABEL_BYTES in before reading the next field
|
||||
*/
|
||||
|
||||
/* Process the route. */
|
||||
if (!withdraw)
|
||||
ret = bgp_update(peer, (struct prefix *)&p, addpath_id, attr,
|
||||
afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL,
|
||||
&prd, label_pnt, 0, &evpn);
|
||||
&prd, &label, 1, 0, &evpn);
|
||||
else
|
||||
ret = bgp_withdraw(peer, (struct prefix *)&p, addpath_id, attr,
|
||||
afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL,
|
||||
&prd, label_pnt, &evpn);
|
||||
&prd, &label, 1, &evpn);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void evpn_mpattr_encode_type5(struct stream *s, struct prefix *p,
|
||||
struct prefix_rd *prd, mpls_label_t *label,
|
||||
struct prefix_rd *prd,
|
||||
mpls_label_t *label, u_int32_t num_labels,
|
||||
struct attr *attr)
|
||||
{
|
||||
int len;
|
||||
@ -2958,7 +3083,7 @@ static void evpn_mpattr_encode_type5(struct stream *s, struct prefix *p,
|
||||
stream_put(s, &temp, 16);
|
||||
}
|
||||
|
||||
if (label)
|
||||
if (num_labels)
|
||||
stream_put(s, label, 3);
|
||||
else
|
||||
stream_put3(s, 0);
|
||||
@ -3057,20 +3182,24 @@ static void bgp_evpn_handle_export_rt_change_for_vrf(struct bgp *bgp_vrf)
|
||||
*/
|
||||
|
||||
/* withdraw type-5 route corresponding to ip prefix */
|
||||
void bgp_evpn_withdraw_type5_route(struct bgp *bgp_vrf, struct bgp_node *rn,
|
||||
void bgp_evpn_withdraw_type5_route(struct bgp *bgp_vrf, struct prefix *p,
|
||||
afi_t afi, safi_t safi)
|
||||
{
|
||||
int ret = 0;
|
||||
struct prefix_evpn evp;
|
||||
char buf[PREFIX_STRLEN];
|
||||
|
||||
build_type5_prefix_from_ip_prefix(&evp, &rn->p);
|
||||
/* NOTE: Check needed as this is called per-route also. */
|
||||
if (!advertise_type5_routes(bgp_vrf, afi))
|
||||
return;
|
||||
|
||||
build_type5_prefix_from_ip_prefix(&evp, p);
|
||||
ret = delete_evpn_type5_route(bgp_vrf, &evp);
|
||||
if (ret) {
|
||||
zlog_err(
|
||||
"%u failed to delete type-5 route for prefix %s in vrf %s",
|
||||
bgp_vrf->vrf_id,
|
||||
prefix2str(&rn->p, buf, sizeof(buf)),
|
||||
prefix2str(p, buf, sizeof(buf)),
|
||||
vrf_id_to_name(bgp_vrf->vrf_id));
|
||||
}
|
||||
}
|
||||
@ -3082,54 +3211,77 @@ void bgp_evpn_withdraw_type5_routes(struct bgp *bgp_vrf,
|
||||
struct bgp_table *table = NULL;
|
||||
struct bgp_node *rn = NULL;
|
||||
|
||||
/* Bail out early if we don't have to advertise type-5 routes. */
|
||||
if (!advertise_type5_routes(bgp_vrf, afi))
|
||||
return;
|
||||
|
||||
table = bgp_vrf->rib[afi][safi];
|
||||
for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn))
|
||||
bgp_evpn_withdraw_type5_route(bgp_vrf, rn, afi, safi);
|
||||
bgp_evpn_withdraw_type5_route(bgp_vrf, &rn->p, afi, safi);
|
||||
|
||||
}
|
||||
|
||||
/* advertise ip prefix as type-5 route*/
|
||||
void bgp_evpn_advertise_type5_route(struct bgp *bgp_vrf, struct bgp_node *rn,
|
||||
/*
|
||||
* Advertise IP prefix as type-5 route. The afi/safi and src_attr passed
|
||||
* to this function correspond to those of the source IP prefix (best
|
||||
* path in the case of the attr. In the case of a local prefix (when we
|
||||
* are advertising local subnets), the src_attr will be NULL.
|
||||
*/
|
||||
void bgp_evpn_advertise_type5_route(struct bgp *bgp_vrf, struct prefix *p,
|
||||
struct attr *src_attr,
|
||||
afi_t afi, safi_t safi)
|
||||
{
|
||||
int ret = 0;
|
||||
struct prefix_evpn evp;
|
||||
char buf[PREFIX_STRLEN];
|
||||
|
||||
/* NOTE: Check needed as this is called per-route also. */
|
||||
if (!advertise_type5_routes(bgp_vrf, afi))
|
||||
return;
|
||||
|
||||
if (!rn->info)
|
||||
return;
|
||||
|
||||
/* only advertise subnet routes as type-5 */
|
||||
if (is_host_route(&rn->p))
|
||||
if (is_host_route(p))
|
||||
return;
|
||||
|
||||
build_type5_prefix_from_ip_prefix(&evp, &rn->p);
|
||||
ret = update_evpn_type5_route(bgp_vrf, &evp);
|
||||
if (ret) {
|
||||
build_type5_prefix_from_ip_prefix(&evp, p);
|
||||
ret = update_evpn_type5_route(bgp_vrf, &evp, src_attr);
|
||||
if (ret)
|
||||
zlog_err(
|
||||
"%u failed to create type-5 route for prefix %s in vrf %s",
|
||||
"%u: Failed to create type-5 route for prefix %s",
|
||||
bgp_vrf->vrf_id,
|
||||
prefix2str(&rn->p, buf, sizeof(buf)),
|
||||
vrf_id_to_name(bgp_vrf->vrf_id));
|
||||
}
|
||||
prefix2str(p, buf, sizeof(buf)));
|
||||
}
|
||||
|
||||
/* advertise all type-5 routes for an address family */
|
||||
/* Inject all prefixes of a particular address-family (currently, IPv4 or
|
||||
* IPv6 unicast) into EVPN as type-5 routes. This is invoked when the
|
||||
* advertisement is enabled.
|
||||
*/
|
||||
void bgp_evpn_advertise_type5_routes(struct bgp *bgp_vrf,
|
||||
afi_t afi, safi_t safi)
|
||||
{
|
||||
struct bgp_table *table = NULL;
|
||||
struct bgp_node *rn = NULL;
|
||||
struct bgp_info *ri;
|
||||
|
||||
/* Bail out early if we don't have to advertise type-5 routes. */
|
||||
if (!advertise_type5_routes(bgp_vrf, afi))
|
||||
return;
|
||||
|
||||
table = bgp_vrf->rib[afi][safi];
|
||||
for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn))
|
||||
bgp_evpn_advertise_type5_route(bgp_vrf, rn, afi, safi);
|
||||
for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) {
|
||||
/* Need to identify the "selected" route entry to use its
|
||||
* attribute.
|
||||
* TODO: Support for AddPath for EVPN.
|
||||
*/
|
||||
for (ri = rn->info; ri; ri = ri->next) {
|
||||
if (CHECK_FLAG(ri->flags, BGP_INFO_SELECTED)) {
|
||||
bgp_evpn_advertise_type5_route(bgp_vrf, &rn->p,
|
||||
ri->attr,
|
||||
afi, safi);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void evpn_rt_delete_auto(struct bgp *bgp, vni_t vni,
|
||||
@ -3350,14 +3502,19 @@ int bgp_evpn_uninstall_routes(struct bgp *bgp, struct bgpevpn *vpn)
|
||||
}
|
||||
|
||||
/*
|
||||
* Function to display "tag" in route as a VNI.
|
||||
* TODO: Hardcoded for a maximum of 2 VNIs right now
|
||||
*/
|
||||
char *bgp_evpn_label2str(mpls_label_t *label, char *buf, int len)
|
||||
char *bgp_evpn_label2str(mpls_label_t *label, u_int32_t num_labels,
|
||||
char *buf, int len)
|
||||
{
|
||||
vni_t vni;
|
||||
vni_t vni1, vni2;
|
||||
|
||||
vni = label2vni(label);
|
||||
snprintf(buf, len, "%u", vni);
|
||||
vni1 = label2vni(label);
|
||||
if (num_labels == 2) {
|
||||
vni2 = label2vni(label+1);
|
||||
snprintf(buf, len, "%u/%u", vni1, vni2);
|
||||
} else
|
||||
snprintf(buf, len, "%u", vni1);
|
||||
return buf;
|
||||
}
|
||||
|
||||
@ -3461,7 +3618,7 @@ char *bgp_evpn_route2str(struct prefix_evpn *p, char *buf, int len)
|
||||
PREFIX2STR_BUFFER));
|
||||
}
|
||||
} else if (p->prefix.route_type == BGP_EVPN_IP_PREFIX_ROUTE) {
|
||||
snprintf(buf, len, "[%d]:[0]:[%d]:[%s]",
|
||||
snprintf(buf, len, "[%d]:[0]:[0]:[%d]:[%s]",
|
||||
p->prefix.route_type,
|
||||
p->prefix.ip_prefix_length,
|
||||
IS_EVPN_PREFIX_IPADDR_V4(p) ?
|
||||
@ -3480,12 +3637,13 @@ char *bgp_evpn_route2str(struct prefix_evpn *p, char *buf, int len)
|
||||
* Encode EVPN prefix in Update (MP_REACH)
|
||||
*/
|
||||
void bgp_evpn_encode_prefix(struct stream *s, struct prefix *p,
|
||||
struct prefix_rd *prd, mpls_label_t *label,
|
||||
struct prefix_rd *prd,
|
||||
mpls_label_t *label, u_int32_t num_labels,
|
||||
struct attr *attr, int addpath_encode,
|
||||
u_int32_t addpath_tx_id)
|
||||
{
|
||||
struct prefix_evpn *evp = (struct prefix_evpn *)p;
|
||||
int ipa_len = 0;
|
||||
int len, ipa_len = 0;
|
||||
|
||||
if (addpath_encode)
|
||||
stream_putl(s, addpath_tx_id);
|
||||
@ -3499,18 +3657,24 @@ void bgp_evpn_encode_prefix(struct stream *s, struct prefix *p,
|
||||
ipa_len = IPV4_MAX_BYTELEN;
|
||||
else if (IS_EVPN_PREFIX_IPADDR_V6(evp))
|
||||
ipa_len = IPV6_MAX_BYTELEN;
|
||||
stream_putc(s, 33 + ipa_len); // 1 VNI
|
||||
/* RD, ESI, EthTag, MAC+len, IP len, [IP], 1 VNI */
|
||||
len = 8 + 10 + 4 + 1 + 6 + 1 + ipa_len + 3;
|
||||
if (ipa_len && num_labels > 1) /* There are 2 VNIs */
|
||||
len += 3;
|
||||
stream_putc(s, len);
|
||||
stream_put(s, prd->val, 8); /* RD */
|
||||
stream_put(s, 0, 10); /* ESI */
|
||||
stream_putl(s, 0); /* Ethernet Tag ID */
|
||||
stream_putc(s, 8 * ETH_ALEN); /* Mac Addr Len - bits */
|
||||
stream_put(s, evp->prefix.mac.octet, 6); /* Mac Addr */
|
||||
stream_putc(s, 8 * ipa_len); /* IP address Length */
|
||||
if (ipa_len)
|
||||
stream_put(s, &evp->prefix.ip.ip.addr,
|
||||
ipa_len); /* IP */
|
||||
stream_put(s, label,
|
||||
BGP_LABEL_BYTES); /* VNI is contained in 'tag' */
|
||||
if (ipa_len) /* IP */
|
||||
stream_put(s, &evp->prefix.ip.ip.addr, ipa_len);
|
||||
/* 1st label is the L2 VNI */
|
||||
stream_put(s, label, BGP_LABEL_BYTES);
|
||||
/* Include 2nd label (L3 VNI) if advertising MAC+IP */
|
||||
if (ipa_len && num_labels > 1)
|
||||
stream_put(s, label+1, BGP_LABEL_BYTES);
|
||||
break;
|
||||
|
||||
case BGP_EVPN_IMET_ROUTE:
|
||||
@ -3524,7 +3688,7 @@ void bgp_evpn_encode_prefix(struct stream *s, struct prefix *p,
|
||||
|
||||
case BGP_EVPN_IP_PREFIX_ROUTE:
|
||||
/* TODO: AddPath support. */
|
||||
evpn_mpattr_encode_type5(s, p, prd, label, attr);
|
||||
evpn_mpattr_encode_type5(s, p, prd, label, num_labels, attr);
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -4020,12 +4184,13 @@ int bgp_evpn_local_macip_add(struct bgp *bgp, vni_t vni, struct ethaddr *mac,
|
||||
char buf2[INET6_ADDRSTRLEN];
|
||||
|
||||
zlog_err(
|
||||
"%u:Failed to create Type-2 route, VNI %u %s MAC %s IP %s",
|
||||
"%u:Failed to create Type-2 route, VNI %u %s MAC %s IP %s (flags: 0x%x)",
|
||||
bgp->vrf_id, vpn->vni,
|
||||
CHECK_FLAG(flags, ZEBRA_MAC_TYPE_STICKY) ? "sticky gateway"
|
||||
CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY) ? "sticky gateway"
|
||||
: "",
|
||||
prefix_mac2str(mac, buf, sizeof(buf)),
|
||||
ipaddr2str(ip, buf2, sizeof(buf2)));
|
||||
ipaddr2str(ip, buf2, sizeof(buf2)),
|
||||
flags);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -34,11 +34,33 @@ static inline int is_evpn_enabled(void)
|
||||
return bgp ? bgp->advertise_all_vni : 0;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
extern void bgp_evpn_advertise_type5_route(struct bgp *bgp_vrf,
|
||||
struct bgp_node *rn,
|
||||
struct prefix *p,
|
||||
struct attr *src_attr,
|
||||
afi_t afi, safi_t safi);
|
||||
extern void bgp_evpn_withdraw_type5_route(struct bgp *bgp_vrf,
|
||||
struct bgp_node *rn,
|
||||
struct prefix *p,
|
||||
afi_t afi, safi_t safi);
|
||||
extern void bgp_evpn_withdraw_type5_routes(struct bgp *bgp_vrf, afi_t afi,
|
||||
safi_t safi);
|
||||
@ -46,11 +68,13 @@ extern void bgp_evpn_advertise_type5_routes(struct bgp *bgp_vrf, afi_t afi,
|
||||
safi_t safi);
|
||||
extern void bgp_evpn_vrf_delete(struct bgp *bgp_vrf);
|
||||
extern void 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_label2str(mpls_label_t *label, u_int32_t num_labels,
|
||||
char *buf, int len);
|
||||
extern char *bgp_evpn_route2str(struct prefix_evpn *p, char *buf, int len);
|
||||
extern void bgp_evpn_route2json(struct prefix_evpn *p, json_object *json);
|
||||
extern void bgp_evpn_encode_prefix(struct stream *s, struct prefix *p,
|
||||
struct prefix_rd *prd, mpls_label_t *label,
|
||||
struct prefix_rd *prd,
|
||||
mpls_label_t *label, u_int32_t num_labels,
|
||||
struct attr *attr, int addpath_encode,
|
||||
u_int32_t addpath_tx_id);
|
||||
extern int bgp_nlri_parse_evpn(struct peer *peer, struct attr *attr,
|
||||
|
@ -65,6 +65,9 @@ struct bgpevpn {
|
||||
/* Flag to indicate if we are advertising the g/w mac ip for this VNI*/
|
||||
u_int8_t advertise_gw_macip;
|
||||
|
||||
/* Flag to indicate if we are advertising subnet for this VNI */
|
||||
u_int8_t advertise_subnet;
|
||||
|
||||
/* Id for deriving the RD automatically for this VNI */
|
||||
u_int16_t rd_id;
|
||||
|
||||
@ -228,26 +231,6 @@ static inline int is_vni_param_configured(struct bgpevpn *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_rmac_extcomm(struct ecommunity_val *eval,
|
||||
struct ethaddr *rmac)
|
||||
{
|
||||
@ -257,6 +240,13 @@ static inline void encode_rmac_extcomm(struct ecommunity_val *eval,
|
||||
memcpy(&eval->val[2], rmac, ETH_ALEN);
|
||||
}
|
||||
|
||||
static inline void encode_default_gw_extcomm(struct ecommunity_val *eval)
|
||||
{
|
||||
memset(eval, 0, sizeof(*eval));
|
||||
eval->val[0] = ECOMMUNITY_ENCODE_OPAQUE;
|
||||
eval->val[1] = ECOMMUNITY_EVPN_SUBTYPE_DEF_GW;
|
||||
}
|
||||
|
||||
static inline void encode_mac_mobility_extcomm(int static_mac, u_int32_t seq,
|
||||
struct ecommunity_val *eval)
|
||||
{
|
||||
|
@ -331,10 +331,88 @@ static void bgp_evpn_show_route_header(struct vty *vty, struct bgp *bgp,
|
||||
vty_out(vty, "Origin codes: i - IGP, e - EGP, ? - incomplete\n");
|
||||
vty_out(vty,
|
||||
"EVPN type-2 prefix: [2]:[ESI]:[EthTag]:[MAClen]:[MAC]:[IPlen]:[IP]\n");
|
||||
vty_out(vty, "EVPN type-3 prefix: [3]:[EthTag]:[IPlen]:[OrigIP]\n\n");
|
||||
vty_out(vty, "EVPN type-3 prefix: [3]:[EthTag]:[IPlen]:[OrigIP]\n");
|
||||
vty_out(vty, "EVPN type-5 prefix: [5]:[ESI]:[EthTag]:[IPlen]:[IP]\n\n");
|
||||
vty_out(vty, "%s", ri_header);
|
||||
}
|
||||
|
||||
static void display_l3vni(struct vty *vty, struct bgp *bgp_vrf,
|
||||
json_object *json)
|
||||
{
|
||||
char buf1[INET6_ADDRSTRLEN];
|
||||
char *ecom_str;
|
||||
struct listnode *node, *nnode;
|
||||
struct ecommunity *ecom;
|
||||
json_object *json_import_rtl = NULL;
|
||||
json_object *json_export_rtl = NULL;
|
||||
|
||||
json_import_rtl = json_export_rtl = 0;
|
||||
|
||||
if (json) {
|
||||
json_import_rtl = json_object_new_array();
|
||||
json_export_rtl = json_object_new_array();
|
||||
json_object_int_add(json, "vni", bgp_vrf->l3vni);
|
||||
json_object_string_add(json, "type", "L3");
|
||||
json_object_string_add(json, "kernelFlag", "Yes");
|
||||
json_object_string_add(
|
||||
json, "rd",
|
||||
prefix_rd2str(&bgp_vrf->vrf_prd, buf1, RD_ADDRSTRLEN));
|
||||
json_object_string_add(json, "originatorIp",
|
||||
inet_ntoa(bgp_vrf->originator_ip));
|
||||
json_object_string_add(json, "advertiseGatewayMacip", "n/a");
|
||||
} else {
|
||||
vty_out(vty, "VNI: %d", bgp_vrf->l3vni);
|
||||
vty_out(vty, " (known to the kernel)");
|
||||
vty_out(vty, "\n");
|
||||
|
||||
vty_out(vty, " Type: %s\n", "L3");
|
||||
vty_out(vty, " Tenant VRF: %s\n",
|
||||
vrf_id_to_name(bgp_vrf->vrf_id));
|
||||
vty_out(vty, " RD: %s\n",
|
||||
prefix_rd2str(&bgp_vrf->vrf_prd, buf1, RD_ADDRSTRLEN));
|
||||
vty_out(vty, " Originator IP: %s\n",
|
||||
inet_ntoa(bgp_vrf->originator_ip));
|
||||
vty_out(vty, " Advertise-gw-macip : %s\n", "n/a");
|
||||
}
|
||||
|
||||
if (!json)
|
||||
vty_out(vty, " Import Route Target:\n");
|
||||
|
||||
for (ALL_LIST_ELEMENTS(bgp_vrf->vrf_import_rtl, node, nnode, ecom)) {
|
||||
ecom_str = ecommunity_ecom2str(ecom,
|
||||
ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
|
||||
|
||||
if (json)
|
||||
json_object_array_add(json_import_rtl,
|
||||
json_object_new_string(ecom_str));
|
||||
else
|
||||
vty_out(vty, " %s\n", ecom_str);
|
||||
|
||||
XFREE(MTYPE_ECOMMUNITY_STR, ecom_str);
|
||||
}
|
||||
|
||||
if (json)
|
||||
json_object_object_add(json, "importRts", json_import_rtl);
|
||||
else
|
||||
vty_out(vty, " Export Route Target:\n");
|
||||
|
||||
for (ALL_LIST_ELEMENTS(bgp_vrf->vrf_export_rtl, node, nnode, ecom)) {
|
||||
ecom_str = ecommunity_ecom2str(ecom,
|
||||
ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
|
||||
|
||||
if (json)
|
||||
json_object_array_add(json_export_rtl,
|
||||
json_object_new_string(ecom_str));
|
||||
else
|
||||
vty_out(vty, " %s\n", ecom_str);
|
||||
|
||||
XFREE(MTYPE_ECOMMUNITY_STR, ecom_str);
|
||||
}
|
||||
|
||||
if (json)
|
||||
json_object_object_add(json, "exportRts", json_export_rtl);
|
||||
}
|
||||
|
||||
static void display_vni(struct vty *vty, struct bgpevpn *vpn, json_object *json)
|
||||
{
|
||||
char buf1[RD_ADDRSTRLEN];
|
||||
@ -348,6 +426,7 @@ static void display_vni(struct vty *vty, struct bgpevpn *vpn, json_object *json)
|
||||
json_import_rtl = json_object_new_array();
|
||||
json_export_rtl = json_object_new_array();
|
||||
json_object_int_add(json, "vni", vpn->vni);
|
||||
json_object_string_add(json, "type", "L2");
|
||||
json_object_string_add(json, "kernelFlag",
|
||||
is_vni_live(vpn) ? "Yes" : "No");
|
||||
json_object_string_add(
|
||||
@ -363,6 +442,7 @@ static void display_vni(struct vty *vty, struct bgpevpn *vpn, json_object *json)
|
||||
vty_out(vty, " (known to the kernel)");
|
||||
vty_out(vty, "\n");
|
||||
|
||||
vty_out(vty, " Type: %s\n", "L2");
|
||||
vty_out(vty, " Tenant-Vrf: %s\n",
|
||||
vrf_id_to_name(vpn->tenant_vrf_id));
|
||||
vty_out(vty, " RD: %s\n",
|
||||
@ -570,6 +650,110 @@ static void show_vni_routes_hash(struct hash_backet *backet, void *arg)
|
||||
json_object_object_add(json, vni_str, json_vni);
|
||||
}
|
||||
|
||||
static void show_l3vni_entry(struct vty *vty, struct bgp *bgp,
|
||||
json_object *json)
|
||||
{
|
||||
json_object *json_vni;
|
||||
json_object *json_import_rtl;
|
||||
json_object *json_export_rtl;
|
||||
char buf1[10];
|
||||
char buf2[INET6_ADDRSTRLEN];
|
||||
char rt_buf[25];
|
||||
char *ecom_str;
|
||||
struct listnode *node, *nnode;
|
||||
struct ecommunity *ecom;
|
||||
|
||||
if (!bgp->l3vni)
|
||||
return;
|
||||
|
||||
if (json) {
|
||||
json_vni = json_object_new_object();
|
||||
json_import_rtl = json_object_new_array();
|
||||
json_export_rtl = json_object_new_array();
|
||||
}
|
||||
|
||||
/* if an l3vni is present in bgp it is live */
|
||||
buf1[0] = '\0';
|
||||
sprintf(buf1, "*");
|
||||
|
||||
if (json) {
|
||||
json_object_int_add(json_vni, "vni", bgp->l3vni);
|
||||
json_object_string_add(json_vni, "type", "L3");
|
||||
json_object_string_add(json_vni, "inKernel", "True");
|
||||
json_object_string_add(json_vni, "originatorIp",
|
||||
inet_ntoa(bgp->originator_ip));
|
||||
json_object_string_add(
|
||||
json_vni, "rd",
|
||||
prefix_rd2str(&bgp->vrf_prd, buf2, RD_ADDRSTRLEN));
|
||||
} else {
|
||||
vty_out(vty, "%-1s %-10u %-4s %-21s",
|
||||
buf1, bgp->l3vni, "L3",
|
||||
prefix_rd2str(&bgp->vrf_prd, buf2, RD_ADDRSTRLEN));
|
||||
}
|
||||
|
||||
for (ALL_LIST_ELEMENTS(bgp->vrf_import_rtl, node, nnode, ecom)) {
|
||||
ecom_str = ecommunity_ecom2str(ecom,
|
||||
ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
|
||||
|
||||
if (json) {
|
||||
json_object_array_add(json_import_rtl,
|
||||
json_object_new_string(ecom_str));
|
||||
} else {
|
||||
if (listcount(bgp->vrf_import_rtl) > 1)
|
||||
sprintf(rt_buf, "%s, ...", ecom_str);
|
||||
else
|
||||
sprintf(rt_buf, "%s", ecom_str);
|
||||
vty_out(vty, " %-25s", rt_buf);
|
||||
}
|
||||
|
||||
XFREE(MTYPE_ECOMMUNITY_STR, ecom_str);
|
||||
|
||||
/* If there are multiple import RTs we break here and show only
|
||||
* one */
|
||||
if (!json)
|
||||
break;
|
||||
}
|
||||
|
||||
if (json)
|
||||
json_object_object_add(json_vni, "importRTs", json_import_rtl);
|
||||
|
||||
for (ALL_LIST_ELEMENTS(bgp->vrf_export_rtl, node, nnode, ecom)) {
|
||||
ecom_str = ecommunity_ecom2str(ecom,
|
||||
ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
|
||||
|
||||
if (json) {
|
||||
json_object_array_add(json_export_rtl,
|
||||
json_object_new_string(ecom_str));
|
||||
} else {
|
||||
if (listcount(bgp->vrf_export_rtl) > 1)
|
||||
sprintf(rt_buf, "%s, ...", ecom_str);
|
||||
else
|
||||
sprintf(rt_buf, "%s", ecom_str);
|
||||
vty_out(vty, " %-25s", rt_buf);
|
||||
}
|
||||
|
||||
XFREE(MTYPE_ECOMMUNITY_STR, ecom_str);
|
||||
|
||||
/* If there are multiple export RTs we break here and show only
|
||||
* one */
|
||||
if (!json)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!json)
|
||||
vty_out(vty, "%-37s", vrf_id_to_name(bgp->vrf_id));
|
||||
|
||||
if (json) {
|
||||
char vni_str[VNI_STR_LEN];
|
||||
|
||||
json_object_object_add(json_vni, "exportRTs", json_export_rtl);
|
||||
snprintf(vni_str, VNI_STR_LEN, "%u", bgp->l3vni);
|
||||
json_object_object_add(json, vni_str, json_vni);
|
||||
} else {
|
||||
vty_out(vty, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void show_vni_entry(struct hash_backet *backet, void *args[])
|
||||
{
|
||||
struct vty *vty;
|
||||
@ -600,16 +784,19 @@ static void show_vni_entry(struct hash_backet *backet, void *args[])
|
||||
|
||||
if (json) {
|
||||
json_object_int_add(json_vni, "vni", vpn->vni);
|
||||
json_object_string_add(json_vni, "type", "L2");
|
||||
json_object_string_add(json_vni, "inKernel",
|
||||
is_vni_live(vpn) ? "True" : "False");
|
||||
json_object_string_add(json_vni, "originatorIp",
|
||||
inet_ntoa(vpn->originator_ip));
|
||||
json_object_string_add(json_vni, "originatorIp",
|
||||
inet_ntoa(vpn->originator_ip));
|
||||
json_object_string_add(
|
||||
json_vni, "rd",
|
||||
prefix_rd2str(&vpn->prd, buf2, sizeof(buf2)));
|
||||
} else {
|
||||
vty_out(vty, "%-1s %-10u %-15s %-21s", buf1, vpn->vni,
|
||||
inet_ntoa(vpn->originator_ip),
|
||||
vty_out(vty, "%-1s %-10u %-4s %-21s",
|
||||
buf1, vpn->vni, "L2",
|
||||
prefix_rd2str(&vpn->prd, buf2, RD_ADDRSTRLEN));
|
||||
}
|
||||
|
||||
@ -1982,7 +2169,7 @@ static void evpn_show_route_rd(struct vty *vty, struct bgp *bgp,
|
||||
vty_out(vty,
|
||||
"EVPN type-3 prefix: [3]:[EthTag]:[IPlen]:[OrigIP]\n");
|
||||
vty_out(vty,
|
||||
"EVPN type-5 prefix: [5]:[EthTag]:[IPlen]:[IP]\n\n");
|
||||
"EVPN type-5 prefix: [5]:[ESI]:[EthTag]:[IPlen]:[IP]\n\n");
|
||||
rd_header = 0;
|
||||
}
|
||||
|
||||
@ -2181,10 +2368,26 @@ static void evpn_show_all_routes(struct vty *vty, struct bgp *bgp, int type,
|
||||
static void evpn_show_vni(struct vty *vty, struct bgp *bgp, vni_t vni,
|
||||
json_object *json)
|
||||
{
|
||||
u_char found = 0;
|
||||
struct bgpevpn *vpn;
|
||||
|
||||
vpn = bgp_evpn_lookup_vni(bgp, vni);
|
||||
if (!vpn) {
|
||||
if (vpn) {
|
||||
found = 1;
|
||||
display_vni(vty, vpn, json);
|
||||
} else {
|
||||
struct bgp *bgp_temp;
|
||||
struct listnode *node = NULL;
|
||||
|
||||
for (ALL_LIST_ELEMENTS_RO(bm->bgp, node, bgp_temp)) {
|
||||
if (bgp_temp->l3vni == vni) {
|
||||
found = 1;
|
||||
display_l3vni(vty, bgp_temp, json);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
if (json) {
|
||||
vty_out(vty, "{}\n");
|
||||
} else {
|
||||
@ -2192,8 +2395,6 @@ static void evpn_show_vni(struct vty *vty, struct bgp *bgp, vni_t vni,
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
display_vni(vty, vpn, json);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2202,28 +2403,29 @@ static void evpn_show_vni(struct vty *vty, struct bgp *bgp, vni_t vni,
|
||||
static void evpn_show_all_vnis(struct vty *vty, struct bgp *bgp,
|
||||
json_object *json)
|
||||
{
|
||||
u_int32_t num_vnis;
|
||||
void *args[2];
|
||||
struct bgp *bgp_temp = NULL;
|
||||
struct listnode *node;
|
||||
|
||||
num_vnis = hashcount(bgp->vnihash);
|
||||
if (!num_vnis)
|
||||
return;
|
||||
|
||||
if (json) {
|
||||
json_object_int_add(json, "numVnis", num_vnis);
|
||||
} else {
|
||||
vty_out(vty, "Number of VNIs: %u\n", num_vnis);
|
||||
if (!json) {
|
||||
vty_out(vty, "Flags: * - Kernel\n");
|
||||
vty_out(vty, " %-10s %-15s %-21s %-25s %-25s %-37s\n", "VNI",
|
||||
"Orig IP", "RD", "Import RT",
|
||||
"Export RT", "Tenant-Vrf");
|
||||
vty_out(vty, " %-10s %-4s %-21s %-25s %-25s %-37s\n", "VNI",
|
||||
"Type", "RD", "Import RT",
|
||||
"Export RT", "Tenant VRF");
|
||||
}
|
||||
|
||||
/* print all L2 VNIS */
|
||||
args[0] = vty;
|
||||
args[1] = json;
|
||||
hash_iterate(bgp->vnihash,
|
||||
(void (*)(struct hash_backet *, void *))show_vni_entry,
|
||||
args);
|
||||
|
||||
/* print all L3 VNIs */
|
||||
for (ALL_LIST_ELEMENTS_RO(bm->bgp, node, bgp_temp))
|
||||
show_l3vni_entry(vty, bgp_temp, json);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2271,6 +2473,32 @@ static void evpn_unset_advertise_default_gw(struct bgp *bgp,
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* evpn - enable advertisement of default g/w
|
||||
*/
|
||||
static void evpn_set_advertise_subnet(struct bgp *bgp,
|
||||
struct bgpevpn *vpn)
|
||||
{
|
||||
if (vpn->advertise_subnet)
|
||||
return;
|
||||
|
||||
vpn->advertise_subnet = 1;
|
||||
bgp_zebra_advertise_subnet(bgp, vpn->advertise_subnet, vpn->vni);
|
||||
}
|
||||
|
||||
/*
|
||||
* evpn - disable advertisement of default g/w
|
||||
*/
|
||||
static void evpn_unset_advertise_subnet(struct bgp *bgp,
|
||||
struct bgpevpn *vpn)
|
||||
{
|
||||
if (!vpn->advertise_subnet)
|
||||
return;
|
||||
|
||||
vpn->advertise_subnet = 0;
|
||||
bgp_zebra_advertise_subnet(bgp, vpn->advertise_subnet, vpn->vni);
|
||||
}
|
||||
|
||||
/*
|
||||
* EVPN (VNI advertisement) enabled. Register with zebra.
|
||||
*/
|
||||
@ -2330,6 +2558,9 @@ static void write_vni_config(struct vty *vty, struct bgpevpn *vpn)
|
||||
if (vpn->advertise_gw_macip)
|
||||
vty_out(vty, " advertise-default-gw\n");
|
||||
|
||||
if (vpn->advertise_subnet)
|
||||
vty_out(vty, " advertise-subnet\n");
|
||||
|
||||
vty_out(vty, " exit-vni\n");
|
||||
}
|
||||
}
|
||||
@ -2440,6 +2671,56 @@ DEFUN (no_bgp_evpn_advertise_all_vni,
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN (bgp_evpn_advertise_vni_subnet,
|
||||
bgp_evpn_advertise_vni_subnet_cmd,
|
||||
"advertise-subnet",
|
||||
"Advertise the subnet corresponding to VNI\n")
|
||||
{
|
||||
struct bgp *bgp_vrf = NULL;
|
||||
struct bgp *bgp = VTY_GET_CONTEXT(bgp);
|
||||
VTY_DECLVAR_CONTEXT_SUB(bgpevpn, vpn);
|
||||
|
||||
if (!bgp)
|
||||
return CMD_WARNING;
|
||||
|
||||
if (!vpn)
|
||||
return CMD_WARNING;
|
||||
|
||||
bgp_vrf = bgp_lookup_by_vrf_id(vpn->tenant_vrf_id);
|
||||
if (!bgp_vrf)
|
||||
return CMD_WARNING;
|
||||
|
||||
if (!(advertise_type5_routes(bgp_vrf, AFI_IP) ||
|
||||
advertise_type5_routes(bgp_vrf, AFI_IP6))) {
|
||||
vty_out(vty,
|
||||
"%%Please enable ip prefix advertisement under l2vpn evpn in %s",
|
||||
vrf_id_to_name(bgp_vrf->vrf_id));
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
evpn_set_advertise_subnet(bgp, vpn);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN (no_bgp_evpn_advertise_vni_subnet,
|
||||
no_bgp_evpn_advertise_vni_subnet_cmd,
|
||||
"no advertise-subnet",
|
||||
NO_STR
|
||||
"Advertise All local VNIs\n")
|
||||
{
|
||||
struct bgp *bgp = VTY_GET_CONTEXT(bgp);
|
||||
VTY_DECLVAR_CONTEXT_SUB(bgpevpn, vpn);
|
||||
|
||||
if (!bgp)
|
||||
return CMD_WARNING;
|
||||
|
||||
if (!vpn)
|
||||
return CMD_WARNING;
|
||||
|
||||
evpn_unset_advertise_subnet(bgp, vpn);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN (bgp_evpn_advertise_type5,
|
||||
bgp_evpn_advertise_type5_cmd,
|
||||
"advertise " BGP_AFI_CMD_STR "" BGP_SAFI_CMD_STR,
|
||||
@ -2563,16 +2844,21 @@ DEFUN(show_bgp_l2vpn_evpn_vni,
|
||||
"VNI number\n"
|
||||
JSON_STR)
|
||||
{
|
||||
struct bgp *bgp;
|
||||
struct bgp *bgp_def;
|
||||
vni_t vni;
|
||||
int idx = 0;
|
||||
u_char uj = 0;
|
||||
json_object *json = NULL;
|
||||
u_int32_t num_l2vnis = 0;
|
||||
u_int32_t num_l3vnis = 0;
|
||||
uint32_t num_vnis = 0;
|
||||
struct listnode *node = NULL;
|
||||
struct bgp *bgp_temp = NULL;
|
||||
|
||||
uj = use_json(argc, argv);
|
||||
|
||||
bgp = bgp_get_default();
|
||||
if (!bgp)
|
||||
bgp_def = bgp_get_default();
|
||||
if (!bgp_def)
|
||||
return CMD_WARNING;
|
||||
|
||||
if (!argv_find(argv, argc, "evpn", &idx))
|
||||
@ -2582,26 +2868,36 @@ DEFUN(show_bgp_l2vpn_evpn_vni,
|
||||
json = json_object_new_object();
|
||||
|
||||
if ((uj && argc == ((idx + 1) + 2)) || (!uj && argc == (idx + 1) + 1)) {
|
||||
|
||||
num_l2vnis = hashcount(bgp_def->vnihash);
|
||||
|
||||
for (ALL_LIST_ELEMENTS_RO(bm->bgp, node, bgp_temp)) {
|
||||
if (bgp_temp->l3vni)
|
||||
num_l3vnis++;
|
||||
}
|
||||
num_vnis = num_l2vnis + num_l3vnis;
|
||||
if (uj) {
|
||||
json_object_string_add(json, "advertiseGatewayMacip",
|
||||
bgp->advertise_gw_macip
|
||||
bgp_def->advertise_gw_macip
|
||||
? "Enabled"
|
||||
: "Disabled");
|
||||
json_object_string_add(json, "advertiseAllVnis",
|
||||
is_evpn_enabled()
|
||||
? "Enabled"
|
||||
: "Disabled");
|
||||
json_object_int_add(json, "numVnis", num_vnis);
|
||||
json_object_int_add(json, "numL2Vnis", num_l2vnis);
|
||||
json_object_int_add(json, "numL3Vnis", num_l3vnis);
|
||||
} else {
|
||||
vty_out(vty, "Advertise Gateway Macip: %s\n",
|
||||
bgp->advertise_gw_macip ? "Enabled"
|
||||
bgp_def->advertise_gw_macip ? "Enabled"
|
||||
: "Disabled");
|
||||
|
||||
/* Display all VNIs */
|
||||
vty_out(vty, "Advertise All VNI flag: %s\n",
|
||||
is_evpn_enabled() ? "Enabled" : "Disabled");
|
||||
vty_out(vty, "Number of L2 VNIs: %u\n", num_l2vnis);
|
||||
vty_out(vty, "Number of L3 VNIs: %u\n", num_l3vnis);
|
||||
}
|
||||
|
||||
evpn_show_all_vnis(vty, bgp, json);
|
||||
evpn_show_all_vnis(vty, bgp_def, json);
|
||||
} else {
|
||||
int vni_idx = 0;
|
||||
|
||||
@ -2610,7 +2906,7 @@ DEFUN(show_bgp_l2vpn_evpn_vni,
|
||||
|
||||
/* Display specific VNI */
|
||||
vni = strtoul(argv[vni_idx + 1]->arg, NULL, 10);
|
||||
evpn_show_vni(vty, bgp, vni, json);
|
||||
evpn_show_vni(vty, bgp_def, vni, json);
|
||||
}
|
||||
|
||||
if (uj) {
|
||||
@ -2644,7 +2940,7 @@ DEFUN(show_bgp_l2vpn_evpn_summary,
|
||||
*/
|
||||
DEFUN(show_bgp_l2vpn_evpn_route,
|
||||
show_bgp_l2vpn_evpn_route_cmd,
|
||||
"show bgp l2vpn evpn route [type <macip|multicast>] [json]",
|
||||
"show bgp l2vpn evpn route [type <macip|multicast|prefix>] [json]",
|
||||
SHOW_STR
|
||||
BGP_STR
|
||||
L2VPN_HELP_STR
|
||||
@ -2653,6 +2949,7 @@ DEFUN(show_bgp_l2vpn_evpn_route,
|
||||
"Specify Route type\n"
|
||||
"MAC-IP (Type-2) route\n"
|
||||
"Multicast (Type-3) route\n"
|
||||
"Prefix route\n"
|
||||
JSON_STR)
|
||||
{
|
||||
struct bgp *bgp;
|
||||
@ -2677,6 +2974,8 @@ DEFUN(show_bgp_l2vpn_evpn_route,
|
||||
type = BGP_EVPN_MAC_IP_ROUTE;
|
||||
else if (strncmp(argv[type_idx + 1]->arg, "mu", 2) == 0)
|
||||
type = BGP_EVPN_IMET_ROUTE;
|
||||
else if (strncmp(argv[type_idx + 1]->arg, "pr", 2) == 0)
|
||||
type = BGP_EVPN_IP_PREFIX_ROUTE;
|
||||
else
|
||||
return CMD_WARNING;
|
||||
}
|
||||
@ -2688,7 +2987,6 @@ DEFUN(show_bgp_l2vpn_evpn_route,
|
||||
json, JSON_C_TO_STRING_PRETTY));
|
||||
json_object_free(json);
|
||||
}
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
@ -2697,7 +2995,7 @@ DEFUN(show_bgp_l2vpn_evpn_route,
|
||||
*/
|
||||
DEFUN(show_bgp_l2vpn_evpn_route_rd,
|
||||
show_bgp_l2vpn_evpn_route_rd_cmd,
|
||||
"show bgp l2vpn evpn route rd ASN:NN_OR_IP-ADDRESS:NN [type <macip|multicast>] [json]",
|
||||
"show bgp l2vpn evpn route rd ASN:NN_OR_IP-ADDRESS:NN [type <macip|multicast|prefix>] [json]",
|
||||
SHOW_STR
|
||||
BGP_STR
|
||||
L2VPN_HELP_STR
|
||||
@ -2708,6 +3006,7 @@ DEFUN(show_bgp_l2vpn_evpn_route_rd,
|
||||
"Specify Route type\n"
|
||||
"MAC-IP (Type-2) route\n"
|
||||
"Multicast (Type-3) route\n"
|
||||
"Prefix route\n"
|
||||
JSON_STR)
|
||||
{
|
||||
struct bgp *bgp;
|
||||
@ -2745,6 +3044,8 @@ DEFUN(show_bgp_l2vpn_evpn_route_rd,
|
||||
type = BGP_EVPN_MAC_IP_ROUTE;
|
||||
else if (strncmp(argv[type_idx + 1]->arg, "mu", 2) == 0)
|
||||
type = BGP_EVPN_IMET_ROUTE;
|
||||
else if (strncmp(argv[type_idx + 1]->arg, "pr", 2) == 0)
|
||||
type = BGP_EVPN_IP_PREFIX_ROUTE;
|
||||
else
|
||||
return CMD_WARNING;
|
||||
}
|
||||
@ -3544,13 +3845,12 @@ static int bgp_evpn_rt_matches_existing(struct list *rtl,
|
||||
/* display L3VNI related info for a VRF instance */
|
||||
DEFUN (show_bgp_vrf_l3vni_info,
|
||||
show_bgp_vrf_l3vni_info_cmd,
|
||||
"show bgp vrf VRFNAME l3vni info [json]",
|
||||
"show bgp vrf VRFNAME vni [json]",
|
||||
SHOW_STR
|
||||
BGP_STR
|
||||
"show bgp vrf\n"
|
||||
"VRF Name\n"
|
||||
"L3-VNI\n"
|
||||
"L3-VNI info\n"
|
||||
JSON_STR)
|
||||
{
|
||||
char buf[ETHER_ADDR_STRLEN];
|
||||
@ -4118,5 +4418,8 @@ void bgp_ethernetvpn_init(void)
|
||||
&bgp_evpn_advertise_default_gw_vni_cmd);
|
||||
install_element(BGP_EVPN_VNI_NODE,
|
||||
&no_bgp_evpn_advertise_default_gw_vni_cmd);
|
||||
install_element(BGP_EVPN_VNI_NODE, &bgp_evpn_advertise_vni_subnet_cmd);
|
||||
install_element(BGP_EVPN_VNI_NODE,
|
||||
&no_bgp_evpn_advertise_vni_subnet_cmd);
|
||||
#endif
|
||||
}
|
||||
|
@ -103,7 +103,7 @@ mpls_label_t bgp_adv_label(struct bgp_node *rn, struct bgp_info *ri,
|
||||
if (!rn || !ri || !to)
|
||||
return MPLS_INVALID_LABEL;
|
||||
|
||||
remote_label = ri->extra ? ri->extra->label : MPLS_INVALID_LABEL;
|
||||
remote_label = ri->extra ? ri->extra->label[0] : MPLS_INVALID_LABEL;
|
||||
from = ri->peer;
|
||||
reflect =
|
||||
((from->sort == BGP_PEER_IBGP) && (to->sort == BGP_PEER_IBGP));
|
||||
@ -325,11 +325,11 @@ int bgp_nlri_parse_label(struct peer *peer, struct attr *attr,
|
||||
if (attr) {
|
||||
bgp_update(peer, &p, addpath_id, attr, packet->afi,
|
||||
SAFI_UNICAST, ZEBRA_ROUTE_BGP,
|
||||
BGP_ROUTE_NORMAL, NULL, &label, 0, NULL);
|
||||
BGP_ROUTE_NORMAL, NULL, &label, 1, 0, NULL);
|
||||
} else {
|
||||
bgp_withdraw(peer, &p, addpath_id, attr, packet->afi,
|
||||
SAFI_UNICAST, ZEBRA_ROUTE_BGP,
|
||||
BGP_ROUTE_NORMAL, NULL, &label, NULL);
|
||||
BGP_ROUTE_NORMAL, NULL, &label, 1, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -214,11 +214,11 @@ int bgp_nlri_parse_vpn(struct peer *peer, struct attr *attr,
|
||||
if (attr) {
|
||||
bgp_update(peer, &p, addpath_id, attr, packet->afi,
|
||||
SAFI_MPLS_VPN, ZEBRA_ROUTE_BGP,
|
||||
BGP_ROUTE_NORMAL, &prd, &label, 0, NULL);
|
||||
BGP_ROUTE_NORMAL, &prd, &label, 1, 0, NULL);
|
||||
} else {
|
||||
bgp_withdraw(peer, &p, addpath_id, attr, packet->afi,
|
||||
SAFI_MPLS_VPN, ZEBRA_ROUTE_BGP,
|
||||
BGP_ROUTE_NORMAL, &prd, &label, NULL);
|
||||
BGP_ROUTE_NORMAL, &prd, &label, 1, NULL);
|
||||
}
|
||||
}
|
||||
/* Packet length consistency check. */
|
||||
|
124
bgpd/bgp_route.c
124
bgpd/bgp_route.c
@ -147,7 +147,8 @@ static struct bgp_info_extra *bgp_info_extra_new(void)
|
||||
{
|
||||
struct bgp_info_extra *new;
|
||||
new = XCALLOC(MTYPE_BGP_ROUTE_EXTRA, sizeof(struct bgp_info_extra));
|
||||
new->label = MPLS_INVALID_LABEL;
|
||||
new->label[0] = MPLS_INVALID_LABEL;
|
||||
new->num_labels = 0;
|
||||
return new;
|
||||
}
|
||||
|
||||
@ -770,9 +771,9 @@ static int bgp_info_cmp(struct bgp *bgp, struct bgp_info *new,
|
||||
/* If one path has a label but the other does not, do not treat
|
||||
* them as equals for multipath
|
||||
*/
|
||||
if ((new->extra &&bgp_is_valid_label(&new->extra->label))
|
||||
if ((new->extra && bgp_is_valid_label(&new->extra->label[0]))
|
||||
!= (exist->extra
|
||||
&& bgp_is_valid_label(&exist->extra->label))) {
|
||||
&& bgp_is_valid_label(&exist->extra->label[0]))) {
|
||||
if (debug)
|
||||
zlog_debug(
|
||||
"%s: %s and %s cannot be multipath, one has a label while the other does not",
|
||||
@ -2225,9 +2226,11 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_node *rn,
|
||||
/* advertise/withdraw type-5 routes */
|
||||
if ((afi == AFI_IP || afi == AFI_IP6) && (safi == SAFI_UNICAST)) {
|
||||
if (new_select)
|
||||
bgp_evpn_advertise_type5_route(bgp, rn, afi, safi);
|
||||
bgp_evpn_advertise_type5_route(bgp, &rn->p,
|
||||
new_select->attr,
|
||||
afi, safi);
|
||||
else if (old_select)
|
||||
bgp_evpn_withdraw_type5_route(bgp, rn, afi, safi);
|
||||
bgp_evpn_withdraw_type5_route(bgp, &rn->p, afi, safi);
|
||||
}
|
||||
|
||||
/* Clear any route change flags. */
|
||||
@ -2670,7 +2673,8 @@ static int bgp_update_martian_nexthop(struct bgp *bgp, afi_t afi, safi_t safi,
|
||||
|
||||
int bgp_update(struct peer *peer, struct prefix *p, u_int32_t addpath_id,
|
||||
struct attr *attr, afi_t afi, safi_t safi, int type,
|
||||
int sub_type, struct prefix_rd *prd, mpls_label_t *label,
|
||||
int sub_type, struct prefix_rd *prd,
|
||||
mpls_label_t *label, u_int32_t num_labels,
|
||||
int soft_reconfig, struct bgp_route_evpn *evpn)
|
||||
{
|
||||
int ret;
|
||||
@ -2681,9 +2685,9 @@ int bgp_update(struct peer *peer, struct prefix *p, u_int32_t addpath_id,
|
||||
struct attr *attr_new;
|
||||
struct bgp_info *ri;
|
||||
struct bgp_info *new;
|
||||
struct bgp_info_extra *extra;
|
||||
const char *reason;
|
||||
char pfx_buf[BGP_PRD_PATH_STRLEN];
|
||||
char label_buf[20];
|
||||
int connected = 0;
|
||||
int do_loop_check = 1;
|
||||
int has_valid_label = 0;
|
||||
@ -2698,10 +2702,11 @@ int bgp_update(struct peer *peer, struct prefix *p, u_int32_t addpath_id,
|
||||
|
||||
bgp = peer->bgp;
|
||||
rn = bgp_afi_node_get(bgp->rib[afi][safi], afi, safi, p, prd);
|
||||
has_valid_label = bgp_is_valid_label(label);
|
||||
|
||||
if (has_valid_label)
|
||||
sprintf(label_buf, "label %u", label_pton(label));
|
||||
/* TODO: Check to see if we can get rid of "is_valid_label" */
|
||||
if (afi == AFI_L2VPN && safi == SAFI_EVPN)
|
||||
has_valid_label = (num_labels > 0) ? 1 : 0;
|
||||
else
|
||||
has_valid_label = bgp_is_valid_label(label);
|
||||
|
||||
/* When peer's soft reconfiguration enabled. Record input packet in
|
||||
Adj-RIBs-In. */
|
||||
@ -2821,7 +2826,7 @@ int bgp_update(struct peer *peer, struct prefix *p, u_int32_t addpath_id,
|
||||
&& attrhash_cmp(ri->attr, attr_new)
|
||||
&& (!has_valid_label
|
||||
|| memcmp(&(bgp_info_extra_get(ri))->label, label,
|
||||
BGP_LABEL_BYTES)
|
||||
num_labels * sizeof(mpls_label_t))
|
||||
== 0)
|
||||
&& (overlay_index_equal(
|
||||
afi, ri, evpn == NULL ? NULL : &evpn->eth_s_id,
|
||||
@ -2832,7 +2837,8 @@ int bgp_update(struct peer *peer, struct prefix *p, u_int32_t addpath_id,
|
||||
&& CHECK_FLAG(ri->flags, BGP_INFO_HISTORY)) {
|
||||
if (bgp_debug_update(peer, p, NULL, 1)) {
|
||||
bgp_debug_rdpfxpath2str(
|
||||
afi, safi, prd, p, label,
|
||||
afi, safi, prd, p,
|
||||
label, num_labels,
|
||||
addpath_id ? 1 : 0, addpath_id,
|
||||
pfx_buf, sizeof(pfx_buf));
|
||||
zlog_debug("%s rcvd %s", peer->host,
|
||||
@ -2857,7 +2863,8 @@ int bgp_update(struct peer *peer, struct prefix *p, u_int32_t addpath_id,
|
||||
}
|
||||
|
||||
bgp_debug_rdpfxpath2str(
|
||||
afi, safi, prd, p, label,
|
||||
afi, safi, prd, p,
|
||||
label, num_labels,
|
||||
addpath_id ? 1 : 0, addpath_id,
|
||||
pfx_buf, sizeof(pfx_buf));
|
||||
zlog_debug(
|
||||
@ -2883,7 +2890,8 @@ int bgp_update(struct peer *peer, struct prefix *p, u_int32_t addpath_id,
|
||||
if (CHECK_FLAG(ri->flags, BGP_INFO_REMOVED)) {
|
||||
if (bgp_debug_update(peer, p, NULL, 1)) {
|
||||
bgp_debug_rdpfxpath2str(
|
||||
afi, safi, prd, p, label,
|
||||
afi, safi, prd, p,
|
||||
label, num_labels,
|
||||
addpath_id ? 1 : 0, addpath_id, pfx_buf,
|
||||
sizeof(pfx_buf));
|
||||
zlog_debug(
|
||||
@ -2896,7 +2904,8 @@ int bgp_update(struct peer *peer, struct prefix *p, u_int32_t addpath_id,
|
||||
|
||||
/* Received Logging. */
|
||||
if (bgp_debug_update(peer, p, NULL, 1)) {
|
||||
bgp_debug_rdpfxpath2str(afi, safi, prd, p, label,
|
||||
bgp_debug_rdpfxpath2str(afi, safi, prd, p,
|
||||
label, num_labels,
|
||||
addpath_id ? 1 : 0, addpath_id,
|
||||
pfx_buf, sizeof(pfx_buf));
|
||||
zlog_debug("%s rcvd %s", peer->host, pfx_buf);
|
||||
@ -2987,9 +2996,12 @@ int bgp_update(struct peer *peer, struct prefix *p, u_int32_t addpath_id,
|
||||
|
||||
/* Update MPLS label */
|
||||
if (has_valid_label) {
|
||||
memcpy(&(bgp_info_extra_get(ri))->label, label,
|
||||
BGP_LABEL_BYTES);
|
||||
bgp_set_valid_label(&(bgp_info_extra_get(ri))->label);
|
||||
extra = bgp_info_extra_get(ri);
|
||||
memcpy(&extra->label, label,
|
||||
num_labels * sizeof(mpls_label_t));
|
||||
extra->num_labels = num_labels;
|
||||
if (!(afi == AFI_L2VPN && safi == SAFI_EVPN))
|
||||
bgp_set_valid_label(&extra->label[0]);
|
||||
}
|
||||
|
||||
#if ENABLE_BGP_VNC
|
||||
@ -3126,7 +3138,8 @@ int bgp_update(struct peer *peer, struct prefix *p, u_int32_t addpath_id,
|
||||
peer->rcvd_attr_printed = 1;
|
||||
}
|
||||
|
||||
bgp_debug_rdpfxpath2str(afi, safi, prd, p, label,
|
||||
bgp_debug_rdpfxpath2str(afi, safi, prd, p,
|
||||
label, num_labels,
|
||||
addpath_id ? 1 : 0, addpath_id, pfx_buf,
|
||||
sizeof(pfx_buf));
|
||||
zlog_debug("%s rcvd %s", peer->host, pfx_buf);
|
||||
@ -3137,9 +3150,12 @@ int bgp_update(struct peer *peer, struct prefix *p, u_int32_t addpath_id,
|
||||
|
||||
/* Update MPLS label */
|
||||
if (has_valid_label) {
|
||||
memcpy(&(bgp_info_extra_get(new))->label, label,
|
||||
BGP_LABEL_BYTES);
|
||||
bgp_set_valid_label(&(bgp_info_extra_get(new))->label);
|
||||
extra = bgp_info_extra_get(new);
|
||||
memcpy(&extra->label, label,
|
||||
num_labels * sizeof(mpls_label_t));
|
||||
extra->num_labels = num_labels;
|
||||
if (!(afi == AFI_L2VPN && safi == SAFI_EVPN))
|
||||
bgp_set_valid_label(&extra->label[0]);
|
||||
}
|
||||
|
||||
/* Update Overlay Index */
|
||||
@ -3241,7 +3257,8 @@ filtered:
|
||||
peer->rcvd_attr_printed = 1;
|
||||
}
|
||||
|
||||
bgp_debug_rdpfxpath2str(afi, safi, prd, p, label,
|
||||
bgp_debug_rdpfxpath2str(afi, safi, prd, p,
|
||||
label, num_labels,
|
||||
addpath_id ? 1 : 0, addpath_id, pfx_buf,
|
||||
sizeof(pfx_buf));
|
||||
zlog_debug("%s rcvd UPDATE about %s -- DENIED due to: %s",
|
||||
@ -3276,7 +3293,8 @@ filtered:
|
||||
|
||||
int bgp_withdraw(struct peer *peer, struct prefix *p, u_int32_t addpath_id,
|
||||
struct attr *attr, afi_t afi, safi_t safi, int type,
|
||||
int sub_type, struct prefix_rd *prd, mpls_label_t *label,
|
||||
int sub_type, struct prefix_rd *prd,
|
||||
mpls_label_t *label, u_int32_t num_labels,
|
||||
struct bgp_route_evpn *evpn)
|
||||
{
|
||||
struct bgp *bgp;
|
||||
@ -3312,7 +3330,8 @@ int bgp_withdraw(struct peer *peer, struct prefix *p, u_int32_t addpath_id,
|
||||
if (!bgp_adj_in_unset(rn, peer, addpath_id)) {
|
||||
if (bgp_debug_update(peer, p, NULL, 1)) {
|
||||
bgp_debug_rdpfxpath2str(
|
||||
afi, safi, prd, p, label,
|
||||
afi, safi, prd, p,
|
||||
label, num_labels,
|
||||
addpath_id ? 1 : 0, addpath_id, pfx_buf,
|
||||
sizeof(pfx_buf));
|
||||
zlog_debug(
|
||||
@ -3332,7 +3351,8 @@ int bgp_withdraw(struct peer *peer, struct prefix *p, u_int32_t addpath_id,
|
||||
|
||||
/* Logging. */
|
||||
if (bgp_debug_update(peer, p, NULL, 1)) {
|
||||
bgp_debug_rdpfxpath2str(afi, safi, prd, p, label,
|
||||
bgp_debug_rdpfxpath2str(afi, safi, prd, p,
|
||||
label, num_labels,
|
||||
addpath_id ? 1 : 0, addpath_id, pfx_buf,
|
||||
sizeof(pfx_buf));
|
||||
zlog_debug("%s rcvd UPDATE about %s -- withdrawn", peer->host,
|
||||
@ -3343,7 +3363,8 @@ int bgp_withdraw(struct peer *peer, struct prefix *p, u_int32_t addpath_id,
|
||||
if (ri && !CHECK_FLAG(ri->flags, BGP_INFO_HISTORY))
|
||||
bgp_rib_withdraw(rn, ri, peer, afi, safi, prd);
|
||||
else if (bgp_debug_update(peer, p, NULL, 1)) {
|
||||
bgp_debug_rdpfxpath2str(afi, safi, prd, p, label,
|
||||
bgp_debug_rdpfxpath2str(afi, safi, prd, p,
|
||||
label, num_labels,
|
||||
addpath_id ? 1 : 0, addpath_id, pfx_buf,
|
||||
sizeof(pfx_buf));
|
||||
zlog_debug("%s Can't find the route %s", peer->host, pfx_buf);
|
||||
@ -3469,14 +3490,18 @@ static void bgp_soft_reconfig_table(struct peer *peer, afi_t afi, safi_t safi,
|
||||
continue;
|
||||
|
||||
struct bgp_info *ri = rn->info;
|
||||
mpls_label_t label = (ri && ri->extra)
|
||||
? ri->extra->label
|
||||
: MPLS_INVALID_LABEL;
|
||||
u_int32_t num_labels = 0;
|
||||
mpls_label_t *label_pnt = NULL;
|
||||
|
||||
if (ri && ri->extra)
|
||||
num_labels = ri->extra->num_labels;
|
||||
if (num_labels)
|
||||
label_pnt = &ri->extra->label[0];
|
||||
|
||||
ret = bgp_update(peer, &rn->p, ain->addpath_rx_id,
|
||||
ain->attr, afi, safi, ZEBRA_ROUTE_BGP,
|
||||
BGP_ROUTE_NORMAL, prd, &label, 1,
|
||||
NULL);
|
||||
BGP_ROUTE_NORMAL, prd,
|
||||
label_pnt, num_labels, 1, NULL);
|
||||
|
||||
if (ret < 0) {
|
||||
bgp_unlock_node(rn);
|
||||
@ -4029,11 +4054,12 @@ int bgp_nlri_parse_ip(struct peer *peer, struct attr *attr,
|
||||
if (attr)
|
||||
ret = bgp_update(peer, &p, addpath_id, attr, afi, safi,
|
||||
ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL,
|
||||
NULL, NULL, 0, NULL);
|
||||
NULL, NULL, 0, 0, NULL);
|
||||
else
|
||||
ret = bgp_withdraw(peer, &p, addpath_id, attr, afi,
|
||||
safi, ZEBRA_ROUTE_BGP,
|
||||
BGP_ROUTE_NORMAL, NULL, NULL, NULL);
|
||||
BGP_ROUTE_NORMAL, NULL,
|
||||
NULL, 0, NULL);
|
||||
|
||||
/* Address family configuration mismatch or maximum-prefix count
|
||||
overflow. */
|
||||
@ -4345,10 +4371,13 @@ static void bgp_static_update_safi(struct bgp *bgp, struct prefix *p,
|
||||
#if ENABLE_BGP_VNC
|
||||
mpls_label_t label = 0;
|
||||
#endif
|
||||
u_int32_t num_labels = 0;
|
||||
union gw_addr add;
|
||||
|
||||
assert(bgp_static);
|
||||
|
||||
if (bgp_static->label != MPLS_INVALID_LABEL)
|
||||
num_labels = 1;
|
||||
rn = bgp_afi_node_get(bgp->rib[afi][safi], afi, safi, p,
|
||||
&bgp_static->prd);
|
||||
|
||||
@ -4443,7 +4472,7 @@ static void bgp_static_update_safi(struct bgp *bgp, struct prefix *p,
|
||||
ri->uptime = bgp_clock();
|
||||
#if ENABLE_BGP_VNC
|
||||
if (ri->extra)
|
||||
label = decode_label(&ri->extra->label);
|
||||
label = decode_label(&ri->extra->label[0]);
|
||||
#endif
|
||||
|
||||
/* Process change. */
|
||||
@ -4466,7 +4495,10 @@ static void bgp_static_update_safi(struct bgp *bgp, struct prefix *p,
|
||||
attr_new, rn);
|
||||
SET_FLAG(new->flags, BGP_INFO_VALID);
|
||||
new->extra = bgp_info_extra_new();
|
||||
new->extra->label = bgp_static->label;
|
||||
if (num_labels) {
|
||||
new->extra->label[0] = bgp_static->label;
|
||||
new->extra->num_labels = num_labels;
|
||||
}
|
||||
#if ENABLE_BGP_VNC
|
||||
label = decode_label(&bgp_static->label);
|
||||
#endif
|
||||
@ -6713,7 +6745,7 @@ void route_vty_out_tag(struct vty *vty, struct prefix *p,
|
||||
}
|
||||
}
|
||||
|
||||
label = decode_label(&binfo->extra->label);
|
||||
label = decode_label(&binfo->extra->label[0]);
|
||||
|
||||
if (bgp_is_valid_label(&label)) {
|
||||
if (json) {
|
||||
@ -7051,14 +7083,15 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct prefix *p,
|
||||
|
||||
#if defined(HAVE_CUMULUS)
|
||||
if (!json_paths && safi == SAFI_EVPN) {
|
||||
char tag_buf[20];
|
||||
char tag_buf[30];
|
||||
|
||||
bgp_evpn_route2str((struct prefix_evpn *)p, buf2, sizeof(buf2));
|
||||
vty_out(vty, " Route %s", buf2);
|
||||
tag_buf[0] = '\0';
|
||||
if (binfo->extra) {
|
||||
bgp_evpn_label2str(&binfo->extra->label, tag_buf,
|
||||
sizeof(tag_buf));
|
||||
if (binfo->extra && binfo->extra->num_labels) {
|
||||
bgp_evpn_label2str(binfo->extra->label,
|
||||
binfo->extra->num_labels,
|
||||
tag_buf, sizeof(tag_buf));
|
||||
vty_out(vty, " VNI %s", tag_buf);
|
||||
}
|
||||
vty_out(vty, "\n");
|
||||
@ -7692,13 +7725,14 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct prefix *p,
|
||||
|
||||
/* Remote Label */
|
||||
#if defined(HAVE_CUMULUS)
|
||||
if (binfo->extra && bgp_is_valid_label(&binfo->extra->label)
|
||||
if (binfo->extra && bgp_is_valid_label(&binfo->extra->label[0])
|
||||
&& safi != SAFI_EVPN)
|
||||
#else
|
||||
if (binfo->extra && bgp_is_valid_label(&binfo->extra->label))
|
||||
if (binfo->extra && bgp_is_valid_label(&binfo->extra->label[0]))
|
||||
#endif
|
||||
{
|
||||
mpls_label_t label = label_pton(&binfo->extra->label);
|
||||
mpls_label_t label = label_pton(
|
||||
&binfo->extra->label[0]);
|
||||
if (json_paths)
|
||||
json_object_int_add(json_path, "remoteLabel",
|
||||
label);
|
||||
|
@ -59,6 +59,11 @@ enum bgp_show_type {
|
||||
#define BGP_SHOW_OCODE_HEADER "Origin codes: i - IGP, e - EGP, ? - incomplete\n\n"
|
||||
#define BGP_SHOW_HEADER " Network Next Hop Metric LocPrf Weight Path\n"
|
||||
|
||||
/* Maximum number of labels we can process or send with a prefix. We
|
||||
* really do only 1 for MPLS (BGP-LU) but we can do 2 for EVPN-VxLAN.
|
||||
*/
|
||||
#define BGP_MAX_LABELS 2
|
||||
|
||||
/* Ancillary information to struct bgp_info,
|
||||
* used for uncommonly used data (aggregation, MPLS, etc.)
|
||||
* and lazily allocated to save memory.
|
||||
@ -73,11 +78,9 @@ struct bgp_info_extra {
|
||||
/* Nexthop reachability check. */
|
||||
u_int32_t igpmetric;
|
||||
|
||||
/* MPLS label - L2VNI */
|
||||
mpls_label_t label;
|
||||
|
||||
/* MPLS label - L3-VNI */
|
||||
mpls_label_t label2;
|
||||
/* MPLS label(s) - VNI(s) for EVPN-VxLAN */
|
||||
mpls_label_t label[BGP_MAX_LABELS];
|
||||
u_int32_t num_labels;
|
||||
|
||||
#if ENABLE_BGP_VNC
|
||||
union {
|
||||
@ -360,10 +363,10 @@ extern int bgp_static_unset_safi(afi_t afi, safi_t safi, struct vty *,
|
||||
/* this is primarily for MPLS-VPN */
|
||||
extern int bgp_update(struct peer *, struct prefix *, u_int32_t, struct attr *,
|
||||
afi_t, safi_t, int, int, struct prefix_rd *,
|
||||
mpls_label_t *, int, struct bgp_route_evpn *);
|
||||
mpls_label_t *, u_int32_t, int, struct bgp_route_evpn *);
|
||||
extern int bgp_withdraw(struct peer *, struct prefix *, u_int32_t,
|
||||
struct attr *, afi_t, safi_t, int, int,
|
||||
struct prefix_rd *, mpls_label_t *,
|
||||
struct prefix_rd *, mpls_label_t *, u_int32_t,
|
||||
struct bgp_route_evpn *);
|
||||
|
||||
/* for bgp_nexthop and bgp_damp */
|
||||
|
@ -659,7 +659,7 @@ static route_map_result_t route_match_vni(void *rule, struct prefix *prefix,
|
||||
vni = *((vni_t *)rule);
|
||||
bgp_info = (struct bgp_info *)object;
|
||||
|
||||
if (vni == label2vni(&bgp_info->extra->label))
|
||||
if (vni == label2vni(&bgp_info->extra->label[0]))
|
||||
return RMAP_MATCH;
|
||||
}
|
||||
|
||||
|
@ -701,7 +701,8 @@ struct bpacket *subgroup_update_packet(struct update_subgroup *subgrp)
|
||||
int addpath_overhead = 0;
|
||||
u_int32_t addpath_tx_id = 0;
|
||||
struct prefix_rd *prd = NULL;
|
||||
mpls_label_t label = MPLS_INVALID_LABEL;
|
||||
mpls_label_t label = MPLS_INVALID_LABEL, *label_pnt = NULL;
|
||||
u_int32_t num_labels = 0;
|
||||
|
||||
if (!subgrp)
|
||||
return NULL;
|
||||
@ -772,7 +773,7 @@ struct bpacket *subgroup_update_packet(struct update_subgroup *subgrp)
|
||||
* attr. */
|
||||
total_attr_len = bgp_packet_attribute(
|
||||
NULL, peer, s, adv->baa->attr, &vecarr, NULL,
|
||||
afi, safi, from, NULL, NULL, 0, 0);
|
||||
afi, safi, from, NULL, NULL, 0, 0, 0);
|
||||
|
||||
space_remaining =
|
||||
STREAM_CONCAT_REMAIN(s, snlri, STREAM_SIZE(s))
|
||||
@ -815,11 +816,15 @@ struct bpacket *subgroup_update_packet(struct update_subgroup *subgrp)
|
||||
if (rn->prn)
|
||||
prd = (struct prefix_rd *)&rn->prn->p;
|
||||
|
||||
if (safi == SAFI_LABELED_UNICAST)
|
||||
if (safi == SAFI_LABELED_UNICAST) {
|
||||
label = bgp_adv_label(rn, binfo, peer, afi,
|
||||
safi);
|
||||
else if (binfo && binfo->extra)
|
||||
label = binfo->extra->label;
|
||||
label_pnt = &label;
|
||||
num_labels = 1;
|
||||
} else if (binfo && binfo->extra) {
|
||||
label_pnt = &binfo->extra->label[0];
|
||||
num_labels = binfo->extra->num_labels;
|
||||
}
|
||||
|
||||
if (stream_empty(snlri))
|
||||
mpattrlen_pos = bgp_packet_mpattr_start(
|
||||
@ -827,8 +832,9 @@ struct bpacket *subgroup_update_packet(struct update_subgroup *subgrp)
|
||||
adv->baa->attr);
|
||||
|
||||
bgp_packet_mpattr_prefix(snlri, afi, safi, &rn->p, prd,
|
||||
&label, addpath_encode,
|
||||
addpath_tx_id, adv->baa->attr);
|
||||
label_pnt, num_labels,
|
||||
addpath_encode, addpath_tx_id,
|
||||
adv->baa->attr);
|
||||
}
|
||||
|
||||
num_pfx++;
|
||||
@ -857,7 +863,8 @@ struct bpacket *subgroup_update_packet(struct update_subgroup *subgrp)
|
||||
send_attr_printed = 1;
|
||||
}
|
||||
|
||||
bgp_debug_rdpfxpath2str(afi, safi, prd, &rn->p, &label,
|
||||
bgp_debug_rdpfxpath2str(afi, safi, prd, &rn->p,
|
||||
label_pnt, num_labels,
|
||||
addpath_encode, addpath_tx_id,
|
||||
pfx_buf, sizeof(pfx_buf));
|
||||
zlog_debug("u%" PRIu64 ":s%" PRIu64 " send UPDATE %s",
|
||||
@ -1009,7 +1016,7 @@ struct bpacket *subgroup_withdraw_packet(struct update_subgroup *subgrp)
|
||||
}
|
||||
|
||||
bgp_packet_mpunreach_prefix(s, &rn->p, afi, safi, prd,
|
||||
NULL, addpath_encode,
|
||||
NULL, 0, addpath_encode,
|
||||
addpath_tx_id, NULL);
|
||||
}
|
||||
|
||||
@ -1018,7 +1025,7 @@ struct bpacket *subgroup_withdraw_packet(struct update_subgroup *subgrp)
|
||||
if (bgp_debug_update(NULL, &rn->p, subgrp->update_group, 0)) {
|
||||
char pfx_buf[BGP_PRD_PATH_STRLEN];
|
||||
|
||||
bgp_debug_rdpfxpath2str(afi, safi, prd, &rn->p, NULL,
|
||||
bgp_debug_rdpfxpath2str(afi, safi, prd, &rn->p, NULL, 0,
|
||||
addpath_encode, addpath_tx_id,
|
||||
pfx_buf, sizeof(pfx_buf));
|
||||
zlog_debug("u%" PRIu64 ":s%" PRIu64
|
||||
@ -1132,7 +1139,7 @@ void subgroup_default_update_packet(struct update_subgroup *subgrp,
|
||||
stream_putw(s, 0);
|
||||
total_attr_len = bgp_packet_attribute(
|
||||
NULL, peer, s, attr, &vecarr, &p, afi, safi, from, NULL, NULL,
|
||||
addpath_encode, BGP_ADDPATH_TX_ID_FOR_DEFAULT_ORIGINATE);
|
||||
0, addpath_encode, BGP_ADDPATH_TX_ID_FOR_DEFAULT_ORIGINATE);
|
||||
|
||||
/* Set Total Path Attribute Length. */
|
||||
stream_putw_at(s, pos, total_attr_len);
|
||||
@ -1227,7 +1234,7 @@ void subgroup_default_withdraw_packet(struct update_subgroup *subgrp)
|
||||
mp_start = stream_get_endp(s);
|
||||
mplen_pos = bgp_packet_mpunreach_start(s, afi, safi);
|
||||
bgp_packet_mpunreach_prefix(
|
||||
s, &p, afi, safi, NULL, NULL, addpath_encode,
|
||||
s, &p, afi, safi, NULL, NULL, 0, addpath_encode,
|
||||
BGP_ADDPATH_TX_ID_FOR_DEFAULT_ORIGINATE, NULL);
|
||||
|
||||
/* Set the mp_unreach attr's length */
|
||||
|
@ -6126,8 +6126,10 @@ DEFUN_NOSH (address_family_ipv4_safi,
|
||||
VTY_DECLVAR_CONTEXT(bgp, bgp);
|
||||
safi_t safi = bgp_vty_safi_from_str(argv[2]->text);
|
||||
if (bgp->inst_type != BGP_INSTANCE_TYPE_DEFAULT &&
|
||||
safi != SAFI_UNICAST && safi != SAFI_MULTICAST) {
|
||||
vty_out(vty, "Only Unicast and Multicast SAFIs supported in non-core instances.\n");
|
||||
safi != SAFI_UNICAST && safi != SAFI_MULTICAST
|
||||
&& safi != SAFI_EVPN) {
|
||||
vty_out(vty,
|
||||
"Only Unicast/Multicast/EVPN SAFIs supported in non-core instances.\n");
|
||||
return CMD_WARNING_CONFIG_FAILED;
|
||||
}
|
||||
vty->node = bgp_node_type(AFI_IP, safi);
|
||||
@ -6148,8 +6150,10 @@ DEFUN_NOSH (address_family_ipv6_safi,
|
||||
VTY_DECLVAR_CONTEXT(bgp, bgp);
|
||||
safi_t safi = bgp_vty_safi_from_str(argv[2]->text);
|
||||
if (bgp->inst_type != BGP_INSTANCE_TYPE_DEFAULT &&
|
||||
safi != SAFI_UNICAST && safi != SAFI_MULTICAST) {
|
||||
vty_out(vty, "Only Unicast and Multicast SAFIs supported in non-core instances.\n");
|
||||
safi != SAFI_UNICAST && safi != SAFI_MULTICAST
|
||||
&& safi != SAFI_EVPN) {
|
||||
vty_out(vty,
|
||||
"Only Unicast/Multicast/EVPN SAFIs supported in non-core instances.\n");
|
||||
return CMD_WARNING_CONFIG_FAILED;
|
||||
}
|
||||
vty->node = bgp_node_type(AFI_IP6, safi);
|
||||
@ -6191,10 +6195,6 @@ DEFUN_NOSH (address_family_evpn,
|
||||
"Address Family modifier\n")
|
||||
{
|
||||
VTY_DECLVAR_CONTEXT(bgp, bgp);
|
||||
if (bgp->inst_type != BGP_INSTANCE_TYPE_DEFAULT) {
|
||||
vty_out(vty, "Only Unicast and Multicast SAFIs supported in non-core instances.\n");
|
||||
return CMD_WARNING_CONFIG_FAILED;
|
||||
}
|
||||
vty->node = BGP_EVPN_NODE;
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
@ -1142,10 +1142,11 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p,
|
||||
api_nh->type = NEXTHOP_TYPE_IPV6_IFINDEX;
|
||||
}
|
||||
|
||||
if (mpinfo->extra && bgp_is_valid_label(&mpinfo->extra->label)
|
||||
if (mpinfo->extra &&
|
||||
bgp_is_valid_label(&mpinfo->extra->label[0])
|
||||
&& !CHECK_FLAG(api.flags, ZEBRA_FLAG_EVPN_ROUTE)) {
|
||||
has_valid_label = 1;
|
||||
label = label_pton(&mpinfo->extra->label);
|
||||
label = label_pton(&mpinfo->extra->label[0]);
|
||||
|
||||
api_nh->label_num = 1;
|
||||
api_nh->labels[0] = label;
|
||||
@ -1634,6 +1635,29 @@ void 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_subnet(struct bgp *bgp, int advertise, vni_t vni)
|
||||
{
|
||||
struct stream *s = NULL;
|
||||
|
||||
/* 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_SUBNET, bgp->vrf_id);
|
||||
stream_putc(s, advertise);
|
||||
stream_put3(s, vni);
|
||||
stream_putw_at(s, 0, stream_get_endp(s));
|
||||
|
||||
return zclient_send_message(zclient);
|
||||
}
|
||||
|
||||
int bgp_zebra_advertise_gw_macip(struct bgp *bgp, int advertise, vni_t vni)
|
||||
{
|
||||
struct stream *s = NULL;
|
||||
@ -1820,6 +1844,55 @@ static int bgp_zebra_process_local_macip(int command, struct zclient *zclient,
|
||||
return bgp_evpn_local_macip_del(bgp, vni, &mac, &ip);
|
||||
}
|
||||
|
||||
static void bgp_zebra_process_local_ip_prefix(int cmd,
|
||||
struct zclient *zclient,
|
||||
zebra_size_t length,
|
||||
vrf_id_t vrf_id)
|
||||
{
|
||||
struct stream *s = NULL;
|
||||
struct bgp *bgp_vrf = NULL;
|
||||
struct prefix p;
|
||||
char buf[PREFIX_STRLEN];
|
||||
|
||||
memset(&p, 0, sizeof(struct prefix));
|
||||
s = zclient->ibuf;
|
||||
stream_get(&p, s, sizeof(struct prefix));
|
||||
|
||||
bgp_vrf = bgp_lookup_by_vrf_id(vrf_id);
|
||||
if (!bgp_vrf)
|
||||
return;
|
||||
|
||||
if (BGP_DEBUG(zebra, ZEBRA))
|
||||
zlog_debug("Recv prefix %s %s on vrf %s",
|
||||
prefix2str(&p, buf, sizeof(buf)),
|
||||
(cmd == ZEBRA_IP_PREFIX_ROUTE_ADD) ? "ADD" : "DEL",
|
||||
vrf_id_to_name(vrf_id));
|
||||
|
||||
if (cmd == ZEBRA_IP_PREFIX_ROUTE_ADD) {
|
||||
|
||||
if (p.family == AF_INET)
|
||||
return bgp_evpn_advertise_type5_route(bgp_vrf, &p,
|
||||
NULL,
|
||||
AFI_IP,
|
||||
SAFI_UNICAST);
|
||||
else
|
||||
return bgp_evpn_advertise_type5_route(bgp_vrf, &p,
|
||||
NULL,
|
||||
AFI_IP6,
|
||||
SAFI_UNICAST);
|
||||
|
||||
} else {
|
||||
if (p.family == AF_INET)
|
||||
return bgp_evpn_withdraw_type5_route(bgp_vrf, &p,
|
||||
AFI_IP,
|
||||
SAFI_UNICAST);
|
||||
else
|
||||
return bgp_evpn_withdraw_type5_route(bgp_vrf, &p,
|
||||
AFI_IP6,
|
||||
SAFI_UNICAST);
|
||||
}
|
||||
}
|
||||
|
||||
extern struct zebra_privs_t bgpd_privs;
|
||||
|
||||
void bgp_zebra_init(struct thread_master *master)
|
||||
@ -1852,6 +1925,8 @@ void bgp_zebra_init(struct thread_master *master)
|
||||
zclient->local_macip_del = bgp_zebra_process_local_macip;
|
||||
zclient->local_l3vni_add = bgp_zebra_process_local_l3vni;
|
||||
zclient->local_l3vni_del = bgp_zebra_process_local_l3vni;
|
||||
zclient->local_ip_prefix_add = bgp_zebra_process_local_ip_prefix;
|
||||
zclient->local_ip_prefix_del = bgp_zebra_process_local_ip_prefix;
|
||||
}
|
||||
|
||||
void bgp_zebra_destroy(void)
|
||||
|
@ -58,7 +58,8 @@ 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_subnet(struct bgp *bgp, int advertise,
|
||||
vni_t vni);
|
||||
extern int bgp_zebra_advertise_gw_macip(struct bgp *, int, vni_t);
|
||||
extern int bgp_zebra_advertise_all_vni(struct bgp *, int);
|
||||
|
||||
|
@ -1083,7 +1083,7 @@ void add_vnc_route(struct rfapi_descriptor *rfd, /* cookie, VPN UN addr, peer */
|
||||
/* save backref to rfapi handle */
|
||||
assert(bgp_info_extra_get(new));
|
||||
new->extra->vnc.export.rfapi_handle = (void *)rfd;
|
||||
encode_label(label_val, &new->extra->label);
|
||||
encode_label(label_val, &new->extra->label[0]);
|
||||
|
||||
/* debug */
|
||||
|
||||
|
@ -521,7 +521,7 @@ static struct bgp_info *rfapiBgpInfoCreate(struct attr *attr, struct peer *peer,
|
||||
rfapi_time(&new->extra->vnc.import.create_time);
|
||||
}
|
||||
if (label)
|
||||
encode_label(*label, &new->extra->label);
|
||||
encode_label(*label, &new->extra->label[0]);
|
||||
new->type = type;
|
||||
new->sub_type = sub_type;
|
||||
new->peer = peer;
|
||||
@ -1338,7 +1338,7 @@ rfapiRouteInfo2NextHopEntry(struct rfapi_ip_prefix *rprefix,
|
||||
vo->v.l2addr.local_nve_id = bi->extra->vnc.import.rd.val[1];
|
||||
|
||||
/* label comes from MP_REACH_NLRI label */
|
||||
vo->v.l2addr.label = decode_label(&bi->extra->label);
|
||||
vo->v.l2addr.label = decode_label(&bi->extra->label[0]);
|
||||
|
||||
new->vn_options = vo;
|
||||
|
||||
@ -4242,7 +4242,7 @@ static void rfapiBgpTableFilteredImport(struct bgp *bgp,
|
||||
|
||||
if (bi->extra)
|
||||
label = decode_label(
|
||||
&bi->extra->label);
|
||||
&bi->extra->label[0]);
|
||||
(*rfapiBgpInfoFilteredImportFunction(
|
||||
safi))(
|
||||
it, /* which import table */
|
||||
|
@ -697,7 +697,7 @@ static void rfapiRibBi2Ri(struct bgp_info *bi, struct rfapi_info *ri,
|
||||
vo->v.l2addr.local_nve_id = bi->extra->vnc.import.rd.val[1];
|
||||
|
||||
/* label comes from MP_REACH_NLRI label */
|
||||
vo->v.l2addr.label = decode_label(&bi->extra->label);
|
||||
vo->v.l2addr.label = decode_label(&bi->extra->label[0]);
|
||||
|
||||
rfapi_vn_options_free(
|
||||
ri->vn_options); /* maybe free old version */
|
||||
|
@ -432,7 +432,7 @@ void rfapi_vty_out_vncinfo(struct vty *vty, struct prefix *p,
|
||||
}
|
||||
|
||||
if (bi->extra != NULL)
|
||||
vty_out(vty, " label=%u", decode_label(&bi->extra->label));
|
||||
vty_out(vty, " label=%u", decode_label(&bi->extra->label[0]));
|
||||
|
||||
if (!rfapiGetVncLifetime(bi->attr, &lifetime)) {
|
||||
vty_out(vty, " life=%d", lifetime);
|
||||
@ -1068,7 +1068,7 @@ static int rfapiPrintRemoteRegBi(struct bgp *bgp, void *stream,
|
||||
inet_ntop(pfx_vn.family, &pfx_vn.u.prefix, buf_ntop,
|
||||
BUFSIZ));
|
||||
if (bi->extra) {
|
||||
u_int32_t l = decode_label(&bi->extra->label);
|
||||
u_int32_t l = decode_label(&bi->extra->label[0]);
|
||||
snprintf(buf_vn, BUFSIZ, "Label: %d", l);
|
||||
} else /* should never happen */
|
||||
{
|
||||
@ -1181,7 +1181,7 @@ static int rfapiPrintRemoteRegBi(struct bgp *bgp, void *stream,
|
||||
}
|
||||
}
|
||||
if (tun_type != BGP_ENCAP_TYPE_MPLS && bi->extra) {
|
||||
u_int32_t l = decode_label(&bi->extra->label);
|
||||
u_int32_t l = decode_label(&bi->extra->label[0]);
|
||||
if (!MPLS_LABEL_IS_NULL(l)) {
|
||||
fp(out, " Label: %d", l);
|
||||
if (nlines == 1)
|
||||
|
@ -317,7 +317,7 @@ void vnc_direct_bgp_add_route_ce(struct bgp *bgp, struct route_node *rn,
|
||||
iattr, /* bgp_update copies this attr */
|
||||
afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT,
|
||||
BGP_ROUTE_REDISTRIBUTE, NULL, /* RD not used for unicast */
|
||||
NULL, /* tag not used for unicast */
|
||||
NULL, 0, /* tag not used for unicast */
|
||||
0, NULL); /* EVPN not used */
|
||||
bgp_attr_unintern(&iattr);
|
||||
}
|
||||
@ -398,7 +398,7 @@ void vnc_direct_bgp_del_route_ce(struct bgp *bgp, struct route_node *rn,
|
||||
NULL, /* attr, ignored */
|
||||
afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT,
|
||||
BGP_ROUTE_REDISTRIBUTE, NULL, /* RD not used for unicast */
|
||||
NULL, NULL); /* tag not used for unicast */
|
||||
NULL, 0, NULL); /* tag not used for unicast */
|
||||
}
|
||||
|
||||
static void vnc_direct_bgp_vpn_enable_ce(struct bgp *bgp, afi_t afi)
|
||||
@ -498,7 +498,7 @@ static void vnc_direct_bgp_vpn_disable_ce(struct bgp *bgp, afi_t afi)
|
||||
ZEBRA_ROUTE_VNC_DIRECT,
|
||||
BGP_ROUTE_REDISTRIBUTE,
|
||||
NULL, /* RD not used for unicast */
|
||||
NULL,
|
||||
NULL, 0,
|
||||
NULL); /* tag not used for unicast */
|
||||
}
|
||||
}
|
||||
@ -880,7 +880,7 @@ void vnc_direct_bgp_del_prefix(struct bgp *bgp,
|
||||
afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT,
|
||||
BGP_ROUTE_REDISTRIBUTE,
|
||||
NULL, /* RD not used for unicast */
|
||||
NULL, NULL); /* tag not used for unicast */
|
||||
NULL, 0, NULL); /* tag not used for unicast */
|
||||
/*
|
||||
* yuck!
|
||||
* - but consistent with rest of function
|
||||
@ -909,7 +909,7 @@ void vnc_direct_bgp_del_prefix(struct bgp *bgp,
|
||||
afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT,
|
||||
BGP_ROUTE_REDISTRIBUTE,
|
||||
NULL, /* RD not used for unicast */
|
||||
NULL, NULL); /* tag not used for unicast */
|
||||
NULL, 0, NULL); /* tag not used for unicast */
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1048,7 +1048,7 @@ void vnc_direct_bgp_add_nve(struct bgp *bgp, struct rfapi_descriptor *rfd)
|
||||
unicast */
|
||||
NULL, /* tag not used for
|
||||
unicast */
|
||||
0, NULL); /* EVPN not used */
|
||||
0, 0, NULL); /* EVPN not used */
|
||||
|
||||
bgp_attr_unintern(&iattr);
|
||||
}
|
||||
@ -1142,7 +1142,7 @@ void vnc_direct_bgp_del_nve(struct bgp *bgp, struct rfapi_descriptor *rfd)
|
||||
BGP_ROUTE_REDISTRIBUTE,
|
||||
NULL, /* RD not used for
|
||||
unicast */
|
||||
NULL, NULL); /* tag not
|
||||
NULL, 0, NULL); /* tag not
|
||||
used for
|
||||
unicast */
|
||||
}
|
||||
@ -1260,7 +1260,7 @@ static void vnc_direct_add_rn_group_rd(struct bgp *bgp,
|
||||
BGP_ROUTE_REDISTRIBUTE,
|
||||
NULL, /* RD not used for unicast */
|
||||
NULL, /* tag not used for unicast */
|
||||
0, NULL); /* EVPN not used */
|
||||
0, 0, NULL); /* EVPN not used */
|
||||
|
||||
bgp_attr_unintern(&iattr);
|
||||
|
||||
@ -1374,7 +1374,7 @@ static void vnc_direct_del_rn_group_rd(struct bgp *bgp,
|
||||
ZEBRA_ROUTE_VNC_DIRECT,
|
||||
BGP_ROUTE_REDISTRIBUTE,
|
||||
NULL, /* RD not used for unicast */
|
||||
NULL,
|
||||
NULL, 0,
|
||||
NULL); /* tag not used for unicast */
|
||||
return;
|
||||
}
|
||||
@ -1496,7 +1496,7 @@ static void vnc_direct_bgp_unexport_table(afi_t afi, struct route_table *rt,
|
||||
BGP_ROUTE_REDISTRIBUTE,
|
||||
NULL, /* RD not used for
|
||||
unicast */
|
||||
NULL, NULL); /* tag not
|
||||
NULL, 0, NULL); /* tag not
|
||||
used for
|
||||
unicast,
|
||||
EVPN
|
||||
@ -1719,7 +1719,7 @@ void vnc_direct_bgp_rh_add_route(struct bgp *bgp, afi_t afi,
|
||||
afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT_RH,
|
||||
BGP_ROUTE_REDISTRIBUTE, NULL, /* RD not used for unicast */
|
||||
NULL, /* tag not used for unicast, EVPN neither */
|
||||
0, NULL); /* EVPN not used */
|
||||
0, 0, NULL); /* EVPN not used */
|
||||
bgp_attr_unintern(&iattr);
|
||||
}
|
||||
|
||||
@ -1734,7 +1734,7 @@ static int vncExportWithdrawTimer(struct thread *t)
|
||||
NULL, /* attr, ignored */
|
||||
family2afi(eti->node->p.family), SAFI_UNICAST, eti->type,
|
||||
eti->subtype, NULL, /* RD not used for unicast */
|
||||
NULL, NULL); /* tag not used for unicast, EVPN neither */
|
||||
NULL, 0, NULL); /* tag not used for unicast, EVPN neither */
|
||||
|
||||
/*
|
||||
* Free the eti
|
||||
@ -1965,7 +1965,7 @@ void vnc_direct_bgp_rh_vpn_enable(struct bgp *bgp, afi_t afi)
|
||||
NULL, /* tag not used for
|
||||
unicast, EVPN
|
||||
neither */
|
||||
0, NULL); /* EVPN not used */
|
||||
0, 0, NULL); /* EVPN not used */
|
||||
bgp_attr_unintern(&iattr);
|
||||
}
|
||||
}
|
||||
@ -2026,7 +2026,7 @@ void vnc_direct_bgp_rh_vpn_disable(struct bgp *bgp, afi_t afi)
|
||||
ZEBRA_ROUTE_VNC_DIRECT_RH,
|
||||
BGP_ROUTE_REDISTRIBUTE,
|
||||
NULL, /* RD not used for unicast */
|
||||
NULL, NULL); /* tag not used for
|
||||
NULL, 0, NULL); /* tag not used for
|
||||
unicast, EVPN
|
||||
neither */
|
||||
}
|
||||
|
@ -495,7 +495,7 @@ static void vnc_import_bgp_add_route_mode_resolve_nve_one_bi(
|
||||
ecommunity_merge(new_ecom, bi->attr->ecommunity);
|
||||
|
||||
if (bi->extra)
|
||||
label = decode_label(&bi->extra->label);
|
||||
label = decode_label(&bi->extra->label[0]);
|
||||
|
||||
add_vnc_route(&vncHDResolveNve, bgp, SAFI_MPLS_VPN,
|
||||
prefix, /* unicast route prefix */
|
||||
@ -1783,7 +1783,7 @@ static void vnc_import_bgp_exterior_add_route_it(
|
||||
prd = &bi_interior->extra->vnc.import
|
||||
.rd;
|
||||
label = decode_label(
|
||||
&bi_interior->extra->label);
|
||||
&bi_interior->extra->label[0]);
|
||||
} else
|
||||
prd = NULL;
|
||||
|
||||
@ -1958,7 +1958,7 @@ void vnc_import_bgp_exterior_del_route(
|
||||
prd = &bi_interior->extra->vnc.import
|
||||
.rd;
|
||||
label = decode_label(
|
||||
&bi_interior->extra->label);
|
||||
&bi_interior->extra->label[0]);
|
||||
} else
|
||||
prd = NULL;
|
||||
|
||||
@ -2113,7 +2113,7 @@ void vnc_import_bgp_exterior_add_route_interior(
|
||||
if (bi_interior->extra) {
|
||||
prd = &bi_interior->extra->vnc.import.rd;
|
||||
label = decode_label(
|
||||
&bi_interior->extra->label);
|
||||
&bi_interior->extra->label[0]);
|
||||
} else
|
||||
prd = NULL;
|
||||
|
||||
@ -2226,7 +2226,7 @@ void vnc_import_bgp_exterior_add_route_interior(
|
||||
if (bi->extra) {
|
||||
prd = &bi->extra->vnc.import.rd;
|
||||
label = decode_label(
|
||||
&bi->extra->label);
|
||||
&bi->extra->label[0]);
|
||||
} else
|
||||
prd = NULL;
|
||||
|
||||
@ -2248,7 +2248,7 @@ void vnc_import_bgp_exterior_add_route_interior(
|
||||
prd = &bi_interior->extra->vnc.import
|
||||
.rd;
|
||||
label = decode_label(
|
||||
&bi_interior->extra->label);
|
||||
&bi_interior->extra->label[0]);
|
||||
} else
|
||||
prd = NULL;
|
||||
|
||||
@ -2369,7 +2369,7 @@ void vnc_import_bgp_exterior_add_route_interior(
|
||||
if (bi_interior->extra) {
|
||||
prd = &bi_interior->extra->vnc.import.rd;
|
||||
label = decode_label(
|
||||
&bi_interior->extra->label);
|
||||
&bi_interior->extra->label[0]);
|
||||
} else
|
||||
prd = NULL;
|
||||
|
||||
@ -2480,7 +2480,7 @@ void vnc_import_bgp_exterior_del_route_interior(
|
||||
|
||||
if (bi_interior->extra) {
|
||||
prd = &bi_interior->extra->vnc.import.rd;
|
||||
label = decode_label(&bi_interior->extra->label);
|
||||
label = decode_label(&bi_interior->extra->label[0]);
|
||||
} else
|
||||
prd = NULL;
|
||||
|
||||
@ -2556,7 +2556,8 @@ void vnc_import_bgp_exterior_del_route_interior(
|
||||
|
||||
if (bi->extra) {
|
||||
prd = &bi->extra->vnc.import.rd;
|
||||
label = decode_label(&bi->extra->label);
|
||||
label = decode_label(
|
||||
&bi->extra->label[0]);
|
||||
} else
|
||||
prd = NULL;
|
||||
|
||||
|
@ -943,6 +943,7 @@ static const struct zebra_desc_table command_types[] = {
|
||||
DESC_ENTRY(ZEBRA_RELEASE_LABEL_CHUNK),
|
||||
DESC_ENTRY(ZEBRA_ADVERTISE_ALL_VNI),
|
||||
DESC_ENTRY(ZEBRA_ADVERTISE_DEFAULT_GW),
|
||||
DESC_ENTRY(ZEBRA_ADVERTISE_SUBNET),
|
||||
DESC_ENTRY(ZEBRA_VNI_ADD),
|
||||
DESC_ENTRY(ZEBRA_VNI_DEL),
|
||||
DESC_ENTRY(ZEBRA_L3VNI_ADD),
|
||||
@ -951,6 +952,8 @@ static const struct zebra_desc_table command_types[] = {
|
||||
DESC_ENTRY(ZEBRA_REMOTE_VTEP_DEL),
|
||||
DESC_ENTRY(ZEBRA_MACIP_ADD),
|
||||
DESC_ENTRY(ZEBRA_MACIP_DEL),
|
||||
DESC_ENTRY(ZEBRA_IP_PREFIX_ROUTE_ADD),
|
||||
DESC_ENTRY(ZEBRA_IP_PREFIX_ROUTE_DEL),
|
||||
DESC_ENTRY(ZEBRA_REMOTE_MACIP_ADD),
|
||||
DESC_ENTRY(ZEBRA_REMOTE_MACIP_DEL),
|
||||
DESC_ENTRY(ZEBRA_PW_ADD),
|
||||
|
41
lib/vrf.c
41
lib/vrf.c
@ -141,7 +141,9 @@ struct vrf *vrf_get(vrf_id_t vrf_id, const char *name)
|
||||
return vrf;
|
||||
}
|
||||
|
||||
/* Delete a VRF. This is called in vrf_terminate(). */
|
||||
/* Delete a VRF. This is called when the underlying VRF goes away, a
|
||||
* pre-configured VRF is deleted or when shutting down (vrf_terminate()).
|
||||
*/
|
||||
void vrf_delete(struct vrf *vrf)
|
||||
{
|
||||
if (debug_vrf)
|
||||
@ -150,6 +152,23 @@ void vrf_delete(struct vrf *vrf)
|
||||
if (vrf_is_enabled(vrf))
|
||||
vrf_disable(vrf);
|
||||
|
||||
/* If the VRF is user configured, it'll stick around, just remove
|
||||
* the ID mapping. Interfaces assigned to this VRF should've been
|
||||
* removed already as part of the VRF going down.
|
||||
*/
|
||||
if (vrf_is_user_cfged(vrf)) {
|
||||
if (vrf->vrf_id != VRF_UNKNOWN) {
|
||||
/* Delete any VRF interfaces - should be only
|
||||
* the VRF itself, other interfaces should've
|
||||
* been moved out of the VRF.
|
||||
*/
|
||||
if_terminate(vrf);
|
||||
RB_REMOVE(vrf_id_head, &vrfs_by_id, vrf);
|
||||
vrf->vrf_id = VRF_UNKNOWN;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (vrf_master.vrf_delete_hook)
|
||||
(*vrf_master.vrf_delete_hook)(vrf);
|
||||
|
||||
@ -172,14 +191,6 @@ struct vrf *vrf_lookup_by_id(vrf_id_t vrf_id)
|
||||
return (RB_FIND(vrf_id_head, &vrfs_by_id, &vrf));
|
||||
}
|
||||
|
||||
/*
|
||||
* Check whether the VRF is enabled.
|
||||
*/
|
||||
static int vrf_is_enabled(struct vrf *vrf)
|
||||
{
|
||||
return vrf && CHECK_FLAG(vrf->status, VRF_ACTIVE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Enable a VRF - that is, let the VRF be ready to use.
|
||||
* The VRF_ENABLE_HOOK callback will be called to inform
|
||||
@ -408,10 +419,16 @@ void vrf_terminate(void)
|
||||
zlog_debug("%s: Shutting down vrf subsystem",
|
||||
__PRETTY_FUNCTION__);
|
||||
|
||||
while ((vrf = RB_ROOT(vrf_id_head, &vrfs_by_id)) != NULL)
|
||||
while ((vrf = RB_ROOT(vrf_id_head, &vrfs_by_id)) != NULL) {
|
||||
/* Clear configured flag and invoke delete. */
|
||||
UNSET_FLAG(vrf->status, VRF_CONFIGURED);
|
||||
vrf_delete(vrf);
|
||||
while ((vrf = RB_ROOT(vrf_name_head, &vrfs_by_name)) != NULL)
|
||||
}
|
||||
while ((vrf = RB_ROOT(vrf_name_head, &vrfs_by_name)) != NULL) {
|
||||
/* Clear configured flag and invoke delete. */
|
||||
UNSET_FLAG(vrf->status, VRF_CONFIGURED);
|
||||
vrf_delete(vrf);
|
||||
}
|
||||
}
|
||||
|
||||
/* Create a socket for the VRF. */
|
||||
@ -473,6 +490,8 @@ DEFUN_NOSH (no_vrf,
|
||||
return CMD_WARNING_CONFIG_FAILED;
|
||||
}
|
||||
|
||||
/* Clear configured flag and invoke delete. */
|
||||
UNSET_FLAG(vrfp->status, VRF_CONFIGURED);
|
||||
vrf_delete(vrfp);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
|
29
lib/vrf.h
29
lib/vrf.h
@ -75,7 +75,8 @@ struct vrf {
|
||||
|
||||
/* Zebra internal VRF status */
|
||||
u_char status;
|
||||
#define VRF_ACTIVE (1 << 0)
|
||||
#define VRF_ACTIVE (1 << 0) /* VRF is up in kernel */
|
||||
#define VRF_CONFIGURED (1 << 1) /* VRF has some FRR configuration */
|
||||
|
||||
/* Interfaces belonging to this VRF */
|
||||
struct if_name_head ifaces_by_name;
|
||||
@ -119,6 +120,32 @@ extern vrf_id_t vrf_name_to_id(const char *);
|
||||
(V) = vrf->vrf_id; \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Check whether the VRF is enabled.
|
||||
*/
|
||||
static inline int vrf_is_enabled(struct vrf *vrf)
|
||||
{
|
||||
return vrf && CHECK_FLAG(vrf->status, VRF_ACTIVE);
|
||||
}
|
||||
|
||||
/* check if the vrf is user configured */
|
||||
static inline int vrf_is_user_cfged(struct vrf *vrf)
|
||||
{
|
||||
return vrf && CHECK_FLAG(vrf->status, VRF_CONFIGURED);
|
||||
}
|
||||
|
||||
/* Mark that VRF has user configuration */
|
||||
static inline void vrf_set_user_cfged(struct vrf *vrf)
|
||||
{
|
||||
SET_FLAG(vrf->status, VRF_CONFIGURED);
|
||||
}
|
||||
|
||||
/* Mark that VRF no longer has any user configuration */
|
||||
static inline void vrf_reset_user_cfged(struct vrf *vrf)
|
||||
{
|
||||
UNSET_FLAG(vrf->status, VRF_CONFIGURED);
|
||||
}
|
||||
|
||||
/*
|
||||
* Utilities to obtain the user data
|
||||
*/
|
||||
|
@ -2333,6 +2333,16 @@ static int zclient_read(struct thread *thread)
|
||||
(*zclient->local_macip_del)(command, zclient, length,
|
||||
vrf_id);
|
||||
break;
|
||||
case ZEBRA_IP_PREFIX_ROUTE_ADD:
|
||||
if (zclient->local_ip_prefix_add)
|
||||
(*zclient->local_ip_prefix_add)(command, zclient,
|
||||
length, vrf_id);
|
||||
break;
|
||||
case ZEBRA_IP_PREFIX_ROUTE_DEL:
|
||||
if (zclient->local_ip_prefix_del)
|
||||
(*zclient->local_ip_prefix_del)(command, zclient,
|
||||
length, vrf_id);
|
||||
break;
|
||||
case ZEBRA_PW_STATUS_UPDATE:
|
||||
if (zclient->pw_status_update)
|
||||
(*zclient->pw_status_update)(command, zclient, length,
|
||||
|
@ -109,6 +109,7 @@ typedef enum {
|
||||
ZEBRA_FEC_UNREGISTER,
|
||||
ZEBRA_FEC_UPDATE,
|
||||
ZEBRA_ADVERTISE_DEFAULT_GW,
|
||||
ZEBRA_ADVERTISE_SUBNET,
|
||||
ZEBRA_ADVERTISE_ALL_VNI,
|
||||
ZEBRA_VNI_ADD,
|
||||
ZEBRA_VNI_DEL,
|
||||
@ -118,6 +119,8 @@ typedef enum {
|
||||
ZEBRA_REMOTE_VTEP_DEL,
|
||||
ZEBRA_MACIP_ADD,
|
||||
ZEBRA_MACIP_DEL,
|
||||
ZEBRA_IP_PREFIX_ROUTE_ADD,
|
||||
ZEBRA_IP_PREFIX_ROUTE_DEL,
|
||||
ZEBRA_REMOTE_MACIP_ADD,
|
||||
ZEBRA_REMOTE_MACIP_DEL,
|
||||
ZEBRA_PW_ADD,
|
||||
@ -204,6 +207,8 @@ struct zclient {
|
||||
int (*local_vni_del)(int, struct zclient *, uint16_t, vrf_id_t);
|
||||
int (*local_l3vni_add)(int, struct zclient *, uint16_t, vrf_id_t);
|
||||
int (*local_l3vni_del)(int, struct zclient *, uint16_t, vrf_id_t);
|
||||
void (*local_ip_prefix_add)(int, struct zclient *, uint16_t, vrf_id_t);
|
||||
void (*local_ip_prefix_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);
|
||||
int (*pw_status_update)(int, struct zclient *, uint16_t, vrf_id_t);
|
||||
@ -343,8 +348,8 @@ enum zapi_route_notify_owner {
|
||||
};
|
||||
|
||||
/* Zebra MAC types */
|
||||
#define ZEBRA_MAC_TYPE_STICKY 0x01 /* Sticky MAC*/
|
||||
#define ZEBRA_MAC_TYPE_GW 0x02 /* gateway (SVI) mac*/
|
||||
#define ZEBRA_MACIP_TYPE_STICKY 0x01 /* Sticky MAC*/
|
||||
#define ZEBRA_MACIP_TYPE_GW 0x02 /* gateway (SVI) mac*/
|
||||
|
||||
struct zclient_options {
|
||||
bool receive_notify;
|
||||
|
@ -352,13 +352,15 @@ void vtysh_config_dump(FILE *fp)
|
||||
for (i = 0; i < vector_active(configvec); i++)
|
||||
if ((master = vector_slot(configvec, i)) != NULL) {
|
||||
for (ALL_LIST_ELEMENTS(master, node, nnode, config)) {
|
||||
/* Don't print empty sections for interface/vrf.
|
||||
/* Don't print empty sections for interface.
|
||||
* Route maps on the
|
||||
* other hand could have a legitimate empty
|
||||
* section at the end.
|
||||
* VRF is handled in the backend, we could have
|
||||
* "configured" VRFs with static routes which
|
||||
* are not under the VRF node.
|
||||
*/
|
||||
if ((config->index == INTERFACE_NODE
|
||||
|| config->index == VRF_NODE)
|
||||
if (config->index == INTERFACE_NODE
|
||||
&& list_isempty(config->line))
|
||||
continue;
|
||||
|
||||
|
@ -2875,6 +2875,16 @@ int zebra_mpls_write_label_block_config(struct vty *vty, struct zebra_vrf *zvrf)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Called when VRF becomes inactive, cleans up information but keeps
|
||||
* the table itself.
|
||||
* NOTE: Currently supported only for default VRF.
|
||||
*/
|
||||
void zebra_mpls_cleanup_tables(struct zebra_vrf *zvrf)
|
||||
{
|
||||
hash_iterate(zvrf->lsp_table, lsp_uninstall_from_kernel, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Called upon process exiting, need to delete LSP forwarding
|
||||
* entries from the kernel.
|
||||
|
@ -384,6 +384,13 @@ void zebra_mpls_print_lsp_table(struct vty *vty, struct zebra_vrf *zvrf,
|
||||
*/
|
||||
int zebra_mpls_write_lsp_config(struct vty *vty, struct zebra_vrf *zvrf);
|
||||
|
||||
/*
|
||||
* Called when VRF becomes inactive, cleans up information but keeps
|
||||
* the table itself.
|
||||
* NOTE: Currently supported only for default VRF.
|
||||
*/
|
||||
void zebra_mpls_cleanup_tables(struct zebra_vrf *zvrf);
|
||||
|
||||
/*
|
||||
* Called upon process exiting, need to delete LSP forwarding
|
||||
* entries from the kernel.
|
||||
|
@ -41,6 +41,7 @@ struct zebra_ns *zebra_ns_lookup(ns_id_t ns_id)
|
||||
return dzns;
|
||||
}
|
||||
|
||||
/* Do global enable actions - open sockets, read kernel config etc. */
|
||||
int zebra_ns_enable(ns_id_t ns_id, void **info)
|
||||
{
|
||||
struct zebra_ns *zns = (struct zebra_ns *)(*info);
|
||||
@ -49,8 +50,6 @@ int zebra_ns_enable(ns_id_t ns_id, void **info)
|
||||
rtadv_init(zns);
|
||||
#endif
|
||||
|
||||
zns->if_table = route_table_init();
|
||||
zebra_vxlan_ns_init(zns);
|
||||
kernel_init(zns);
|
||||
interface_list(zns);
|
||||
route_read(zns);
|
||||
@ -79,8 +78,14 @@ int zebra_ns_init(void)
|
||||
|
||||
ns_init();
|
||||
|
||||
/* Do any needed per-NS data structure allocation. */
|
||||
dzns->if_table = route_table_init();
|
||||
zebra_vxlan_ns_init(dzns);
|
||||
|
||||
/* Register zebra VRF callbacks, create and activate default VRF. */
|
||||
zebra_vrf_init();
|
||||
|
||||
/* Default NS is activated */
|
||||
zebra_ns_enable(NS_DEFAULT, (void **)&dzns);
|
||||
|
||||
return 0;
|
||||
|
@ -41,6 +41,11 @@
|
||||
|
||||
extern struct zebra_t zebrad;
|
||||
|
||||
static void zebra_vrf_table_create(struct zebra_vrf *zvrf, afi_t afi,
|
||||
safi_t safi);
|
||||
static void zebra_rnhtable_node_cleanup(struct route_table *table,
|
||||
struct route_node *node);
|
||||
|
||||
/* VRF information update. */
|
||||
static void zebra_vrf_add_update(struct zebra_vrf *zvrf)
|
||||
{
|
||||
@ -82,7 +87,7 @@ static int zebra_vrf_new(struct vrf *vrf)
|
||||
struct zebra_vrf *zvrf;
|
||||
|
||||
if (IS_ZEBRA_DEBUG_EVENT)
|
||||
zlog_info("ZVRF %s with id %u", vrf->name, vrf->vrf_id);
|
||||
zlog_info("VRF %s created, id %u", vrf->name, vrf->vrf_id);
|
||||
|
||||
zvrf = zebra_vrf_alloc();
|
||||
zvrf->zns = zebra_ns_lookup(
|
||||
@ -101,14 +106,36 @@ static int zebra_vrf_enable(struct vrf *vrf)
|
||||
struct route_table *stable;
|
||||
struct route_node *rn;
|
||||
struct static_route *si;
|
||||
struct route_table *table;
|
||||
struct interface *ifp;
|
||||
afi_t afi;
|
||||
safi_t safi;
|
||||
|
||||
assert(zvrf);
|
||||
if (IS_ZEBRA_DEBUG_EVENT)
|
||||
zlog_debug("VRF %s id %u is now active",
|
||||
zvrf_name(zvrf), zvrf_id(zvrf));
|
||||
|
||||
/* Inform clients that the VRF is now active. This is an
|
||||
* add for the clients.
|
||||
*/
|
||||
zebra_vrf_add_update(zvrf);
|
||||
|
||||
/* Allocate tables */
|
||||
for (afi = AFI_IP; afi <= AFI_IP6; afi++) {
|
||||
for (safi = SAFI_UNICAST; safi <= SAFI_MULTICAST; safi++)
|
||||
zebra_vrf_table_create(zvrf, afi, safi);
|
||||
|
||||
table = route_table_init();
|
||||
table->cleanup = zebra_rnhtable_node_cleanup;
|
||||
zvrf->rnh_table[afi] = table;
|
||||
|
||||
table = route_table_init();
|
||||
table->cleanup = zebra_rnhtable_node_cleanup;
|
||||
zvrf->import_check_table[afi] = table;
|
||||
}
|
||||
|
||||
/* Install any static routes configured for this VRF. */
|
||||
for (afi = AFI_IP; afi < AFI_MAX; afi++)
|
||||
for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) {
|
||||
stable = zvrf->stable[afi][safi];
|
||||
@ -132,6 +159,9 @@ static int zebra_vrf_enable(struct vrf *vrf)
|
||||
}
|
||||
}
|
||||
|
||||
/* Kick off any VxLAN-EVPN processing. */
|
||||
zebra_vxlan_vrf_enable(zvrf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -142,13 +172,19 @@ static int zebra_vrf_disable(struct vrf *vrf)
|
||||
struct route_table *stable;
|
||||
struct route_node *rn;
|
||||
struct static_route *si;
|
||||
struct route_table *table;
|
||||
struct interface *ifp;
|
||||
u_int32_t table_id;
|
||||
afi_t afi;
|
||||
safi_t safi;
|
||||
unsigned i;
|
||||
|
||||
if (IS_ZEBRA_DEBUG_KERNEL)
|
||||
zlog_debug("VRF %s id %u is now disabled.", zvrf_name(zvrf),
|
||||
zvrf_id(zvrf));
|
||||
assert(zvrf);
|
||||
if (IS_ZEBRA_DEBUG_EVENT)
|
||||
zlog_debug("VRF %s id %u is now inactive",
|
||||
zvrf_name(zvrf), zvrf_id(zvrf));
|
||||
|
||||
/* Uninstall any static routes configured for this VRF. */
|
||||
for (afi = AFI_IP; afi < AFI_MAX; afi++)
|
||||
for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) {
|
||||
stable = zvrf->stable[afi][safi];
|
||||
@ -161,6 +197,84 @@ static int zebra_vrf_disable(struct vrf *vrf)
|
||||
afi, safi, &rn->p, NULL, si);
|
||||
}
|
||||
|
||||
/* Stop any VxLAN-EVPN processing. */
|
||||
zebra_vxlan_vrf_disable(zvrf);
|
||||
|
||||
/* Inform clients that the VRF is now inactive. This is a
|
||||
* delete for the clients.
|
||||
*/
|
||||
zebra_vrf_delete_update(zvrf);
|
||||
|
||||
/* If asked to retain routes, there's nothing more to do. */
|
||||
if (CHECK_FLAG(zvrf->flags, ZEBRA_VRF_RETAIN))
|
||||
return 0;
|
||||
|
||||
/* Remove all routes. */
|
||||
for (afi = AFI_IP; afi <= AFI_IP6; afi++) {
|
||||
for (safi = SAFI_UNICAST; safi <= SAFI_MULTICAST; safi++)
|
||||
rib_close_table(zvrf->table[afi][safi]);
|
||||
|
||||
if (vrf->vrf_id == VRF_DEFAULT)
|
||||
for (table_id = 0; table_id < ZEBRA_KERNEL_TABLE_MAX;
|
||||
table_id++)
|
||||
if (zvrf->other_table[afi][table_id])
|
||||
rib_close_table(zvrf->other_table[afi][table_id]);
|
||||
}
|
||||
|
||||
/* Cleanup Vxlan, MPLS and PW tables. */
|
||||
zebra_vxlan_cleanup_tables(zvrf);
|
||||
zebra_mpls_cleanup_tables(zvrf);
|
||||
zebra_pw_exit(zvrf);
|
||||
|
||||
/* Remove link-local IPv4 addresses created for BGP unnumbered peering. */
|
||||
FOR_ALL_INTERFACES (vrf, ifp)
|
||||
if_nbr_ipv6ll_to_ipv4ll_neigh_del_all(ifp);
|
||||
|
||||
/* clean-up work queues */
|
||||
for (i = 0; i < MQ_SIZE; i++) {
|
||||
struct listnode *lnode, *nnode;
|
||||
struct route_node *rnode;
|
||||
rib_dest_t *dest;
|
||||
|
||||
for (ALL_LIST_ELEMENTS(zebrad.mq->subq[i], lnode, nnode, rnode)) {
|
||||
dest = rib_dest_from_rnode(rnode);
|
||||
if (dest && rib_dest_vrf(dest) == zvrf) {
|
||||
route_unlock_node(rnode);
|
||||
list_delete_node(zebrad.mq->subq[i], lnode);
|
||||
zebrad.mq->size--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Cleanup (free) routing tables and NHT tables. */
|
||||
for (afi = AFI_IP; afi <= AFI_IP6; afi++) {
|
||||
void *table_info;
|
||||
|
||||
for (safi = SAFI_UNICAST; safi <= SAFI_MULTICAST; safi++) {
|
||||
table = zvrf->table[afi][safi];
|
||||
table_info = table->info;
|
||||
route_table_finish(table);
|
||||
XFREE(MTYPE_RIB_TABLE_INFO, table_info);
|
||||
zvrf->table[afi][safi] = NULL;
|
||||
}
|
||||
|
||||
if (vrf->vrf_id == VRF_DEFAULT)
|
||||
for (table_id = 0; table_id < ZEBRA_KERNEL_TABLE_MAX;
|
||||
table_id++)
|
||||
if (zvrf->other_table[afi][table_id]) {
|
||||
table = zvrf->other_table[afi][table_id];
|
||||
table_info = table->info;
|
||||
route_table_finish(table);
|
||||
XFREE(MTYPE_RIB_TABLE_INFO, table_info);
|
||||
zvrf->other_table[afi][table_id] = NULL;
|
||||
}
|
||||
|
||||
route_table_finish(zvrf->rnh_table[afi]);
|
||||
zvrf->rnh_table[afi] = NULL;
|
||||
route_table_finish(zvrf->import_check_table[afi]);
|
||||
zvrf->import_check_table[afi] = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -174,38 +288,9 @@ static int zebra_vrf_delete(struct vrf *vrf)
|
||||
unsigned i;
|
||||
|
||||
assert(zvrf);
|
||||
|
||||
zebra_vrf_delete_update(zvrf);
|
||||
|
||||
/* uninstall everything */
|
||||
if (!CHECK_FLAG(zvrf->flags, ZEBRA_VRF_RETAIN)) {
|
||||
struct interface *ifp;
|
||||
|
||||
for (afi = AFI_IP; afi <= AFI_IP6; afi++) {
|
||||
for (safi = SAFI_UNICAST; safi <= SAFI_MULTICAST;
|
||||
safi++)
|
||||
rib_close_table(zvrf->table[afi][safi]);
|
||||
|
||||
if (vrf->vrf_id == VRF_DEFAULT)
|
||||
for (table_id = 0;
|
||||
table_id < ZEBRA_KERNEL_TABLE_MAX;
|
||||
table_id++)
|
||||
if (zvrf->other_table[afi][table_id])
|
||||
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);
|
||||
zebra_pw_exit(zvrf);
|
||||
|
||||
FOR_ALL_INTERFACES (vrf, ifp)
|
||||
if_nbr_ipv6ll_to_ipv4ll_neigh_del_all(ifp);
|
||||
}
|
||||
if (IS_ZEBRA_DEBUG_EVENT)
|
||||
zlog_debug("VRF %s id %u deleted",
|
||||
zvrf_name(zvrf), zvrf_id(zvrf));
|
||||
|
||||
/* clean-up work queues */
|
||||
for (i = 0; i < MQ_SIZE; i++) {
|
||||
@ -213,8 +298,7 @@ static int zebra_vrf_delete(struct vrf *vrf)
|
||||
struct route_node *rnode;
|
||||
rib_dest_t *dest;
|
||||
|
||||
for (ALL_LIST_ELEMENTS(zebrad.mq->subq[i], lnode, nnode,
|
||||
rnode)) {
|
||||
for (ALL_LIST_ELEMENTS(zebrad.mq->subq[i], lnode, nnode, rnode)) {
|
||||
dest = rib_dest_from_rnode(rnode);
|
||||
if (dest && rib_dest_vrf(dest) == zvrf) {
|
||||
route_unlock_node(rnode);
|
||||
@ -224,22 +308,27 @@ static int zebra_vrf_delete(struct vrf *vrf)
|
||||
}
|
||||
}
|
||||
|
||||
/* Free Vxlan and MPLS. */
|
||||
zebra_vxlan_close_tables(zvrf);
|
||||
zebra_mpls_close_tables(zvrf);
|
||||
|
||||
/* release allocated memory */
|
||||
for (afi = AFI_IP; afi <= AFI_IP6; afi++) {
|
||||
void *table_info;
|
||||
|
||||
for (safi = SAFI_UNICAST; safi <= SAFI_MULTICAST; safi++) {
|
||||
table = zvrf->table[afi][safi];
|
||||
table_info = table->info;
|
||||
route_table_finish(table);
|
||||
XFREE(MTYPE_RIB_TABLE_INFO, table_info);
|
||||
if (table) {
|
||||
table_info = table->info;
|
||||
route_table_finish(table);
|
||||
XFREE(MTYPE_RIB_TABLE_INFO, table_info);
|
||||
}
|
||||
|
||||
table = zvrf->stable[afi][safi];
|
||||
route_table_finish(table);
|
||||
}
|
||||
|
||||
for (table_id = 0; table_id < ZEBRA_KERNEL_TABLE_MAX;
|
||||
table_id++)
|
||||
for (table_id = 0; table_id < ZEBRA_KERNEL_TABLE_MAX; table_id++)
|
||||
if (zvrf->other_table[afi][table_id]) {
|
||||
table = zvrf->other_table[afi][table_id];
|
||||
table_info = table->info;
|
||||
@ -251,7 +340,7 @@ static int zebra_vrf_delete(struct vrf *vrf)
|
||||
route_table_finish(zvrf->import_check_table[afi]);
|
||||
}
|
||||
|
||||
/* cleanup evpn states for vrf */
|
||||
/* Cleanup EVPN states for vrf */
|
||||
zebra_vxlan_vrf_delete(zvrf);
|
||||
|
||||
list_delete_all_node(zvrf->rid_all_sorted_list);
|
||||
@ -262,6 +351,37 @@ static int zebra_vrf_delete(struct vrf *vrf)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Return if this VRF has any FRR configuration or not.
|
||||
* IMPORTANT: This function needs to be updated when additional configuration
|
||||
* is added for a VRF.
|
||||
*/
|
||||
int zebra_vrf_has_config(struct zebra_vrf *zvrf)
|
||||
{
|
||||
afi_t afi;
|
||||
safi_t safi;
|
||||
struct route_table *stable;
|
||||
|
||||
/* NOTE: This is a don't care for the default VRF, but we go through
|
||||
* the motions to keep things consistent.
|
||||
*/
|
||||
/* Any static routes? */
|
||||
for (afi = AFI_IP; afi < AFI_MAX; afi++) {
|
||||
for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) {
|
||||
stable = zvrf->stable[afi][safi];
|
||||
if (!stable)
|
||||
continue;
|
||||
if (route_table_count(stable))
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* EVPN L3-VNI? */
|
||||
if (zvrf->l3vni)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Lookup the routing table in a VRF based on both VRF-Id and table-id.
|
||||
* NOTE: Table-id is relevant only in the Default VRF.
|
||||
*/
|
||||
@ -354,9 +474,9 @@ struct zebra_vrf *zebra_vrf_alloc(void)
|
||||
|
||||
zvrf = XCALLOC(MTYPE_ZEBRA_VRF, sizeof(struct zebra_vrf));
|
||||
|
||||
/* Allocate table for static route configuration. */
|
||||
for (afi = AFI_IP; afi <= AFI_IP6; afi++) {
|
||||
for (safi = SAFI_UNICAST; safi <= SAFI_MULTICAST; safi++) {
|
||||
zebra_vrf_table_create(zvrf, afi, safi);
|
||||
if (afi == AFI_IP6)
|
||||
table = srcdest_table_init();
|
||||
else
|
||||
@ -364,14 +484,6 @@ struct zebra_vrf *zebra_vrf_alloc(void)
|
||||
table->cleanup = zebra_stable_node_cleanup;
|
||||
zvrf->stable[afi][safi] = table;
|
||||
}
|
||||
|
||||
table = route_table_init();
|
||||
table->cleanup = zebra_rnhtable_node_cleanup;
|
||||
zvrf->rnh_table[afi] = table;
|
||||
|
||||
table = route_table_init();
|
||||
table->cleanup = zebra_rnhtable_node_cleanup;
|
||||
zvrf->import_check_table[afi] = table;
|
||||
}
|
||||
|
||||
zebra_vxlan_init_tables(zvrf);
|
||||
@ -477,16 +589,23 @@ static int vrf_config_write(struct vty *vty)
|
||||
if (!zvrf)
|
||||
continue;
|
||||
|
||||
if (vrf->vrf_id != VRF_DEFAULT)
|
||||
if (zvrf_id(zvrf) == VRF_DEFAULT) {
|
||||
if (zvrf->l3vni)
|
||||
vty_out(vty, "vni %u\n", zvrf->l3vni);
|
||||
vty_out(vty, "!\n");
|
||||
}
|
||||
|
||||
if (vrf_is_user_cfged(vrf)) {
|
||||
vty_out(vty, "vrf %s\n", zvrf_name(zvrf));
|
||||
if (zvrf->l3vni)
|
||||
vty_out(vty, " vni %u\n", zvrf->l3vni);
|
||||
vty_out(vty, "!\n");
|
||||
}
|
||||
|
||||
static_config(vty, zvrf, AFI_IP, SAFI_UNICAST, "ip route");
|
||||
static_config(vty, zvrf, AFI_IP, SAFI_MULTICAST, "ip mroute");
|
||||
static_config(vty, zvrf, AFI_IP6, SAFI_UNICAST, "ipv6 route");
|
||||
|
||||
if (vrf->vrf_id != VRF_DEFAULT && zvrf->l3vni)
|
||||
vty_out(vty, " vni %u\n", zvrf->l3vni);
|
||||
|
||||
if (vrf->vrf_id != VRF_DEFAULT)
|
||||
vty_out(vty, "!\n");
|
||||
}
|
||||
|
@ -149,5 +149,6 @@ extern struct route_table *zebra_vrf_static_table(afi_t, safi_t,
|
||||
struct zebra_vrf *zvrf);
|
||||
extern struct route_table *
|
||||
zebra_vrf_other_route_table(afi_t afi, u_int32_t table_id, vrf_id_t vrf_id);
|
||||
extern int zebra_vrf_has_config(struct zebra_vrf *zvrf);
|
||||
extern void zebra_vrf_init(void);
|
||||
#endif
|
||||
|
@ -231,13 +231,19 @@ static int zebra_static_route_leak(struct vty *vty,
|
||||
type = STATIC_IPV6_GATEWAY;
|
||||
}
|
||||
|
||||
if (!negate)
|
||||
if (!negate) {
|
||||
static_add_route(afi, safi, type, &p, src_p, gatep, ifname,
|
||||
bh_type, tag, distance, zvrf, nh_zvrf,
|
||||
&snh_label);
|
||||
else
|
||||
/* Mark as having FRR configuration */
|
||||
vrf_set_user_cfged(zvrf->vrf);
|
||||
} else {
|
||||
static_delete_route(afi, safi, type, &p, src_p, gatep, ifname,
|
||||
tag, distance, zvrf, &snh_label);
|
||||
/* If no other FRR config for this VRF, mark accordingly. */
|
||||
if (!zebra_vrf_has_config(zvrf))
|
||||
vrf_reset_user_cfged(zvrf->vrf);
|
||||
}
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
@ -247,19 +253,39 @@ static int zebra_static_route(struct vty *vty, afi_t afi, safi_t safi,
|
||||
const char *mask_str, const char *src_str,
|
||||
const char *gate_str, const char *ifname,
|
||||
const char *flag_str, const char *tag_str,
|
||||
const char *distance_str, const char *vrf_id_str,
|
||||
const char *distance_str, const char *vrf_name,
|
||||
const char *label_str)
|
||||
{
|
||||
struct zebra_vrf *zvrf;
|
||||
struct vrf *vrf;
|
||||
|
||||
/* VRF id */
|
||||
zvrf = zebra_vrf_lookup_by_name(vrf_id_str);
|
||||
zvrf = zebra_vrf_lookup_by_name(vrf_name);
|
||||
|
||||
if (!zvrf) {
|
||||
vty_out(vty, "%% vrf %s is not defined\n", vrf_id_str);
|
||||
/* When trying to delete, the VRF must exist. */
|
||||
if (negate && !zvrf) {
|
||||
vty_out(vty, "%% vrf %s is not defined\n", vrf_name);
|
||||
return CMD_WARNING_CONFIG_FAILED;
|
||||
}
|
||||
|
||||
/* When trying to create, create the VRF if it doesn't exist.
|
||||
* Note: The VRF isn't active until we hear about it from the kernel.
|
||||
*/
|
||||
if (!zvrf) {
|
||||
vrf = vrf_get(VRF_UNKNOWN, vrf_name);
|
||||
if (!vrf) {
|
||||
vty_out(vty, "%% Could not create vrf %s\n", vrf_name);
|
||||
return CMD_WARNING_CONFIG_FAILED;
|
||||
}
|
||||
zvrf = vrf->info;
|
||||
if (!zvrf) {
|
||||
vty_out(vty, "%% Could not create vrf-info %s\n",
|
||||
vrf_name);
|
||||
return CMD_WARNING_CONFIG_FAILED;
|
||||
}
|
||||
/* Mark as having FRR configuration */
|
||||
vrf_set_user_cfged(vrf);
|
||||
}
|
||||
return zebra_static_route_leak(vty, zvrf, zvrf, afi, safi,
|
||||
negate, dest_str, mask_str, src_str,
|
||||
gate_str, ifname, flag_str, tag_str,
|
||||
@ -2286,16 +2312,67 @@ DEFUN (show_vrf,
|
||||
else
|
||||
vty_out(vty, "id %u table %u", zvrf_id(zvrf),
|
||||
zvrf->table_id);
|
||||
if (vrf_is_user_cfged(vrf))
|
||||
vty_out(vty, " (configured)");
|
||||
vty_out(vty, "\n");
|
||||
}
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN (default_vrf_vni_mapping,
|
||||
default_vrf_vni_mapping_cmd,
|
||||
"vni " CMD_VNI_RANGE,
|
||||
"VNI corresponding to the DEFAULT VRF\n"
|
||||
"VNI-ID\n")
|
||||
{
|
||||
int ret = 0;
|
||||
char err[ERR_STR_SZ];
|
||||
struct zebra_vrf *zvrf = NULL;
|
||||
vni_t vni = strtoul(argv[1]->arg, NULL, 10);
|
||||
|
||||
zvrf = vrf_info_lookup(VRF_DEFAULT);
|
||||
if (!zvrf)
|
||||
return CMD_WARNING;
|
||||
|
||||
ret = zebra_vxlan_process_vrf_vni_cmd(zvrf, vni, err, ERR_STR_SZ, 1);
|
||||
if (ret != 0) {
|
||||
vty_out(vty, "%s\n", err);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN (no_default_vrf_vni_mapping,
|
||||
no_default_vrf_vni_mapping_cmd,
|
||||
"no vni " CMD_VNI_RANGE,
|
||||
NO_STR
|
||||
"VNI corresponding to DEFAULT VRF\n"
|
||||
"VNI-ID")
|
||||
{
|
||||
int ret = 0;
|
||||
char err[ERR_STR_SZ];
|
||||
vni_t vni = strtoul(argv[2]->arg, NULL, 10);
|
||||
struct zebra_vrf *zvrf = NULL;
|
||||
|
||||
zvrf = vrf_info_lookup(VRF_DEFAULT);
|
||||
if (!zvrf)
|
||||
return CMD_WARNING;
|
||||
|
||||
ret = zebra_vxlan_process_vrf_vni_cmd(zvrf, vni, err, ERR_STR_SZ, 0);
|
||||
if (ret != 0) {
|
||||
vty_out(vty, "%s\n", err);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN (vrf_vni_mapping,
|
||||
vrf_vni_mapping_cmd,
|
||||
"vni " CMD_VNI_RANGE,
|
||||
"VNI\n"
|
||||
"VNI corresponding to tenant VRF\n"
|
||||
"VNI-ID\n")
|
||||
{
|
||||
int ret = 0;
|
||||
@ -2307,6 +2384,8 @@ DEFUN (vrf_vni_mapping,
|
||||
assert(vrf);
|
||||
assert(zvrf);
|
||||
|
||||
/* Mark as having FRR configuration */
|
||||
vrf_set_user_cfged(vrf);
|
||||
ret = zebra_vxlan_process_vrf_vni_cmd(zvrf, vni, err, ERR_STR_SZ, 1);
|
||||
if (ret != 0) {
|
||||
vty_out(vty, "%s\n", err);
|
||||
@ -2320,7 +2399,7 @@ DEFUN (no_vrf_vni_mapping,
|
||||
no_vrf_vni_mapping_cmd,
|
||||
"no vni " CMD_VNI_RANGE,
|
||||
NO_STR
|
||||
"VNI\n"
|
||||
"VNI corresponding to tenant VRF\n"
|
||||
"VNI-ID")
|
||||
{
|
||||
int ret = 0;
|
||||
@ -2338,6 +2417,10 @@ DEFUN (no_vrf_vni_mapping,
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
/* If no other FRR config for this VRF, mark accordingly. */
|
||||
if (!zebra_vrf_has_config(zvrf))
|
||||
vrf_reset_user_cfged(vrf);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
@ -2361,29 +2444,16 @@ DEFUN (show_vrf_vni,
|
||||
json_vrfs = json_object_new_array();
|
||||
}
|
||||
|
||||
if (!uj)
|
||||
vty_out(vty, "%-37s %-10s %-20s %-20s %-5s %-18s\n",
|
||||
"VRF", "VNI", "VxLAN IF", "L3-SVI", "State", "Rmac");
|
||||
|
||||
RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name) {
|
||||
zvrf = vrf->info;
|
||||
if (!zvrf)
|
||||
continue;
|
||||
|
||||
if (!zvrf->l3vni)
|
||||
continue;
|
||||
|
||||
if (!uj) {
|
||||
vty_out(vty, "vrf: %s VNI: %u",
|
||||
zvrf_name(zvrf),
|
||||
zvrf->l3vni);
|
||||
vty_out(vty, "\n");
|
||||
} else {
|
||||
json_object *json_vrf = NULL;
|
||||
|
||||
json_vrf = json_object_new_object();
|
||||
json_object_string_add(json_vrf, "vrf",
|
||||
zvrf_name(zvrf));
|
||||
json_object_int_add(json_vrf, "l3vni",
|
||||
zvrf->l3vni);
|
||||
json_object_array_add(json_vrfs, json_vrf);
|
||||
}
|
||||
zebra_vxlan_print_vrf_vni(vty, zvrf, json_vrfs);
|
||||
}
|
||||
|
||||
if (uj) {
|
||||
@ -2396,6 +2466,19 @@ DEFUN (show_vrf_vni,
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN (show_evpn_global,
|
||||
show_evpn_global_cmd,
|
||||
"show evpn [json]",
|
||||
SHOW_STR
|
||||
"EVPN\n"
|
||||
JSON_STR)
|
||||
{
|
||||
u_char uj = use_json(argc, argv);
|
||||
|
||||
zebra_vxlan_print_evpn(vty, uj);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN (show_evpn_vni,
|
||||
show_evpn_vni_cmd,
|
||||
"show evpn vni [json]",
|
||||
@ -2431,44 +2514,13 @@ DEFUN (show_evpn_vni_vni,
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN (show_evpn_l3vni,
|
||||
show_evpn_l3vni_cmd,
|
||||
"show evpn l3vni [json]",
|
||||
SHOW_STR
|
||||
"EVPN\n"
|
||||
"L3 VNI\n"
|
||||
JSON_STR)
|
||||
{
|
||||
u_char uj = use_json(argc, argv);
|
||||
|
||||
zebra_vxlan_print_l3vnis(vty, uj);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN (show_evpn_l3vni_vni,
|
||||
show_evpn_l3vni_vni_cmd,
|
||||
"show evpn l3vni " CMD_VNI_RANGE "[json]",
|
||||
SHOW_STR
|
||||
"EVPN\n"
|
||||
"L3 VxLAN Network Identifier\n"
|
||||
"VNI number\n"
|
||||
JSON_STR)
|
||||
{
|
||||
vni_t vni;
|
||||
u_char uj = use_json(argc, argv);
|
||||
|
||||
vni = strtoul(argv[3]->arg, NULL, 10);
|
||||
zebra_vxlan_print_l3vni(vty, vni, uj);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN (show_evpn_rmac_l3vni_mac,
|
||||
show_evpn_rmac_l3vni_mac_cmd,
|
||||
"show evpn rmac l3vni " CMD_VNI_RANGE " mac WORD [json]",
|
||||
DEFUN (show_evpn_rmac_vni_mac,
|
||||
show_evpn_rmac_vni_mac_cmd,
|
||||
"show evpn rmac vni " CMD_VNI_RANGE " mac WORD [json]",
|
||||
SHOW_STR
|
||||
"EVPN\n"
|
||||
"RMAC\n"
|
||||
"L3-VNI\n"
|
||||
"L3 VNI\n"
|
||||
"VNI number\n"
|
||||
"MAC\n"
|
||||
"mac-address (e.g. 0a:0a:0a:0a:0a:0a)\n"
|
||||
@ -2487,13 +2539,13 @@ DEFUN (show_evpn_rmac_l3vni_mac,
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN (show_evpn_rmac_l3vni,
|
||||
show_evpn_rmac_l3vni_cmd,
|
||||
"show evpn rmac l3vni " CMD_VNI_RANGE "[json]",
|
||||
DEFUN (show_evpn_rmac_vni,
|
||||
show_evpn_rmac_vni_cmd,
|
||||
"show evpn rmac vni " CMD_VNI_RANGE "[json]",
|
||||
SHOW_STR
|
||||
"EVPN\n"
|
||||
"RMAC\n"
|
||||
"L3-VNI\n"
|
||||
"L3 VNI\n"
|
||||
"VNI number\n"
|
||||
JSON_STR)
|
||||
{
|
||||
@ -2506,13 +2558,13 @@ DEFUN (show_evpn_rmac_l3vni,
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN (show_evpn_rmac_l3vni_all,
|
||||
show_evpn_rmac_l3vni_all_cmd,
|
||||
"show evpn rmac l3vni all [json]",
|
||||
DEFUN (show_evpn_rmac_vni_all,
|
||||
show_evpn_rmac_vni_all_cmd,
|
||||
"show evpn rmac vni all [json]",
|
||||
SHOW_STR
|
||||
"EVPN\n"
|
||||
"RMAC addresses\n"
|
||||
"L3-VNI\n"
|
||||
"L3 VNI\n"
|
||||
"All VNIs\n"
|
||||
JSON_STR)
|
||||
{
|
||||
@ -2523,13 +2575,13 @@ DEFUN (show_evpn_rmac_l3vni_all,
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN (show_evpn_nh_l3vni_ip,
|
||||
show_evpn_nh_l3vni_ip_cmd,
|
||||
"show evpn next-hops l3vni " CMD_VNI_RANGE " ip WORD [json]",
|
||||
DEFUN (show_evpn_nh_vni_ip,
|
||||
show_evpn_nh_vni_ip_cmd,
|
||||
"show evpn next-hops vni " CMD_VNI_RANGE " ip WORD [json]",
|
||||
SHOW_STR
|
||||
"EVPN\n"
|
||||
"Remote Vteps\n"
|
||||
"L3-VNI\n"
|
||||
"L3 VNI\n"
|
||||
"VNI number\n"
|
||||
"Ip address\n"
|
||||
"Host address (ipv4 or ipv6)\n"
|
||||
@ -2550,13 +2602,13 @@ DEFUN (show_evpn_nh_l3vni_ip,
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN (show_evpn_nh_l3vni,
|
||||
show_evpn_nh_l3vni_cmd,
|
||||
"show evpn next-hops l3vni " CMD_VNI_RANGE "[json]",
|
||||
DEFUN (show_evpn_nh_vni,
|
||||
show_evpn_nh_vni_cmd,
|
||||
"show evpn next-hops vni " CMD_VNI_RANGE "[json]",
|
||||
SHOW_STR
|
||||
"EVPN\n"
|
||||
"Remote Vteps\n"
|
||||
"L3-VNI\n"
|
||||
"L3 VNI\n"
|
||||
"VNI number\n"
|
||||
JSON_STR)
|
||||
{
|
||||
@ -2569,13 +2621,13 @@ DEFUN (show_evpn_nh_l3vni,
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN (show_evpn_nh_l3vni_all,
|
||||
show_evpn_nh_l3vni_all_cmd,
|
||||
"show evpn next-hops l3vni all [json]",
|
||||
DEFUN (show_evpn_nh_vni_all,
|
||||
show_evpn_nh_vni_all_cmd,
|
||||
"show evpn next-hops vni all [json]",
|
||||
SHOW_STR
|
||||
"EVPN\n"
|
||||
"Remote VTEPs\n"
|
||||
"L3-VNI\n"
|
||||
"L3 VNI\n"
|
||||
"All VNIs\n"
|
||||
JSON_STR)
|
||||
{
|
||||
@ -3283,16 +3335,15 @@ void zebra_vty_init(void)
|
||||
/* Commands for VRF */
|
||||
install_element(VIEW_NODE, &show_ipv6_mroute_vrf_all_cmd);
|
||||
|
||||
install_element(VIEW_NODE, &show_evpn_global_cmd);
|
||||
install_element(VIEW_NODE, &show_evpn_vni_cmd);
|
||||
install_element(VIEW_NODE, &show_evpn_vni_vni_cmd);
|
||||
install_element(VIEW_NODE, &show_evpn_l3vni_cmd);
|
||||
install_element(VIEW_NODE, &show_evpn_l3vni_vni_cmd);
|
||||
install_element(VIEW_NODE, &show_evpn_rmac_l3vni_mac_cmd);
|
||||
install_element(VIEW_NODE, &show_evpn_rmac_l3vni_cmd);
|
||||
install_element(VIEW_NODE, &show_evpn_rmac_l3vni_all_cmd);
|
||||
install_element(VIEW_NODE, &show_evpn_nh_l3vni_ip_cmd);
|
||||
install_element(VIEW_NODE, &show_evpn_nh_l3vni_cmd);
|
||||
install_element(VIEW_NODE, &show_evpn_nh_l3vni_all_cmd);
|
||||
install_element(VIEW_NODE, &show_evpn_rmac_vni_mac_cmd);
|
||||
install_element(VIEW_NODE, &show_evpn_rmac_vni_cmd);
|
||||
install_element(VIEW_NODE, &show_evpn_rmac_vni_all_cmd);
|
||||
install_element(VIEW_NODE, &show_evpn_nh_vni_ip_cmd);
|
||||
install_element(VIEW_NODE, &show_evpn_nh_vni_cmd);
|
||||
install_element(VIEW_NODE, &show_evpn_nh_vni_all_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);
|
||||
@ -3303,7 +3354,8 @@ void zebra_vty_init(void)
|
||||
install_element(VIEW_NODE, &show_evpn_neigh_vni_neigh_cmd);
|
||||
install_element(VIEW_NODE, &show_evpn_neigh_vni_vtep_cmd);
|
||||
|
||||
install_element(CONFIG_NODE, &no_vrf_vni_mapping_cmd);
|
||||
install_element(CONFIG_NODE, &default_vrf_vni_mapping_cmd);
|
||||
install_element(CONFIG_NODE, &no_default_vrf_vni_mapping_cmd);
|
||||
install_element(VRF_NODE, &vrf_vni_mapping_cmd);
|
||||
install_element(VRF_NODE, &no_vrf_vni_mapping_cmd);
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -31,6 +31,7 @@
|
||||
#include "vlan.h"
|
||||
#include "vxlan.h"
|
||||
|
||||
#include "lib/json.h"
|
||||
#include "zebra/zebra_vrf.h"
|
||||
|
||||
/* Is EVPN enabled? */
|
||||
@ -53,8 +54,12 @@ is_evpn_enabled()
|
||||
|
||||
extern ifindex_t get_l3vni_svi_ifindex(vrf_id_t vrf_id);
|
||||
extern int zebra_vxlan_vrf_delete(struct zebra_vrf *zvrf);
|
||||
extern int zebra_vxlan_vrf_enable(struct zebra_vrf *zvrf);
|
||||
extern int zebra_vxlan_vrf_disable(struct zebra_vrf *zvrf);
|
||||
extern int zebra_vxlan_vrf_delete(struct zebra_vrf *zvrf);
|
||||
extern void zebra_vxlan_print_specific_nh_l3vni(struct vty *vty, vni_t l3vni,
|
||||
struct ipaddr *ip, u_char uj);
|
||||
extern void zebra_vxlan_print_evpn(struct vty *vty, u_char uj);
|
||||
extern void zebra_vxlan_print_specific_rmac_l3vni(struct vty *vty, vni_t l3vni,
|
||||
struct ethaddr *rmac,
|
||||
u_char use_json);
|
||||
@ -99,9 +104,8 @@ extern void zebra_vxlan_print_nh_l3vni(struct vty *vty, vni_t vni, u_char
|
||||
extern void zebra_vxlan_print_nh_all_l3vni(struct vty *vty, u_char use_json);
|
||||
extern void zebra_vxlan_print_l3vni(struct vty *vty, vni_t vni,
|
||||
u_char use_json);
|
||||
extern void zebra_vxlan_print_l3vnis(struct vty *vty,
|
||||
u_char use_json);
|
||||
|
||||
extern void zebra_vxlan_print_vrf_vni(struct vty *vty, struct zebra_vrf *zvrf,
|
||||
json_object *json_vrfs);
|
||||
extern int zebra_vxlan_add_del_gw_macip(struct interface *ifp, struct prefix *p,
|
||||
int add);
|
||||
extern int zebra_vxlan_svi_up(struct interface *ifp, struct interface *link_if);
|
||||
@ -140,6 +144,8 @@ extern int zebra_vxlan_remote_vtep_add(struct zserv *client,
|
||||
u_short length, struct zebra_vrf *zvrf);
|
||||
extern int zebra_vxlan_remote_vtep_del(struct zserv *client,
|
||||
u_short length, struct zebra_vrf *zvrf);
|
||||
extern int zebra_vxlan_advertise_subnet(struct zserv *client, u_short length,
|
||||
struct zebra_vrf *zvrf);
|
||||
extern int zebra_vxlan_advertise_gw_macip(struct zserv *client,
|
||||
u_short length,
|
||||
struct zebra_vrf *zvrf);
|
||||
@ -151,6 +157,7 @@ extern int zebra_vxlan_process_vrf_vni_cmd(struct zebra_vrf *zvrf, vni_t vni,
|
||||
int err_str_sz, int add);
|
||||
extern void zebra_vxlan_init_tables(struct zebra_vrf *zvrf);
|
||||
extern void zebra_vxlan_close_tables(struct zebra_vrf *);
|
||||
extern void zebra_vxlan_cleanup_tables(struct zebra_vrf *);
|
||||
extern void zebra_vxlan_ns_init(struct zebra_ns *zns);
|
||||
extern void zebra_vxlan_ns_disable(struct zebra_ns *zns);
|
||||
extern void zebra_vxlan_evpn_vrf_route_add(vrf_id_t vrf_id,
|
||||
|
@ -83,6 +83,10 @@ void zebra_vxlan_print_vnis(struct vty *vty, struct zebra_vrf *zvrf)
|
||||
{
|
||||
}
|
||||
|
||||
void zebra_vxlan_print_evpn(struct vty *vty, u_char uj)
|
||||
{
|
||||
}
|
||||
|
||||
void zebra_vxlan_print_rmacs_l3vni(struct vty*, vni_t, u_char)
|
||||
{
|
||||
}
|
||||
@ -103,10 +107,6 @@ void zebra_vxlan_print_l3vni(struct vty *vty, vni_t vni)
|
||||
{
|
||||
}
|
||||
|
||||
void zebra_vxlan_print_l3vnis(struct vty *vty)
|
||||
{
|
||||
}
|
||||
|
||||
int zebra_vxlan_svi_up(struct interface *ifp, struct interface *link_if)
|
||||
{
|
||||
return 0;
|
||||
@ -207,3 +207,7 @@ void zebra_vxlan_init_tables(struct zebra_vrf *zvrf)
|
||||
void zebra_vxlan_close_tables(struct zebra_vrf *zvrf)
|
||||
{
|
||||
}
|
||||
|
||||
void zebra_vxlan_cleanup_tables(struct zebra_vrf *zvrf)
|
||||
{
|
||||
}
|
||||
|
@ -70,6 +70,9 @@ struct zebra_vni_t_ {
|
||||
/* Flag for advertising gw macip */
|
||||
u_int8_t advertise_gw_macip;
|
||||
|
||||
/* Flag for advertising gw macip */
|
||||
u_int8_t advertise_subnet;
|
||||
|
||||
/* Corresponding VxLAN interface. */
|
||||
struct interface *vxlan_if;
|
||||
|
||||
@ -233,6 +236,7 @@ struct zebra_mac_t_ {
|
||||
#define ZEBRA_MAC_AUTO 0x04 /* Auto created for neighbor. */
|
||||
#define ZEBRA_MAC_STICKY 0x08 /* Static MAC */
|
||||
#define ZEBRA_MAC_REMOTE_RMAC 0x10 /* remote router mac */
|
||||
#define ZEBRA_MAC_DEF_GW 0x20
|
||||
|
||||
/* Local or remote info. */
|
||||
union {
|
||||
@ -314,6 +318,7 @@ struct zebra_neigh_t_ {
|
||||
#define ZEBRA_NEIGH_LOCAL 0x01
|
||||
#define ZEBRA_NEIGH_REMOTE 0x02
|
||||
#define ZEBRA_NEIGH_REMOTE_NH 0x04 /* neigh entry for remote vtep */
|
||||
#define ZEBRA_NEIGH_DEF_GW 0x08
|
||||
|
||||
enum zebra_neigh_state state;
|
||||
|
||||
|
@ -2603,6 +2603,9 @@ static inline void zserv_handle_commands(struct zserv *client,
|
||||
case ZEBRA_ADVERTISE_DEFAULT_GW:
|
||||
zebra_vxlan_advertise_gw_macip(client, length, zvrf);
|
||||
break;
|
||||
case ZEBRA_ADVERTISE_SUBNET:
|
||||
zebra_vxlan_advertise_subnet(client, length, zvrf);
|
||||
break;
|
||||
case ZEBRA_ADVERTISE_ALL_VNI:
|
||||
zebra_vxlan_advertise_all_vni(client, length, zvrf);
|
||||
break;
|
||||
|
@ -114,6 +114,8 @@ struct zserv {
|
||||
u_int32_t l3vnidel_cnt;
|
||||
u_int32_t macipadd_cnt;
|
||||
u_int32_t macipdel_cnt;
|
||||
u_int32_t prefixadd_cnt;
|
||||
u_int32_t prefixdel_cnt;
|
||||
|
||||
time_t connect_time;
|
||||
time_t last_read_time;
|
||||
|
Loading…
Reference in New Issue
Block a user