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