for (ALL_LIST_ELEMENTS(vpn->export_rtl, node, nnode, ecom))
attr->ecommunity = ecommunity_merge(attr->ecommunity, ecom);
- /* Add the export RTs for L3VNI - currently only supported for IPV4 host
- * routes
+ /*
+ * only attach l3-vni export rts for ipv4 address family and if we are
+ * advertising both the labels in type-2 routes
*/
- if (afi == AFI_IP) {
+ if (afi == AFI_IP && CHECK_FLAG(vpn->flags, VNI_FLAG_USE_TWO_LABELS)) {
vrf_export_rtl = bgpevpn_get_vrf_export_rtl(vpn);
if (vrf_export_rtl && !list_isempty(vrf_export_rtl)) {
for (ALL_LIST_ELEMENTS(vrf_export_rtl, node, nnode,
ecommunity_merge(attr->ecommunity, &ecom_sticky);
}
- if (afi == AFI_IP && !is_zero_mac(&attr->rmac)) {
+ /*
+ * only attach l3-vni rmac for ipv4 address family and if we are
+ * advertising both the labels in type-2 routes
+ */
+ if (afi == AFI_IP && !is_zero_mac(&attr->rmac) &&
+ CHECK_FLAG(vpn->flags, VNI_FLAG_USE_TWO_LABELS)) {
memset(&ecom_rmac, 0, sizeof(ecom_rmac));
encode_rmac_extcomm(&eval_rmac, &attr->rmac);
ecom_rmac.size = 1;
/* The VNI goes into the 'label' field of the route */
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) {
+
+ /* Type-2 routes may carry a second VNI - the L3-VNI.
+ * Only attach second label if we are advertising two labels for
+ * type-2 routes.
+ */
+ if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE &&
+ CHECK_FLAG(vpn->flags, VNI_FLAG_USE_TWO_LABELS)) {
vni_t l3vni;
l3vni = bgpevpn_get_l3vni(vpn);
&& !CHECK_FLAG(tmp_ri->flags, BGP_INFO_REMOVED))
route_change = 0;
else {
+ /*
+ * The attributes have changed, type-2 routes needs to
+ * be advertised with right labels.
+ */
+ vni2label(vpn->vni, &label[0]);
+ if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE &&
+ CHECK_FLAG(vpn->flags, VNI_FLAG_USE_TWO_LABELS)) {
+ vni_t l3vni;
+
+ l3vni = bgpevpn_get_l3vni(vpn);
+ if (l3vni) {
+ vni2label(l3vni, &label[1]);
+ num_labels++;
+ }
+ }
+ memcpy(&tmp_ri->extra->label, label, sizeof(label));
+ tmp_ri->extra->num_labels = num_labels;
+
/* The attribute has changed. */
/* Add (or update) attribute to hash. */
attr_new = bgp_attr_intern(attr);
int bgp_evpn_local_l3vni_add(vni_t l3vni,
vrf_id_t vrf_id,
struct ethaddr *rmac,
- struct in_addr originator_ip)
+ struct in_addr originator_ip,
+ int filter)
{
struct bgp *bgp_vrf = NULL; /* bgp VRF instance */
struct bgp *bgp_def = NULL; /* default bgp instance */
/* set the originator ip */
bgp_vrf->originator_ip = originator_ip;
+ /* set the right filter - are we using l3vni only for prefix routes? */
+ if (filter)
+ SET_FLAG(bgp_vrf->vrf_flags, BGP_VRF_L3VNI_PREFIX_ROUTES_ONLY);
+
/* auto derive RD/RT */
if (!CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_IMPORT_RT_CFGD))
evpn_auto_rt_import_add_for_vrf(bgp_vrf);
link_l2vni_hash_to_l3vni,
bgp_vrf);
- /* updates all corresponding local mac-ip routes */
- for (ALL_LIST_ELEMENTS_RO(bgp_vrf->l2vnis, node, vpn))
- update_routes_for_vni(bgp_def, vpn);
+ /* Only update all corresponding type-2 routes if we are advertising two
+ * labels along with type-2 routes
+ */
+ if (!filter)
+ for (ALL_LIST_ELEMENTS_RO(bgp_vrf->l2vnis, node, vpn))
+ update_routes_for_vni(bgp_def, vpn);
/* advertise type-5 routes if needed */
update_advertise_vrf_routes(bgp_vrf);
}
/* update all corresponding local mac-ip routes */
- for (ALL_LIST_ELEMENTS_RO(bgp_vrf->l2vnis, node, vpn))
- update_routes_for_vni(bgp_def, vpn);
-
+ if (!CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_L3VNI_PREFIX_ROUTES_ONLY)) {
+ for (ALL_LIST_ELEMENTS_RO(bgp_vrf->l2vnis, node, vpn)) {
+ UNSET_FLAG(vpn->flags, VNI_FLAG_USE_TWO_LABELS);
+ update_routes_for_vni(bgp_def, vpn);
+ }
+ }
/* Delete the instance if it was autocreated */
if (CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_AUTO))
u_char flags);
extern int bgp_evpn_local_l3vni_add(vni_t vni, vrf_id_t vrf_id,
struct ethaddr *rmac,
- struct in_addr originator_ip);
+ struct in_addr originator_ip,
+ int filter);
extern int bgp_evpn_local_l3vni_del(vni_t vni, vrf_id_t vrf_id);
extern int bgp_evpn_local_vni_del(struct bgp *bgp, vni_t vni);
extern int bgp_evpn_local_vni_add(struct bgp *bgp, vni_t vni,
#define VNI_FLAG_RD_CFGD 0x4 /* RD is user configured. */
#define VNI_FLAG_IMPRT_CFGD 0x8 /* Import RT is user configured */
#define VNI_FLAG_EXPRT_CFGD 0x10 /* Export RT is user configured */
+#define VNI_FLAG_USE_TWO_LABELS 0x20 /* Attach both L2-VNI and L3-VNI if
+ needed for this VPN */
/* Flag to indicate if we are advertising the g/w mac ip for this VNI*/
u_int8_t advertise_gw_macip;
struct bgp *bgp_vrf = NULL;
bgp_vrf = bgp_lookup_by_vrf_id(vpn->tenant_vrf_id);
- if (!bgp_vrf || !bgp_vrf->l2vnis)
+ if (!bgp_vrf)
return;
- listnode_delete(bgp_vrf->l2vnis, vpn);
+
+ UNSET_FLAG(vpn->flags, VNI_FLAG_USE_TWO_LABELS);
+
+ if (bgp_vrf->l2vnis)
+ listnode_delete(bgp_vrf->l2vnis, vpn);
}
static inline void bgpevpn_link_to_l3vni(struct bgpevpn *vpn)
struct bgp *bgp_vrf = NULL;
bgp_vrf = bgp_lookup_by_vrf_id(vpn->tenant_vrf_id);
- if (!bgp_vrf || !bgp_vrf->l2vnis)
+ if (!bgp_vrf)
return;
- listnode_add_sort(bgp_vrf->l2vnis, vpn);
+
+ /* check if we are advertising two labels for this vpn */
+ if (!CHECK_FLAG(bgp_vrf->vrf_flags,
+ BGP_VRF_L3VNI_PREFIX_ROUTES_ONLY))
+ SET_FLAG(vpn->flags, VNI_FLAG_USE_TWO_LABELS);
+
+ if (bgp_vrf->l2vnis)
+ listnode_add_sort(bgp_vrf->l2vnis, vpn);
}
static inline int is_vni_configured(struct bgpevpn *vpn)
vty_out(vty, " L3-VNI: %u\n", bgp->l3vni);
vty_out(vty, " Rmac: %s\n",
prefix_mac2str(&bgp->rmac, buf, sizeof(buf)));
+ vty_out(vty, " VNI Filter: %s\n",
+ CHECK_FLAG(bgp->vrf_flags,
+ BGP_VRF_L3VNI_PREFIX_ROUTES_ONLY) ?
+ "prefix-routes-only" : "none");
vty_out(vty, " L2-VNI List:\n");
vty_out(vty, " ");
for (ALL_LIST_ELEMENTS_RO(bgp->l2vnis, node, vpn))
json_object_string_add(json, "rmac",
prefix_mac2str(&bgp->rmac, buf,
sizeof(buf)));
+ json_object_string_add(json, "vniFilter",
+ CHECK_FLAG(bgp->vrf_flags,
+ BGP_VRF_L3VNI_PREFIX_ROUTES_ONLY)
+ ? "prefix-routes-only" : "none");
/* list of l2vnis */
for (ALL_LIST_ELEMENTS_RO(bgp->l2vnis, node, vpn))
json_object_array_add(json_vnis,
static int bgp_zebra_process_local_l3vni(int cmd, struct zclient *zclient,
zebra_size_t length, vrf_id_t vrf_id)
{
+ int filter = 0;
char buf[ETHER_ADDR_STRLEN];
vni_t l3vni = 0;
struct ethaddr rmac;
if (cmd == ZEBRA_L3VNI_ADD) {
stream_get(&rmac, s, sizeof(struct ethaddr));
originator_ip.s_addr = stream_get_ipv4(s);
+ stream_get(&filter, s, sizeof(int));
}
if (BGP_DEBUG(zebra, ZEBRA))
- zlog_debug("Rx L3-VNI %s VRF %s VNI %u RMAC %s",
+ zlog_debug("Rx L3-VNI %s VRF %s VNI %u RMAC %s filter %s",
(cmd == ZEBRA_L3VNI_ADD) ? "add" : "del",
- vrf_id_to_name(vrf_id), l3vni,
- prefix_mac2str(&rmac, buf, sizeof(buf)));
+ vrf_id_to_name(vrf_id),
+ l3vni,
+ prefix_mac2str(&rmac, buf, sizeof(buf)),
+ filter ? "prefix-routes-only" : "none");
if (cmd == ZEBRA_L3VNI_ADD)
- bgp_evpn_local_l3vni_add(l3vni, vrf_id, &rmac, originator_ip);
+ bgp_evpn_local_l3vni_add(l3vni, vrf_id, &rmac, originator_ip,
+ filter);
else
bgp_evpn_local_l3vni_del(l3vni, vrf_id);
#define BGP_VRF_IMPORT_RT_CFGD (1 << 3)
#define BGP_VRF_EXPORT_RT_CFGD (1 << 4)
#define BGP_VRF_RD_CFGD (1 << 5)
+#define BGP_VRF_L3VNI_PREFIX_ROUTES_ONLY (1 << 6)
/* unique ID for auto derivation of RD for this vrf */
uint16_t vrf_rd_id;
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, " vni %u%s\n",
+ zvrf->l3vni,
+ is_l3vni_for_prefix_routes_only(zvrf->l3vni) ?
+ " prefix-routes-only" :"");
vty_out(vty, "!\n");
}
DEFUN (default_vrf_vni_mapping,
default_vrf_vni_mapping_cmd,
- "vni " CMD_VNI_RANGE,
+ "vni " CMD_VNI_RANGE "[prefix-routes-only]",
"VNI corresponding to the DEFAULT VRF\n"
- "VNI-ID\n")
+ "VNI-ID\n"
+ "Prefix routes only \n")
{
int ret = 0;
char err[ERR_STR_SZ];
struct zebra_vrf *zvrf = NULL;
vni_t vni = strtoul(argv[1]->arg, NULL, 10);
+ int filter = 0;
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 (argc == 3)
+ filter = 1;
+
+ ret = zebra_vxlan_process_vrf_vni_cmd(zvrf, vni, err, ERR_STR_SZ,
+ filter, 1);
if (ret != 0) {
vty_out(vty, "%s\n", err);
return CMD_WARNING;
if (!zvrf)
return CMD_WARNING;
- ret = zebra_vxlan_process_vrf_vni_cmd(zvrf, vni, err, ERR_STR_SZ, 0);
+ ret = zebra_vxlan_process_vrf_vni_cmd(zvrf, vni, err, ERR_STR_SZ, 0, 0);
if (ret != 0) {
vty_out(vty, "%s\n", err);
return CMD_WARNING;
DEFUN (vrf_vni_mapping,
vrf_vni_mapping_cmd,
- "vni " CMD_VNI_RANGE,
+ "vni " CMD_VNI_RANGE "[prefix-routes-only]",
"VNI corresponding to tenant VRF\n"
- "VNI-ID\n")
+ "VNI-ID\n"
+ "prefix-routes-only\n")
{
int ret = 0;
+ int filter = 0;
ZEBRA_DECLVAR_CONTEXT(vrf, zvrf);
vni_t vni = strtoul(argv[1]->arg, NULL, 10);
assert(vrf);
assert(zvrf);
+ if (argc == 3)
+ filter = 1;
+
/* Mark as having FRR configuration */
vrf_set_user_cfged(vrf);
- ret = zebra_vxlan_process_vrf_vni_cmd(zvrf, vni, err, ERR_STR_SZ, 1);
+ ret = zebra_vxlan_process_vrf_vni_cmd(zvrf, vni, err, ERR_STR_SZ,
+ filter, 1);
if (ret != 0) {
vty_out(vty, "%s\n", err);
return CMD_WARNING;
assert(vrf);
assert(zvrf);
- ret = zebra_vxlan_process_vrf_vni_cmd(zvrf, vni, err, ERR_STR_SZ, 0);
+ ret = zebra_vxlan_process_vrf_vni_cmd(zvrf, vni, err, ERR_STR_SZ, 0, 0);
if (ret != 0) {
vty_out(vty, "%s\n", err);
return CMD_WARNING;
zl3vni_svi_if_name(zl3vni));
vty_out(vty, " State: %s\n",
zl3vni_state2str(zl3vni));
+ vty_out(vty, " VNI Filter: %s\n",
+ CHECK_FLAG(zl3vni->filter, PREFIX_ROUTES_ONLY) ?
+ "prefix-routes-only" : "none");
vty_out(vty, " Router MAC: %s\n",
zl3vni_rmac2str(zl3vni, buf, sizeof(buf)));
vty_out(vty, " L2 VNIs: ");
json_object_string_add(json, "routerMac",
zl3vni_rmac2str(zl3vni, buf,
sizeof(buf)));
+ json_object_string_add(json, "vniFilter",
+ CHECK_FLAG(zl3vni->filter,
+ PREFIX_ROUTES_ONLY) ?
+ "prefix-routes-only" : "none");
for (ALL_LIST_ELEMENTS(zl3vni->l2vnis, node, nnode, zvni)) {
json_object_array_add(json_vni_list,
json_object_new_int(zvni->vni));
stream_putl(s, zl3vni->vni);
stream_put(s, &rmac, sizeof(struct ethaddr));
stream_put_in_addr(s, &zl3vni->local_vtep_ip);
+ stream_put(s, &zl3vni->filter, sizeof(int));
/* Write packet size. */
stream_putw_at(s, 0, stream_get_endp(s));
if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug("Send L3_VNI_ADD %u VRF %s RMAC %s local-ip %s to %s",
+ zlog_debug(
+ "Send L3_VNI_ADD %u VRF %s RMAC %s local-ip %s filter %s to %s",
zl3vni->vni, vrf_id_to_name(zl3vni_vrf_id(zl3vni)),
prefix_mac2str(&rmac, buf, sizeof(buf)),
inet_ntoa(zl3vni->local_vtep_ip),
+ CHECK_FLAG(zl3vni->filter, PREFIX_ROUTES_ONLY) ?
+ "prefix-routes-only" : "none",
zebra_route_string(client->proto));
client->l3vniadd_cnt++;
if (!zl3vni)
return;
- if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug("L3-VNI %u is UP - send add to BGP",
- zl3vni->vni);
-
/* send l3vni add to BGP */
zl3vni_send_add_to_client(zl3vni);
}
if (!zl3vni)
return;
- if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug("L3-VNI %u is Down - Send del to BGP",
- zl3vni->vni);
-
/* send l3-vni del to BGP*/
zl3vni_send_del_to_client(zl3vni);
}
/* Public functions */
+int is_l3vni_for_prefix_routes_only(vni_t vni)
+{
+ zebra_l3vni_t *zl3vni = NULL;
+
+ zl3vni = zl3vni_lookup(vni);
+ if (!zl3vni)
+ return 0;
+
+ return CHECK_FLAG(zl3vni->filter, PREFIX_ROUTES_ONLY) ? 1 : 0;
+}
+
/* handle evpn route in vrf table */
void zebra_vxlan_evpn_vrf_route_add(vrf_id_t vrf_id,
struct ethaddr *rmac,
int zebra_vxlan_process_vrf_vni_cmd(struct zebra_vrf *zvrf,
vni_t vni,
char *err, int err_str_sz,
- int add)
+ int filter, int add)
{
zebra_l3vni_t *zl3vni = NULL;
struct zebra_vrf *zvrf_default = NULL;
/* associate the vrf with vni */
zvrf->l3vni = vni;
+ /* set the filter in l3vni to denote if we are using l3vni only
+ * for prefix routes
+ */
+ if (filter)
+ SET_FLAG(zl3vni->filter, PREFIX_ROUTES_ONLY);
+
/* associate with vxlan-intf;
* we need to associate with the vxlan-intf first
*/
#define VNI_STR_LEN 32
+extern int is_l3vni_for_prefix_routes_only(vni_t vni);
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);
struct zebra_vrf *zvrf);
extern int zebra_vxlan_process_vrf_vni_cmd(struct zebra_vrf *zvrf, vni_t vni,
char *err,
- int err_str_sz, int add);
+ int err_str_sz, int filter, 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 *);
/* vrf_id */
vrf_id_t vrf_id;
+ uint32_t filter;
+#define PREFIX_ROUTES_ONLY (1 << 0) /* l3-vni used for prefix routes only */
+
/* Local IP */
struct in_addr local_vtep_ip;