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);
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)
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);
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;
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);
}
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);
}
/* 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;
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 *);
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);
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);
}
}
+/*
+ * 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.
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 */
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];
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)
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);
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) {
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;
}
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)));
{
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;
&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);
}
/* 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);
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,
&& !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;
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,
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
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);
/* 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;
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;
}
/* uninten temporary */
- aspath_unintern(&attr.aspath);
+ if (!src_attr)
+ aspath_unintern(&attr.aspath);
return 0;
}
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
* 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. */
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;
+
+ l3vni = bgpevpn_get_l3vni(vpn);
+ if (l3vni) {
+ vni2label(l3vni, &label[1]);
+ num_labels++;
+ }
+ }
- memcpy(&tmp_ri->extra->label, &label, BGP_LABEL_BYTES);
+ 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;
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));
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,
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;
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;
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.
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);
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,
/* 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;
}
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)
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)
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
}
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;
}
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;
}
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:
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;
stream_put(s, &temp, 16);
}
- if (label)
+ if (num_labels)
stream_put(s, label, 3);
else
stream_put3(s, 0);
*/
/* 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));
}
}
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,
}
/*
- * 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;
}
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) ?
* 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);
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:
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:
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;
}
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);
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,
/* 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;
|| 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)
{
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)
{
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];
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(
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",
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;
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));
}
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;
}
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 {
return;
}
}
-
- display_vni(vty, vpn, json);
}
/*
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);
+
}
/*
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.
*/
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");
}
}
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,
"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))
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;
/* 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) {
*/
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
"Specify Route type\n"
"MAC-IP (Type-2) route\n"
"Multicast (Type-3) route\n"
+ "Prefix route\n"
JSON_STR)
{
struct bgp *bgp;
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;
}
json, JSON_C_TO_STRING_PRETTY));
json_object_free(json);
}
-
return CMD_SUCCESS;
}
*/
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
"Specify Route type\n"
"MAC-IP (Type-2) route\n"
"Multicast (Type-3) route\n"
+ "Prefix route\n"
JSON_STR)
{
struct bgp *bgp;
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;
}
/* 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];
&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
}
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));
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);
}
}
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. */
{
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;
}
/* 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",
/* 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. */
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;
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;
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. */
&& 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,
&& 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,
}
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(
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(
/* 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);
/* 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
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);
/* 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 */
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",
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;
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(
/* 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,
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);
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);
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. */
#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);
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. */
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
}
}
- label = decode_label(&binfo->extra->label);
+ label = decode_label(&binfo->extra->label[0]);
if (bgp_is_valid_label(&label)) {
if (json) {
#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");
/* 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);
#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.
/* 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 {
/* 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 */
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;
}
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;
* 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))
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(
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++;
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",
}
bgp_packet_mpunreach_prefix(s, &rn->p, afi, safi, prd,
- NULL, addpath_encode,
+ NULL, 0, addpath_encode,
addpath_tx_id, NULL);
}
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
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);
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 */
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);
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);
"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;
}
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;
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;
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)
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)
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);
/* 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 */
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;
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;
if (bi->extra)
label = decode_label(
- &bi->extra->label);
+ &bi->extra->label[0]);
(*rfapiBgpInfoFilteredImportFunction(
safi))(
it, /* which import table */
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 */
}
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);
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 */
{
}
}
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)
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);
}
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)
ZEBRA_ROUTE_VNC_DIRECT,
BGP_ROUTE_REDISTRIBUTE,
NULL, /* RD not used for unicast */
- NULL,
+ NULL, 0,
NULL); /* tag not used for unicast */
}
}
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
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 */
}
}
}
unicast */
NULL, /* tag not used for
unicast */
- 0, NULL); /* EVPN not used */
+ 0, 0, NULL); /* EVPN not used */
bgp_attr_unintern(&iattr);
}
BGP_ROUTE_REDISTRIBUTE,
NULL, /* RD not used for
unicast */
- NULL, NULL); /* tag not
+ NULL, 0, NULL); /* tag not
used for
unicast */
}
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);
ZEBRA_ROUTE_VNC_DIRECT,
BGP_ROUTE_REDISTRIBUTE,
NULL, /* RD not used for unicast */
- NULL,
+ NULL, 0,
NULL); /* tag not used for unicast */
return;
}
BGP_ROUTE_REDISTRIBUTE,
NULL, /* RD not used for
unicast */
- NULL, NULL); /* tag not
+ NULL, 0, NULL); /* tag not
used for
unicast,
EVPN
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);
}
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
NULL, /* tag not used for
unicast, EVPN
neither */
- 0, NULL); /* EVPN not used */
+ 0, 0, NULL); /* EVPN not used */
bgp_attr_unintern(&iattr);
}
}
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 */
}
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 */
prd = &bi_interior->extra->vnc.import
.rd;
label = decode_label(
- &bi_interior->extra->label);
+ &bi_interior->extra->label[0]);
} else
prd = NULL;
prd = &bi_interior->extra->vnc.import
.rd;
label = decode_label(
- &bi_interior->extra->label);
+ &bi_interior->extra->label[0]);
} else
prd = NULL;
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;
if (bi->extra) {
prd = &bi->extra->vnc.import.rd;
label = decode_label(
- &bi->extra->label);
+ &bi->extra->label[0]);
} else
prd = NULL;
prd = &bi_interior->extra->vnc.import
.rd;
label = decode_label(
- &bi_interior->extra->label);
+ &bi_interior->extra->label[0]);
} else
prd = NULL;
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;
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;
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;
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),
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),
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)
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);
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
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. */
return CMD_WARNING_CONFIG_FAILED;
}
+ /* Clear configured flag and invoke delete. */
+ UNSET_FLAG(vrfp->status, VRF_CONFIGURED);
vrf_delete(vrfp);
return CMD_SUCCESS;
/* 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;
(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
*/
(*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,
ZEBRA_FEC_UNREGISTER,
ZEBRA_FEC_UPDATE,
ZEBRA_ADVERTISE_DEFAULT_GW,
+ ZEBRA_ADVERTISE_SUBNET,
ZEBRA_ADVERTISE_ALL_VNI,
ZEBRA_VNI_ADD,
ZEBRA_VNI_DEL,
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,
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);
};
/* 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;
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;
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.
*/
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.
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);
rtadv_init(zns);
#endif
- zns->if_table = route_table_init();
- zebra_vxlan_ns_init(zns);
kernel_init(zns);
interface_list(zns);
route_read(zns);
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;
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)
{
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(
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];
}
}
+ /* Kick off any VxLAN-EVPN processing. */
+ zebra_vxlan_vrf_enable(zvrf);
+
return 0;
}
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];
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;
}
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++) {
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);
}
}
+ /* 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;
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);
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.
*/
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
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);
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");
}
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
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;
}
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,
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;
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);
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;
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;
}
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) {
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]",
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"
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)
{
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)
{
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"
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)
{
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)
{
/* 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);
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);
#include "zebra/zebra_vxlan.h"
#include "zebra/zebra_memory.h"
#include "zebra/zebra_l2.h"
-#include "lib/json.h"
DEFINE_MTYPE_STATIC(ZEBRA, HOST_PREFIX, "host prefix");
DEFINE_MTYPE_STATIC(ZEBRA, ZVNI, "VNI hash");
/* static function declarations */
+static int ip_prefix_send_to_client(vrf_id_t vrf_id,
+ struct prefix *p,
+ uint16_t cmd);
static void zvni_print_neigh(zebra_neigh_t *n, void *ctxt, json_object *json);
static void zvni_print_neigh_hash(struct hash_backet *backet, void *ctxt);
static void zvni_print_neigh_hash_all_vni(struct hash_backet *backet,
: "Inactive");
}
}
+ if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_DEF_GW)) {
+ if (!json)
+ vty_out(vty, " Default-gateway");
+ else
+ json_object_boolean_true_add(json, "defaultGateway");
+ }
if (json == NULL)
vty_out(vty, "\n");
}
ipaddr2str(&n->ip, buf2, sizeof(buf2)));
vty_out(vty, " RMAC: %s\n",
prefix_mac2str(&n->emac, buf1, sizeof(buf1)));
- vty_out(vty, " Host-List:\n");
+ vty_out(vty, " Refcount: %d\n", listcount(n->host_list));
+ vty_out(vty, " Prefixes:\n");
for (ALL_LIST_ELEMENTS_RO(n->host_list, node, p))
vty_out(vty, " %s\n",
prefix2str(p, buf2, sizeof(buf2)));
json_object_string_add(json, "ip",
ipaddr2str(&(n->ip), buf2,
sizeof(buf2)));
- json_object_string_add(json, "rmac",
+ json_object_string_add(json, "routerMac",
prefix_mac2str(&n->emac, buf2,
sizeof(buf2)));
+ json_object_int_add(json, "refCount", listcount(n->host_list));
for (ALL_LIST_ELEMENTS_RO(n->host_list, node, p))
json_object_array_add(json_hosts,
json_object_new_string(
prefix2str(p, buf2,
sizeof(buf2))));
- json_object_object_add(json, "hosts", json_hosts);
+ json_object_object_add(json, "prefixList", json_hosts);
}
}
prefix_mac2str(&zrmac->macaddr, buf1, sizeof(buf1)));
vty_out(vty, " Remote VTEP: %s\n",
inet_ntoa(zrmac->fwd_info.r_vtep_ip));
- vty_out(vty, " Host-List:\n");
+ vty_out(vty, " Refcount: %d\n", listcount(zrmac->host_list));
+ vty_out(vty, " Prefixes:\n");
for (ALL_LIST_ELEMENTS_RO(zrmac->host_list, node, p))
vty_out(vty, " %s\n",
prefix2str(p, buf2, sizeof(buf2)));
} else {
json_hosts = json_object_new_array();
- json_object_string_add(json, "Rmac",
+ json_object_string_add(json, "routerMac",
prefix_mac2str(&zrmac->macaddr,
buf1,
sizeof(buf1)));
- json_object_string_add(json, "vtep-ip",
+ json_object_string_add(json, "vtepIp",
inet_ntoa(zrmac->fwd_info.r_vtep_ip));
+ json_object_int_add(json, "refCount",
+ listcount(zrmac->host_list));
for (ALL_LIST_ELEMENTS_RO(zrmac->host_list, node, p))
json_object_array_add(json_hosts,
json_object_new_string(
prefix2str(p, buf2,
sizeof(buf2))));
- json_object_object_add(json, "hosts", json_hosts);
+ json_object_object_add(json, "prefixList", json_hosts);
}
}
vty_out(vty, " Auto Mac ");
}
+ if (CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY))
+ vty_out(vty, " Sticky Mac ");
+
+ if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DEF_GW))
+ vty_out(vty, " Default-gateway Mac ");
+
vty_out(vty, "\n");
/* print all the associated neigh */
vty_out(vty, " Neighbors:\n");
return;
if (!json_vni) {
- vty_out(vty, "%-15s %-17s %6d\n",
+ vty_out(vty, "%-15s %-17s\n",
ipaddr2str(&(n->ip), buf2, sizeof(buf2)),
- prefix_mac2str(&n->emac, buf1, sizeof(buf1)),
- listcount(n->host_list));
+ prefix_mac2str(&n->emac, buf1, sizeof(buf1)));
} else {
- json_object_string_add(json_nh, "nexthop-ip",
+ json_object_string_add(json_nh, "nexthopIp",
ipaddr2str(&n->ip, buf2, sizeof(buf2)));
- json_object_string_add(json_nh, "rmac",
+ json_object_string_add(json_nh, "routerMac",
prefix_mac2str(&n->emac, buf1,
sizeof(buf1)));
- json_object_int_add(json_nh, "refCnt", listcount(n->host_list));
json_object_object_add(json_vni,
ipaddr2str(&(n->ip), buf2, sizeof(buf2)),
json_nh);
if (json == NULL) {
vty_out(vty, "\nVNI %u #Next-Hops %u\n\n",
zl3vni->vni, num_nh);
- vty_out(vty, "%-15s %-17s %6s\n", "IP",
- "RMAC", "Refcnt");
+ vty_out(vty, "%-15s %-17s\n", "IP", "RMAC");
} else
- json_object_int_add(json_vni, "numNh", num_nh);
+ json_object_int_add(json_vni, "numNextHops", num_nh);
memset(&wctx, 0, sizeof(struct nh_walk_ctx));
wctx.vty = vty;
}
if (json == NULL) {
- vty_out(vty, "\nVNI %u #MACs %u\n\n",
+ vty_out(vty, "\nVNI %u #RMACs %u\n\n",
zl3vni->vni, num_rmacs);
- vty_out(vty, "%-17s %-21s %-6s\n", "MAC",
- "Remote VTEP", "Refcnt");
+ vty_out(vty, "%-17s %-21s\n", "RMAC", "Remote VTEP");
} else
json_object_int_add(json_vni, "numRmacs", num_rmacs);
return;
if (!json) {
- vty_out(vty, "%-17s %-21s %-6d\n",
+ vty_out(vty, "%-17s %-21s\n",
prefix_mac2str(&zrmac->macaddr, buf, sizeof(buf)),
- inet_ntoa(zrmac->fwd_info.r_vtep_ip),
- listcount(zrmac->host_list));
+ inet_ntoa(zrmac->fwd_info.r_vtep_ip));
} else {
- json_object_string_add(json_rmac, "rmac",
+ json_object_string_add(json_rmac, "routerMac",
prefix_mac2str(&zrmac->macaddr, buf,
sizeof(buf)));
- json_object_string_add(json_rmac, "vtep-ip",
+ json_object_string_add(json_rmac, "vtepIp",
inet_ntoa(zrmac->fwd_info.r_vtep_ip));
- json_object_int_add(json_rmac, "refcnt",
- listcount(zrmac->host_list));
json_object_object_add(json,
prefix_mac2str(&zrmac->macaddr, buf,
sizeof(buf)),
if (!json) {
vty_out(vty, "VNI: %u\n", zl3vni->vni);
- vty_out(vty, " Local Vtep Ip: %s",
+ vty_out(vty, " Type: %s\n", "L3");
+ vty_out(vty, " Tenant VRF: %s\n",
+ zl3vni_vrf_name(zl3vni));
+ vty_out(vty, " Local Vtep Ip: %s\n",
inet_ntoa(zl3vni->local_vtep_ip));
vty_out(vty, " Vxlan-Intf: %s\n",
zl3vni_vxlan_if_name(zl3vni));
zl3vni_svi_if_name(zl3vni));
vty_out(vty, " State: %s\n",
zl3vni_state2str(zl3vni));
- vty_out(vty, " Vrf: %s\n",
- zl3vni_vrf_name(zl3vni));
- vty_out(vty, " Rmac: %s\n",
+ vty_out(vty, " Router MAC: %s\n",
zl3vni_rmac2str(zl3vni, buf, sizeof(buf)));
- vty_out(vty, " L2-VNIs: ");
+ vty_out(vty, " L2 VNIs: ");
for (ALL_LIST_ELEMENTS(zl3vni->l2vnis, node, nnode, zvni))
vty_out(vty, "%u ", zvni->vni);
vty_out(vty, "\n");
} else {
json_vni_list = json_object_new_array();
json_object_int_add(json, "vni", zl3vni->vni);
- json_object_string_add(json, "local-vtep-ip",
+ json_object_string_add(json, "type", "L3");
+ json_object_string_add(json, "localVtepIp",
inet_ntoa(zl3vni->local_vtep_ip));
- json_object_string_add(json, "vxlan-intf",
+ json_object_string_add(json, "vxlanIntf",
zl3vni_vxlan_if_name(zl3vni));
- json_object_string_add(json, "svi-if",
+ json_object_string_add(json, "sviIntf",
zl3vni_svi_if_name(zl3vni));
json_object_string_add(json, "state",
zl3vni_state2str(zl3vni));
json_object_string_add(json, "vrf",
zl3vni_vrf_name(zl3vni));
- json_object_string_add(json, "rmac",
+ json_object_string_add(json, "routerMac",
zl3vni_rmac2str(zl3vni, buf,
sizeof(buf)));
for (ALL_LIST_ELEMENTS(zl3vni->l2vnis, node, nnode, zvni)) {
json_object_array_add(json_vni_list,
json_object_new_int(zvni->vni));
}
- json_object_object_add(json, "l2-vnis", json_vni_list);
+ json_object_object_add(json, "l2Vnis", json_vni_list);
}
}
if (json == NULL) {
vty_out(vty, "VNI: %u\n", zvni->vni);
- vty_out(vty, " VRF: %s\n", vrf_id_to_name(zvni->vrf_id));
+ vty_out(vty, " Type: %s\n", "L2");
+ vty_out(vty, " Tenant VRF: %s\n", vrf_id_to_name(zvni->vrf_id));
} else {
json_object_int_add(json, "vni", zvni->vni);
+ json_object_string_add(json, "type", "L2");
json_object_string_add(json, "vrf",
vrf_id_to_name(zvni->vrf_id));
}
}
num_macs = num_valid_macs(zvni);
num_neigh = hashcount(zvni->neigh_table);
- if (json == NULL)
- vty_out(vty, " VxLAN interface: %s ifIndex: %u VTEP IP: %s\n",
- zvni->vxlan_if->name, zvni->vxlan_if->ifindex,
+ if (json == NULL) {
+ vty_out(vty, " VxLAN interface: %s\n",
+ zvni->vxlan_if->name);
+ vty_out(vty, " VxLAN ifIndex: %u\n", zvni->vxlan_if->ifindex);
+ vty_out(vty," Local VTEP IP: %s\n",
inet_ntoa(zvni->local_vtep_ip));
- else {
+ } else {
json_object_string_add(json, "vxlanInterface",
zvni->vxlan_if->name);
json_object_int_add(json, "ifindex", zvni->vxlan_if->ifindex);
static void zl3vni_print_hash(struct hash_backet *backet,
void *ctx[])
{
- char buf[ETHER_ADDR_STRLEN];
struct vty *vty = NULL;
json_object *json = NULL;
json_object *json_vni = NULL;
return;
if (!json) {
- vty_out(vty, "%-10u %-15s %-20s %-20s %-5s %-37s %-18s\n",
- zl3vni->vni,
- inet_ntoa(zl3vni->local_vtep_ip),
+ vty_out(vty,
+ "%-10u %-4s %-21s %-8lu %-8lu %-15s %-37s\n",
+ zl3vni->vni, "L3",
zl3vni_vxlan_if_name(zl3vni),
- zl3vni_svi_if_name(zl3vni),
- zl3vni_state2str(zl3vni),
- zl3vni_vrf_name(zl3vni),
- zl3vni_rmac2str(zl3vni, buf, sizeof(buf)));
+ hashcount(zl3vni->rmac_table),
+ hashcount(zl3vni->nh_table),
+ "n/a",
+ zl3vni_vrf_name(zl3vni));
} else {
char vni_str[VNI_STR_LEN];
snprintf(vni_str, VNI_STR_LEN, "%u", zl3vni->vni);
json_vni = json_object_new_object();
json_object_int_add(json_vni, "vni", zl3vni->vni);
- json_object_string_add(json_vni, "local-ip",
- inet_ntoa(zl3vni->local_vtep_ip));
- json_object_string_add(json_vni, "vxlan-if",
+ json_object_string_add(json_vni, "vxlanIf",
zl3vni_vxlan_if_name(zl3vni));
- json_object_string_add(json_vni, "svi-if",
- zl3vni_svi_if_name(zl3vni));
- json_object_string_add(json_vni, "state",
- zl3vni_state2str(zl3vni));
- json_object_string_add(json_vni, "vrf",
+ json_object_int_add(json_vni, "numMacs",
+ hashcount(zl3vni->rmac_table));
+ json_object_int_add(json_vni, "numArpNd",
+ hashcount(zl3vni->nh_table));
+ json_object_string_add(json_vni, "numRemoteVteps", "n/a");
+ json_object_string_add(json_vni, "type", "L3");
+ json_object_string_add(json_vni, "tenantVrf",
zl3vni_vrf_name(zl3vni));
- json_object_string_add(json_vni, "rmac",
- zl3vni_rmac2str(zl3vni, buf,
- sizeof(buf)));
json_object_object_add(json, vni_str, json_vni);
}
num_macs = num_valid_macs(zvni);
num_neigh = hashcount(zvni->neigh_table);
if (json == NULL)
- vty_out(vty, "%-10u %-21s %-15s %-8u %-8u %-15u %-37s\n",
- zvni->vni,
+ vty_out(vty,
+ "%-10u %-4s %-21s %-8u %-8u %-15u %-37s\n",
+ zvni->vni, "L2",
zvni->vxlan_if ? zvni->vxlan_if->name : "unknown",
- inet_ntoa(zvni->local_vtep_ip), num_macs, num_neigh,
- num_vteps,
+ num_macs, num_neigh, num_vteps,
vrf_id_to_name(zvni->vrf_id));
else {
char vni_str[VNI_STR_LEN];
snprintf(vni_str, VNI_STR_LEN, "%u", zvni->vni);
json_vni = json_object_new_object();
+ json_object_int_add(json_vni, "vni", zvni->vni);
+ json_object_string_add(json_vni, "type", "L2");
json_object_string_add(json_vni, "vxlanIf",
zvni->vxlan_if ? zvni->vxlan_if->name
: "unknown");
- json_object_string_add(json_vni, "vtepIp",
- inet_ntoa(zvni->local_vtep_ip));
json_object_int_add(json_vni, "numMacs", num_macs);
json_object_int_add(json_vni, "numArpNd", num_neigh);
json_object_int_add(json_vni, "numRemoteVteps", num_vteps);
+ json_object_string_add(json_vni, "tenantVrf",
+ vrf_id_to_name(zvni->vrf_id));
if (num_vteps) {
json_vtep_list = json_object_new_array();
for (zvtep = zvni->vteps; zvtep; zvtep = zvtep->next) {
ZEBRA_NEIGH_SET_ACTIVE(n);
zvni_neigh_send_add_to_client(
- zvni->vni, &n->ip, &n->emac, 0);
+ zvni->vni, &n->ip, &n->emac, n->flags);
} else {
if (IS_ZEBRA_DEBUG_VXLAN)
zlog_debug(
*/
static int zvni_neigh_send_add_to_client(vni_t vni,
struct ipaddr *ip,
- struct ethaddr *macaddr, u_char flags)
+ struct ethaddr *macaddr,
+ u_char neigh_flags)
{
+ u_char flags = 0;
+
+ if (CHECK_FLAG(neigh_flags, ZEBRA_NEIGH_DEF_GW))
+ SET_FLAG(flags, ZEBRA_MACIP_TYPE_GW);
+
return zvni_macip_send_msg_to_client(vni, macaddr, ip, flags,
ZEBRA_MACIP_ADD);
}
zvni_gw_macip_add(ifp, zvni, &macaddr, &ip);
}
+ return 0;
+}
+
+
+static int zvni_advertise_subnet(zebra_vni_t *zvni,
+ struct interface *ifp,
+ int advertise)
+{
+ struct listnode *cnode = NULL, *cnnode = NULL;
+ struct connected *c = NULL;
+ struct ethaddr macaddr;
+
+ memcpy(&macaddr.octet, ifp->hw_addr, ETH_ALEN);
+
+ for (ALL_LIST_ELEMENTS(ifp->connected, cnode, cnnode, c)) {
+ struct prefix p;
+ memcpy(&p, c->address, sizeof(struct prefix));
+
+ /* skip link local address */
+ if (IN6_IS_ADDR_LINKLOCAL(&p.u.prefix6))
+ continue;
+
+ apply_mask(&p);
+ if (advertise)
+ ip_prefix_send_to_client(ifp->vrf_id, &p,
+ ZEBRA_IP_PREFIX_ROUTE_ADD);
+ else
+ ip_prefix_send_to_client(ifp->vrf_id, &p,
+ ZEBRA_IP_PREFIX_ROUTE_DEL);
+ }
return 0;
}
/* Set "local" forwarding info. */
SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL);
SET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
+ SET_FLAG(mac->flags, ZEBRA_MAC_DEF_GW);
memset(&mac->fwd_info, 0, sizeof(mac->fwd_info));
mac->fwd_info.local.ifindex = ifp->ifindex;
mac->fwd_info.local.vid = vxl->access_vlan;
/* Set "local" forwarding info. */
SET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL);
+ SET_FLAG(n->flags, ZEBRA_NEIGH_DEF_GW);
memcpy(&n->emac, macaddr, ETH_ALEN);
n->ifindex = ifp->ifindex;
+ /* Only advertise in BGP if the knob is enabled */
+ if (!advertise_gw_macip_enabled(zvni))
+ return 0;
+
if (IS_ZEBRA_DEBUG_VXLAN)
zlog_debug(
"SVI %s(%u) L2-VNI %u, sending GW MAC %s IP %s add to BGP",
ipaddr2str(ip, buf2, sizeof(buf2)));
zvni_neigh_send_add_to_client(zvni->vni, ip, macaddr,
- ZEBRA_MAC_TYPE_GW);
+ n->flags);
return 0;
}
if (!CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL))
return -1;
- if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug(
- "SVI %s(%u) L2-VNI %u, sending GW MAC %s IP %s del to BGP",
- ifp->name, ifp->ifindex, zvni->vni,
- prefix_mac2str(&(n->emac), buf1, sizeof(buf1)),
- ipaddr2str(ip, buf2, sizeof(buf2)));
-
- /* Remove neighbor from BGP. */
- zvni_neigh_send_del_to_client(zvni->vni, &n->ip, &n->emac,
- ZEBRA_MAC_TYPE_GW);
+ /* only need to delete the entry from bgp if we sent it before */
+ if (advertise_gw_macip_enabled(zvni)) {
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug("%u:SVI %s(%u) VNI %u, sending GW MAC %s IP %s del to BGP",
+ ifp->vrf_id, ifp->name,
+ ifp->ifindex, zvni->vni,
+ prefix_mac2str(&(n->emac),
+ NULL,
+ ETHER_ADDR_STRLEN),
+ ipaddr2str(ip, buf2, sizeof(buf2)));
+
+ /* Remove neighbor from BGP. */
+ zvni_neigh_send_del_to_client(zvni->vni, &n->ip, &n->emac,
+ ZEBRA_MACIP_TYPE_GW);
+ }
/* Delete this neighbor entry. */
zvni_neigh_del(zvni, n);
if (!zvni)
return;
- if (!advertise_gw_macip_enabled(zvni))
- return;
-
ifp = zvni->vxlan_if;
if (!ifp)
return;
{
struct mac_walk_ctx *wctx = arg;
zebra_mac_t *mac = backet->data;
- u_char sticky = 0;
if (((wctx->flags & DEL_LOCAL_MAC) && (mac->flags & ZEBRA_MAC_LOCAL))
|| ((wctx->flags & DEL_REMOTE_MAC)
&& IPV4_ADDR_SAME(&mac->fwd_info.r_vtep_ip,
&wctx->r_vtep_ip))) {
if (wctx->upd_client && (mac->flags & ZEBRA_MAC_LOCAL)) {
- sticky = CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY) ? 1
- : 0;
zvni_mac_send_del_to_client(
wctx->zvni->vni, &mac->macaddr,
- (sticky ? ZEBRA_MAC_TYPE_STICKY : 0));
+ mac->flags);
}
if (wctx->uninstall)
* Inform BGP about local MAC addition.
*/
static int zvni_mac_send_add_to_client(vni_t vni,
- struct ethaddr *macaddr, u_char flags)
+ struct ethaddr *macaddr,
+ u_char mac_flags)
{
+ u_char flags = 0;
+
+ if (CHECK_FLAG(mac_flags, ZEBRA_MAC_STICKY))
+ SET_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY);
+ if (CHECK_FLAG(mac_flags, ZEBRA_MAC_DEF_GW))
+ SET_FLAG(flags, ZEBRA_MACIP_TYPE_GW);
+
return zvni_macip_send_msg_to_client(vni, macaddr, NULL, flags,
ZEBRA_MACIP_ADD);
}
* Inform BGP about local MAC deletion.
*/
static int zvni_mac_send_del_to_client(vni_t vni,
- struct ethaddr *macaddr, u_char flags)
+ struct ethaddr *macaddr,
+ u_char mac_flags)
{
+ u_char flags = 0;
+
+ if (CHECK_FLAG(mac_flags, ZEBRA_MAC_STICKY))
+ SET_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY);
+ if (CHECK_FLAG(mac_flags, ZEBRA_MAC_DEF_GW))
+ SET_FLAG(flags, ZEBRA_MACIP_TYPE_GW);
+
return zvni_macip_send_msg_to_client(vni, macaddr, NULL, flags,
ZEBRA_MACIP_DEL);
}
vlan_if = zvni_map_to_svi(vxl->access_vlan, zif->brslave_info.br_if);
if (vlan_if) {
- if (advertise_gw_macip_enabled(zvni)) {
- /* Add SVI MAC-IP */
- zvni_add_macip_for_intf(vlan_if, zvni);
+ /* Add SVI MAC-IP */
+ zvni_add_macip_for_intf(vlan_if, zvni);
- /* Add VRR MAC-IP - if any*/
- vrr_if = zebra_get_vrr_intf_for_svi(vlan_if);
- if (vrr_if)
- zvni_add_macip_for_intf(vrr_if, zvni);
- }
+ /* Add VRR MAC-IP - if any*/
+ vrr_if = zebra_get_vrr_intf_for_svi(vlan_if);
+ if (vrr_if)
+ zvni_add_macip_for_intf(vrr_if, zvni);
neigh_read_for_vlan(zns, vlan_if);
}
/*
* Cleanup VNI/VTEP and update kernel
*/
-static void zvni_cleanup_all(struct hash_backet *backet, void *zvrf)
+static void zvni_cleanup_all(struct hash_backet *backet, void *arg)
{
zebra_vni_t *zvni = NULL;
zebra_l3vni_t *zl3vni = NULL;
+ struct zebra_vrf *zvrf = (struct zebra_vrf *)arg;
zvni = (zebra_vni_t *)backet->data;
if (!zvni)
return;
/* remove from l3-vni list */
- zl3vni = zl3vni_from_vrf(zvni->vrf_id);
+ if (zvrf->l3vni)
+ zl3vni = zl3vni_lookup(zvrf->l3vni);
if (zl3vni)
listnode_delete(zl3vni->l2vnis, zvni);
static int zl3vni_nh_uninstall(zebra_l3vni_t *zl3vni,
zebra_neigh_t *n)
{
- if (!is_l3vni_oper_up(zl3vni))
- return -1;
-
if (!(n->flags & ZEBRA_NEIGH_REMOTE) ||
!(n->flags & ZEBRA_NEIGH_REMOTE_NH))
return 0;
+ if (!zl3vni->svi_if || !if_is_operative(zl3vni->svi_if))
+ return 0;
+
return kernel_del_neigh(zl3vni->svi_if, &n->ip);
}
zl3vni_nh_del(zl3vni, n);
}
+static int ip_prefix_send_to_client(vrf_id_t vrf_id,
+ struct prefix *p,
+ uint16_t cmd)
+{
+ struct zserv *client = NULL;
+ struct stream *s = NULL;
+ char buf[PREFIX_STRLEN];
+
+ client = zebra_find_client(ZEBRA_ROUTE_BGP, 0);
+ /* BGP may not be running. */
+ if (!client)
+ return 0;
+
+ s = client->obuf;
+ stream_reset(s);
+
+ zclient_create_header(s, cmd, vrf_id);
+ stream_put(s, p, sizeof(struct prefix));
+
+ /* Write packet size. */
+ stream_putw_at(s, 0, stream_get_endp(s));
+
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug(
+ "Send ip 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)
+ client->prefixadd_cnt++;
+ else
+ client->prefixdel_cnt++;
+
+ return zebra_server_send_message(client);
+}
+
+/* re-add remote rmac if needed */
+static int zebra_vxlan_readd_remote_rmac(zebra_l3vni_t *zl3vni,
+ struct ethaddr *rmac)
+{
+ char buf[ETHER_ADDR_STRLEN];
+ zebra_mac_t *zrmac = NULL;
+
+ zrmac = zl3vni_rmac_lookup(zl3vni, rmac);
+ if (!zrmac)
+ return 0;
+
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug("Del remote RMAC %s L3VNI %u - readd",
+ prefix_mac2str(rmac, buf, sizeof(buf)),
+ zl3vni->vni);
+
+ zl3vni_rmac_install(zl3vni, zrmac);
+ return 0;
+}
+
/* Public functions */
/* handle evpn route in vrf table */
vty_out(vty,
"Number of Remote RMACs known for this VNI: %u\n",
num_rmacs);
- vty_out(vty, "%-17s %-21s %-6s\n", "MAC",
- "Remote VTEP", "Refcnt");
+ vty_out(vty, "%-17s %-21s\n", "MAC", "Remote VTEP");
} else
json_object_int_add(json, "numRmacs", num_rmacs);
vty_out(vty,
"Number of NH Neighbors known for this VNI: %u\n",
num_nh);
- vty_out(vty, "%-15s %-17s %6s\n", "IP",
- "RMAC", "Refcnt");
+ vty_out(vty, "%-15s %-17s\n", "IP", "RMAC");
} else
- json_object_int_add(json, "numNh", num_nh);
+ json_object_int_add(json, "numNextHops", num_nh);
hash_iterate(zl3vni->nh_table, zl3vni_print_nh_hash, &wctx);
}
}
-/*
- * Display L3 VNI hash table (VTY command handler).
- */
-void zebra_vxlan_print_l3vnis(struct vty *vty, u_char use_json)
+void zebra_vxlan_print_vrf_vni(struct vty *vty, struct zebra_vrf *zvrf,
+ json_object *json_vrfs)
{
- u_int32_t num_vnis;
- void *args[2];
- json_object *json = NULL;
- struct zebra_ns *zns = NULL;
-
- if (!is_evpn_enabled()) {
- if (use_json)
- vty_out(vty, "{}\n");
- return;
- }
-
- zns = zebra_ns_lookup(NS_DEFAULT);
- assert(zns);
+ char buf[ETHER_ADDR_STRLEN];
+ zebra_l3vni_t *zl3vni = NULL;
- num_vnis = hashcount(zns->l3vni_table);
- if (!num_vnis) {
- if (use_json)
- vty_out(vty, "{}\n");
+ zl3vni = zl3vni_lookup(zvrf->l3vni);
+ if (!zl3vni)
return;
- }
- if (use_json) {
- json = json_object_new_object();
- json_object_int_add(json, "numVnis", num_vnis);
+ if (!json_vrfs) {
+ vty_out(vty, "%-37s %-10u %-20s %-20s %-5s %-18s\n",
+ zvrf_name(zvrf),
+ zl3vni->vni,
+ zl3vni_vxlan_if_name(zl3vni),
+ zl3vni_svi_if_name(zl3vni),
+ zl3vni_state2str(zl3vni),
+ zl3vni_rmac2str(zl3vni, buf, sizeof(buf)));
} else {
- vty_out(vty, "Number of L3 VNIs: %u\n", num_vnis);
- vty_out(vty, "%-10s %-15s %-20s %-20s %-5s %-37s %-18s\n",
- "VNI", "Local-ip", "Vx-intf", "L3-SVI", "State",
- "VRF", "Rmac");
- }
-
- args[0] = vty;
- args[1] = json;
- hash_iterate(zns->l3vni_table,
- (void (*)(struct hash_backet *, void *))zl3vni_print_hash,
- args);
-
- if (use_json) {
- vty_out(vty, "%s\n", json_object_to_json_string_ext(
- json, JSON_C_TO_STRING_PRETTY));
- json_object_free(json);
+ 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, "vni", zl3vni->vni);
+ json_object_string_add(json_vrf, "vxlanIntf",
+ zl3vni_vxlan_if_name(zl3vni));
+ json_object_string_add(json_vrf, "sviIntf",
+ zl3vni_svi_if_name(zl3vni));
+ json_object_string_add(json_vrf, "state",
+ zl3vni_state2str(zl3vni));
+ json_object_string_add(json_vrf, "routerMac",
+ zl3vni_rmac2str(zl3vni, buf,
+ sizeof(buf)));
+ json_object_array_add(json_vrfs, json_vrf);
}
}
void zebra_vxlan_print_vni(struct vty *vty, struct zebra_vrf *zvrf, vni_t vni,
u_char use_json)
{
- zebra_vni_t *zvni;
json_object *json = NULL;
void *args[2];
if (!is_evpn_enabled())
return;
- zvni = zvni_lookup(vni);
- if (!zvni) {
- if (use_json)
- vty_out(vty, "{}\n");
- else
- vty_out(vty, "%% VNI %u does not exist\n", vni);
- return;
- }
+
if (use_json)
json = json_object_new_object();
args[0] = vty;
args[1] = json;
- zvni_print(zvni, (void *)args);
+
+ if (is_vni_l3(vni)) {
+ zebra_l3vni_t *zl3vni = NULL;
+
+ zl3vni = zl3vni_lookup(vni);
+ if (!zl3vni) {
+ if (use_json)
+ vty_out(vty, "{}\n");
+ else
+ vty_out(vty, "%% VNI %u does not exist\n", vni);
+ return;
+ }
+
+ zl3vni_print(zl3vni, (void *)args);
+ } else {
+ zebra_vni_t *zvni;
+
+ zvni = zvni_lookup(vni);
+ if (!zvni) {
+ if (use_json)
+ vty_out(vty, "{}\n");
+ else
+ vty_out(vty, "%% VNI %u does not exist\n", vni);
+ return;
+ }
+
+ zvni_print(zvni, (void *)args);
+ }
+
if (use_json) {
vty_out(vty, "%s\n", json_object_to_json_string_ext(
json, JSON_C_TO_STRING_PRETTY));
}
}
-/*
- * Display VNI hash table (VTY command handler).
- */
-void zebra_vxlan_print_vnis(struct vty *vty, struct zebra_vrf *zvrf,
- u_char use_json)
+/* Display all global details for EVPN */
+void zebra_vxlan_print_evpn(struct vty *vty, u_char uj)
{
- u_int32_t num_vnis;
+ int num_l2vnis = 0;
+ int num_l3vnis = 0;
+ int num_vnis = 0;
json_object *json = NULL;
- void *args[2];
+ struct zebra_ns *zns = NULL;
+ struct zebra_vrf *zvrf = NULL;
if (!is_evpn_enabled())
return;
- num_vnis = hashcount(zvrf->vni_table);
- if (!num_vnis) {
- if (use_json)
- vty_out(vty, "{}\n");
+
+ zns = zebra_ns_lookup(NS_DEFAULT);
+ if (!zns)
return;
- }
- if (use_json) {
+
+ zvrf = vrf_info_lookup(VRF_DEFAULT);
+ if (!zvrf)
+ return;
+
+ num_l3vnis = hashcount(zns->l3vni_table);
+ num_l2vnis = hashcount(zvrf->vni_table);
+ num_vnis = num_l2vnis + num_l3vnis;
+
+ if (uj) {
json = json_object_new_object();
json_object_string_add(json, "advertiseGatewayMacip",
zvrf->advertise_gw_macip ? "Yes" : "No");
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, "L2 VNIs: %u\n", num_l2vnis);
+ vty_out(vty, "L3 VNIs: %u\n", num_l3vnis);
vty_out(vty, "Advertise gateway mac-ip: %s\n",
zvrf->advertise_gw_macip ? "Yes" : "No");
- vty_out(vty, "Number of VNIs: %u\n", num_vnis);
- vty_out(vty, "%-10s %-21s %-15s %-8s %-8s %-15s %-37s\n", "VNI",
- "VxLAN IF", "VTEP IP", "# MACs", "# ARPs",
- "# Remote VTEPs", "VRF");
}
+
+ if (uj) {
+ vty_out(vty, "%s\n", json_object_to_json_string_ext(
+ json, JSON_C_TO_STRING_PRETTY));
+ json_object_free(json);
+ }
+}
+
+/*
+ * Display VNI hash table (VTY command handler).
+ */
+void zebra_vxlan_print_vnis(struct vty *vty, struct zebra_vrf *zvrf,
+ u_char use_json)
+{
+ json_object *json = NULL;
+ struct zebra_ns *zns = NULL;
+ void *args[2];
+
+ if (!is_evpn_enabled())
+ return;
+
+ zns = zebra_ns_lookup(NS_DEFAULT);
+ if (!zns)
+ return;
+
+
+ if (use_json)
+ json = json_object_new_object();
+ else
+ vty_out(vty,
+ "%-10s %-4s %-21s %-8s %-8s %-15s %-37s\n",
+ "VNI", "Type", "VxLAN IF", "# MACs",
+ "# ARPs", "# Remote VTEPs", "Tenant VRF");
+
args[0] = vty;
args[1] = json;
+ /* Display all L2-VNIs */
hash_iterate(zvrf->vni_table,
(void (*)(struct hash_backet *, void *))zvni_print_hash,
args);
+ /* Display all L3-VNIs */
+ hash_iterate(zns->l3vni_table,
+ (void (*)(struct hash_backet *, void *))zl3vni_print_hash,
+ args);
+
if (use_json) {
vty_out(vty, "%s\n", json_object_to_json_string_ext(
json, JSON_C_TO_STRING_PRETTY));
zvni->vni);
ZEBRA_NEIGH_SET_ACTIVE(n);
- return zvni_neigh_send_add_to_client(zvni->vni, ip, macaddr, 0);
+ return zvni_neigh_send_add_to_client(zvni->vni, ip, macaddr, n->flags);
}
if (!mac && !n)
continue;
+ /* Ignore the delete if this mac is a gateway mac-ip */
+ if (mac && CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL) &&
+ CHECK_FLAG(mac->flags, ZEBRA_MAC_DEF_GW)) {
+ zlog_err("%u: Ignore Del for MAC %s neigh %s on VNI %u as it is configured as a default gateway",
+ zvrf_id(zvrf),
+ prefix_mac2str(&macaddr, buf, sizeof(buf)),
+ ipaddr2str(&ip, buf1, sizeof(buf1)),
+ vni);
+ continue;
+ }
+
/* Uninstall remote neighbor or MAC. */
if (n) {
/* When the MAC changes for an IP, it is possible the
int update_mac = 0, update_neigh = 0;
char buf[ETHER_ADDR_STRLEN];
char buf1[INET6_ADDRSTRLEN];
- u_char sticky;
+ u_char sticky = 0;
+ u_char flags = 0;
struct interface *ifp = NULL;
struct zebra_if *zif = NULL;
STREAM_GET(&vtep_ip.s_addr, s, IPV4_MAX_BYTELEN);
l += IPV4_MAX_BYTELEN;
- /* Get 'sticky' flag. */
- STREAM_GETC(s, sticky);
+ /* Get flags - sticky mac and/or gateway mac */
+ flags = stream_getc(s);
+ sticky = CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY);
l++;
if (IS_ZEBRA_DEBUG_VXLAN)
zlog_debug(
- "Recv MACIP Add %sMAC %s IP %s VNI %u Remote VTEP %s from %s",
- sticky ? "sticky " : "",
+ "Recv MACIP Add MAC %s IP %s VNI %u Remote VTEP %s with flags 0x%x from %s",
prefix_mac2str(&macaddr, buf, sizeof(buf)),
ipaddr2str(&ip, buf1, sizeof(buf1)), vni,
- inet_ntoa(vtep_ip),
+ inet_ntoa(vtep_ip), flags,
zebra_route_string(client->proto));
/* Locate VNI hash entry - expected to exist. */
zvni_vtep_install(zvni, &vtep_ip);
}
- /* First, check if the remote MAC is unknown or has a change. If
- * so,
- * that needs to be updated first. Note that client could
- * install
- * MAC and MACIP separately or just install the latter.
- */
mac = zvni_mac_lookup(zvni, &macaddr);
+
+ /* Ignore the update if the mac is already present
+ as a gateway mac */
+ if (mac && CHECK_FLAG(mac->flags, ZEBRA_MAC_DEF_GW) &&
+ CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_GW)) {
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug("%u:Ignore MAC %s IP %s on VNI %u as MAC is already configured as gateway mac",
+ zvrf_id(zvrf),
+ prefix_mac2str(&macaddr,
+ buf, sizeof(buf)),
+ ipaddr2str(&ip, buf1,
+ sizeof(buf1)), vni);
+ continue;
+ }
+
+ /* check if the remote MAC is unknown or has a change.
+ * If so, that needs to be updated first. Note that client could
+ * install MAC and MACIP separately or just install the latter.
+ */
if (!mac || !CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)
|| (CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY) ? 1 : 0)
!= sticky
zebra_vni_t *zvni;
zebra_mac_t *mac;
char buf[ETHER_ADDR_STRLEN];
- u_char sticky;
zif = ifp->info;
assert(zif);
ifp->name, ifp->ifindex, vni);
/* Remove MAC from BGP. */
- sticky = CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY) ? 1 : 0;
- zvni_mac_send_del_to_client(zvni->vni, macaddr,
- (sticky ? ZEBRA_MAC_TYPE_STICKY : 0));
+ zvni_mac_send_del_to_client(zvni->vni, macaddr, mac->flags);
/*
* If there are no neigh associated with the mac delete the mac
struct interface *br_if,
struct ethaddr *macaddr, vlanid_t vid)
{
- struct zebra_if *zif;
- struct zebra_l2info_vxlan *vxl;
+ struct zebra_if *zif = NULL;
+ struct zebra_l2info_vxlan *vxl = NULL;
vni_t vni;
- zebra_vni_t *zvni;
- zebra_mac_t *mac;
+ zebra_vni_t *zvni = NULL;
+ zebra_l3vni_t *zl3vni = NULL;
+ zebra_mac_t *mac = NULL;
char buf[ETHER_ADDR_STRLEN];
zif = ifp->info;
if (!is_evpn_enabled())
return 0;
+ /* check if this is a remote RMAC and readd simillar to remote macs */
+ zl3vni = zl3vni_lookup(vni);
+ if (zl3vni)
+ return zebra_vxlan_readd_remote_rmac(zl3vni, macaddr);
+
/* Locate hash entry; it is expected to exist. */
zvni = zvni_lookup(vni);
if (!zvni)
zebra_vni_t *zvni;
zebra_mac_t *mac;
char buf[ETHER_ADDR_STRLEN];
- u_char sticky;
/* We are interested in MACs only on ports or (port, VLAN) that
* map to a VNI.
return 0;
/* Remove MAC from BGP. */
- sticky = CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY) ? 1 : 0;
- zvni_mac_send_del_to_client(zvni->vni, macaddr,
- (sticky ? ZEBRA_MAC_TYPE_STICKY : 0));
+ zvni_mac_send_del_to_client(zvni->vni, macaddr, mac->flags);
/* Update all the neigh entries associated with this mac */
zvni_process_neigh_on_local_mac_del(zvni, mac);
if (add) {
zvni_process_neigh_on_local_mac_add(zvni, mac);
return zvni_mac_send_add_to_client(zvni->vni, macaddr,
- sticky);
+ mac->flags);
}
return 0;
}
- /* check if we are advertising gw macip routes */
- if (!advertise_gw_macip_enabled(zvni))
- return 0;
-
memcpy(&macaddr.octet, ifp->hw_addr, ETH_ALEN);
if (p->family == AF_INET) {
return 0;
}
-int zebra_vxlan_vrf_delete(struct zebra_vrf *zvrf)
+int zebra_vxlan_vrf_enable(struct zebra_vrf *zvrf)
{
zebra_l3vni_t *zl3vni = NULL;
- zl3vni = zl3vni_from_vrf(zvrf_id(zvrf));
+ if (zvrf->l3vni)
+ zl3vni = zl3vni_lookup(zvrf->l3vni);
if (!zl3vni)
return 0;
+ zl3vni->vrf_id = zvrf_id(zvrf);
+ if (is_l3vni_oper_up(zl3vni))
+ zebra_vxlan_process_l3vni_oper_up(zl3vni);
+ return 0;
+}
+
+int zebra_vxlan_vrf_disable(struct zebra_vrf *zvrf)
+{
+ zebra_l3vni_t *zl3vni = NULL;
+
+ if (zvrf->l3vni)
+ zl3vni = zl3vni_lookup(zvrf->l3vni);
+ if (!zl3vni)
+ return 0;
+
+ zl3vni->vrf_id = VRF_UNKNOWN;
zebra_vxlan_process_l3vni_oper_down(zl3vni);
+ return 0;
+}
+
+int zebra_vxlan_vrf_delete(struct zebra_vrf *zvrf)
+{
+ zebra_l3vni_t *zl3vni = NULL;
+ vni_t vni;
+
+ if (zvrf->l3vni)
+ zl3vni = zl3vni_lookup(zvrf->l3vni);
+ if (!zl3vni)
+ return 0;
+
+ vni = zl3vni->vni;
zl3vni_del(zl3vni);
- zebra_vxlan_handle_vni_transition(zvrf, zl3vni->vni, 0);
+ zebra_vxlan_handle_vni_transition(zvrf, vni, 0);
+
+ return 0;
+}
+
+/*
+ * Handle message from client to enable/disable advertisement of g/w macip
+ * routes
+ */
+int zebra_vxlan_advertise_subnet(struct zserv *client, u_short length,
+ struct zebra_vrf *zvrf)
+{
+ struct stream *s;
+ int advertise;
+ vni_t vni = 0;
+ zebra_vni_t *zvni = NULL;
+ struct interface *ifp = NULL;
+ struct zebra_if *zif = NULL;
+ struct zebra_l2info_vxlan zl2_info;
+ struct interface *vlan_if = NULL;
+
+ if (zvrf_id(zvrf) != VRF_DEFAULT) {
+ zlog_err("EVPN GW-MACIP Adv for non-default VRF %u",
+ zvrf_id(zvrf));
+ return -1;
+ }
+
+ s = client->ibuf;
+ advertise = stream_getc(s);
+ vni = stream_get3(s);
+
+ zvni = zvni_lookup(vni);
+ if (!zvni)
+ return 0;
+
+ if (zvni->advertise_subnet == advertise)
+ return 0;
+
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug(
+ "EVPN subnet Adv %s on VNI %d , currently %s",
+ advertise ? "enabled" : "disabled", vni,
+ zvni->advertise_subnet ? "enabled" : "disabled");
+
+
+ zvni->advertise_subnet = advertise;
+
+ ifp = zvni->vxlan_if;
+ if (!ifp)
+ return 0;
+
+ zif = ifp->info;
+
+ /* If down or not mapped to a bridge, we're done. */
+ if (!if_is_operative(ifp) || !zif->brslave_info.br_if)
+ return 0;
+
+ zl2_info = zif->l2info.vxl;
+
+ vlan_if = zvni_map_to_svi(zl2_info.access_vlan,
+ zif->brslave_info.br_if);
+ if (!vlan_if)
+ return 0;
+
+ if (zvni->advertise_subnet)
+ zvni_advertise_subnet(zvni, vlan_if, 1);
+ else
+ zvni_advertise_subnet(zvni, vlan_if, 0);
return 0;
}
"Zebra VRF VNI Table");
}
+/* Cleanup VNI info, but don't free the table. */
+void zebra_vxlan_cleanup_tables(struct zebra_vrf *zvrf)
+{
+ if (!zvrf)
+ return;
+ hash_iterate(zvrf->vni_table, zvni_cleanup_all, zvrf);
+}
+
/* Close all VNI handling */
void zebra_vxlan_close_tables(struct zebra_vrf *zvrf)
{
#include "vlan.h"
#include "vxlan.h"
+#include "lib/json.h"
#include "zebra/zebra_vrf.h"
/* 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);
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);
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);
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,
{
}
+void zebra_vxlan_print_evpn(struct vty *vty, u_char uj)
+{
+}
+
void zebra_vxlan_print_rmacs_l3vni(struct vty*, vni_t, u_char)
{
}
{
}
-void zebra_vxlan_print_l3vnis(struct vty *vty)
-{
-}
-
int zebra_vxlan_svi_up(struct interface *ifp, struct interface *link_if)
{
return 0;
void zebra_vxlan_close_tables(struct zebra_vrf *zvrf)
{
}
+
+void zebra_vxlan_cleanup_tables(struct zebra_vrf *zvrf)
+{
+}
/* 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;
#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 {
#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;
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;
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;