summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--babeld/babel_interface.c26
-rw-r--r--bgpd/bgp_attr.c172
-rw-r--r--bgpd/bgp_attr.h4
-rw-r--r--bgpd/bgp_debug.c1
-rw-r--r--bgpd/bgp_evpn.c64
-rw-r--r--bgpd/bgp_evpn.h26
-rw-r--r--bgpd/bgp_evpn_mh.c4
-rw-r--r--bgpd/bgp_routemap.c102
-rw-r--r--bgpd/bgp_snmp_bgp4.c1
-rw-r--r--bgpd/bgp_snmp_bgp4v2.c1
-rw-r--r--bgpd/bgp_updgrp_adv.c10
-rw-r--r--bgpd/bgp_vty.c69
-rw-r--r--bgpd/bgp_zebra.c63
-rw-r--r--bgpd/bgpd.c20
-rw-r--r--bgpd/bgpd.h5
-rw-r--r--bgpd/rfapi/vnc_debug.c1
-rw-r--r--debian/changelog12
-rw-r--r--doc/user/basic.rst6
-rw-r--r--doc/user/bgp.rst5
-rw-r--r--doc/user/zebra.rst42
-rw-r--r--include/linux/if_bridge.h448
-rw-r--r--isisd/isis_spf.c5
-rw-r--r--lib/mpls.c11
-rw-r--r--lib/mpls.h39
-rw-r--r--lib/nexthop_group.c51
-rw-r--r--lib/nexthop_group.h2
-rw-r--r--lib/routemap.c67
-rw-r--r--lib/routemap.h4
-rw-r--r--lib/subdir.am1
-rw-r--r--lib/yang_translator.c14
-rw-r--r--lib/zclient.c3
-rw-r--r--lib/zclient.h1
-rw-r--r--lib/zebra.h50
-rw-r--r--ospfd/ospf_routemap.c29
-rw-r--r--ospfd/ospf_ti_lfa.c4
-rw-r--r--pathd/path_pcep_controller.c1
-rw-r--r--pathd/path_pcep_pcc.c1
-rw-r--r--pimd/pim6_mld.c3
-rw-r--r--pimd/pim_main.c1
-rw-r--r--redhat/frr.spec.in4
-rw-r--r--sharpd/sharp_zebra.c5
-rw-r--r--tests/ospfd/common.c3
-rw-r--r--tests/ospfd/test_ospf_spf.c2
-rw-r--r--tests/topotests/bgp_default_originate_withdraw/__init__.py0
-rw-r--r--tests/topotests/bgp_default_originate_withdraw/r1/bgpd.conf12
-rw-r--r--tests/topotests/bgp_default_originate_withdraw/r1/zebra.conf7
-rw-r--r--tests/topotests/bgp_default_originate_withdraw/r2/bgpd.conf9
-rw-r--r--tests/topotests/bgp_default_originate_withdraw/r2/zebra.conf4
-rw-r--r--tests/topotests/bgp_default_originate_withdraw/r3/bgpd.conf9
-rw-r--r--tests/topotests/bgp_default_originate_withdraw/r3/zebra.conf5
-rw-r--r--tests/topotests/bgp_default_originate_withdraw/test_bgp_default_originate_withdraw.py159
-rw-r--r--tests/topotests/bgp_evpn_vxlan_svd_topo1/P1/bgpd.conf1
-rw-r--r--tests/topotests/bgp_evpn_vxlan_svd_topo1/P1/ospfd.conf13
-rw-r--r--tests/topotests/bgp_evpn_vxlan_svd_topo1/P1/zebra.conf7
-rw-r--r--tests/topotests/bgp_evpn_vxlan_svd_topo1/PE1/bgpd.conf19
-rw-r--r--tests/topotests/bgp_evpn_vxlan_svd_topo1/PE1/evpn.vni.json16
-rw-r--r--tests/topotests/bgp_evpn_vxlan_svd_topo1/PE1/ospfd.conf9
-rw-r--r--tests/topotests/bgp_evpn_vxlan_svd_topo1/PE1/zebra.conf13
-rw-r--r--tests/topotests/bgp_evpn_vxlan_svd_topo1/PE2/bgpd.conf24
-rw-r--r--tests/topotests/bgp_evpn_vxlan_svd_topo1/PE2/evpn.vni.json15
-rw-r--r--tests/topotests/bgp_evpn_vxlan_svd_topo1/PE2/ospfd.conf9
-rw-r--r--tests/topotests/bgp_evpn_vxlan_svd_topo1/PE2/zebra.conf17
-rw-r--r--tests/topotests/bgp_evpn_vxlan_svd_topo1/__init__.py0
-rw-r--r--tests/topotests/bgp_evpn_vxlan_svd_topo1/host1/bgpd.conf1
-rw-r--r--tests/topotests/bgp_evpn_vxlan_svd_topo1/host1/ospfd.conf1
-rw-r--r--tests/topotests/bgp_evpn_vxlan_svd_topo1/host1/zebra.conf3
-rw-r--r--tests/topotests/bgp_evpn_vxlan_svd_topo1/host2/bgpd.conf1
-rw-r--r--tests/topotests/bgp_evpn_vxlan_svd_topo1/host2/ospfd.conf1
-rw-r--r--tests/topotests/bgp_evpn_vxlan_svd_topo1/host2/zebra.conf3
-rwxr-xr-xtests/topotests/bgp_evpn_vxlan_svd_topo1/test_bgp_evpn_vxlan_svd.py534
-rw-r--r--tests/topotests/bgp_path_attribute_treat_as_withdraw/__init__.py0
-rw-r--r--tests/topotests/bgp_path_attribute_treat_as_withdraw/r1/bgpd.conf14
-rw-r--r--tests/topotests/bgp_path_attribute_treat_as_withdraw/r1/zebra.conf4
-rw-r--r--tests/topotests/bgp_path_attribute_treat_as_withdraw/r2/bgpd.conf6
-rw-r--r--tests/topotests/bgp_path_attribute_treat_as_withdraw/r2/zebra.conf4
-rw-r--r--tests/topotests/bgp_path_attribute_treat_as_withdraw/test_bgp_path_attribute_treat_as_withdraw.py143
-rw-r--r--tests/topotests/lib/topotest.py23
-rw-r--r--vrrpd/vrrp.c3
-rw-r--r--zebra/dplane_fpm_nl.c14
-rw-r--r--zebra/if_netlink.c365
-rw-r--r--zebra/if_netlink.h3
-rw-r--r--zebra/interface.c170
-rw-r--r--zebra/interface.h1
-rw-r--r--zebra/kernel_netlink.c35
-rw-r--r--zebra/kernel_netlink.h4
-rw-r--r--zebra/redistribute.c6
-rw-r--r--zebra/rib.h3
-rw-r--r--zebra/rt.h5
-rw-r--r--zebra/rt_netlink.c282
-rw-r--r--zebra/rt_netlink.h5
-rw-r--r--zebra/rtread_netlink.c16
-rw-r--r--zebra/rtread_sysctl.c11
-rw-r--r--zebra/subdir.am4
-rw-r--r--zebra/zapi_msg.c12
-rw-r--r--zebra/zebra_dplane.c116
-rw-r--r--zebra/zebra_dplane.h36
-rw-r--r--zebra/zebra_evpn.c253
-rw-r--r--zebra/zebra_evpn.h17
-rw-r--r--zebra/zebra_evpn_mac.c28
-rw-r--r--zebra/zebra_evpn_mh.c229
-rw-r--r--zebra/zebra_evpn_mh.h18
-rw-r--r--zebra/zebra_evpn_neigh.c2
-rw-r--r--zebra/zebra_evpn_neigh.h3
-rw-r--r--zebra/zebra_evpn_vxlan.h30
-rw-r--r--zebra/zebra_l2.c81
-rw-r--r--zebra/zebra_l2.h79
-rw-r--r--zebra/zebra_l2_bridge_if.c383
-rw-r--r--zebra/zebra_l2_bridge_if.h75
-rw-r--r--zebra/zebra_mpls.c25
-rw-r--r--zebra/zebra_mpls.h4
-rw-r--r--zebra/zebra_nb_state.c20
-rw-r--r--zebra/zebra_nhg.c117
-rw-r--r--zebra/zebra_ns.c2
-rw-r--r--zebra/zebra_ptm.c1
-rw-r--r--zebra/zebra_rib.c104
-rw-r--r--zebra/zebra_rnh.c12
-rw-r--r--zebra/zebra_routemap.c28
-rw-r--r--zebra/zebra_vty.c76
-rw-r--r--zebra/zebra_vxlan.c1375
-rw-r--r--zebra/zebra_vxlan.h22
-rw-r--r--zebra/zebra_vxlan_if.c1162
-rw-r--r--zebra/zebra_vxlan_if.h96
-rw-r--r--zebra/zebra_vxlan_private.h16
123 files changed, 6320 insertions, 1498 deletions
diff --git a/babeld/babel_interface.c b/babeld/babel_interface.c
index 4ca875206f..53dcbb8348 100644
--- a/babeld/babel_interface.c
+++ b/babeld/babel_interface.c
@@ -295,17 +295,18 @@ static void
babel_set_wired_internal(babel_interface_nfo *babel_ifp, int wired)
{
if(wired) {
- babel_ifp->flags |= BABEL_IF_WIRED;
- babel_ifp->flags |= BABEL_IF_SPLIT_HORIZON;
+ SET_FLAG(babel_ifp->flags, BABEL_IF_WIRED);
+ SET_FLAG(babel_ifp->flags, BABEL_IF_SPLIT_HORIZON);
babel_ifp->cost = BABEL_DEFAULT_RXCOST_WIRED;
babel_ifp->channel = BABEL_IF_CHANNEL_NONINTERFERING;
- babel_ifp->flags &= ~BABEL_IF_LQ;
- } else {
- babel_ifp->flags &= ~BABEL_IF_WIRED;
- babel_ifp->flags &= ~BABEL_IF_SPLIT_HORIZON;
+ UNSET_FLAG(babel_ifp->flags, BABEL_IF_LQ);
+ }
+ else {
+ UNSET_FLAG(babel_ifp->flags, BABEL_IF_WIRED);
+ UNSET_FLAG(babel_ifp->flags, BABEL_IF_SPLIT_HORIZON);
babel_ifp->cost = BABEL_DEFAULT_RXCOST_WIRELESS;
babel_ifp->channel = BABEL_IF_CHANNEL_INTERFERING;
- babel_ifp->flags |= BABEL_IF_LQ;
+ SET_FLAG(babel_ifp->flags, BABEL_IF_LQ);
}
}
@@ -595,7 +596,7 @@ interface_recalculate(struct interface *ifp)
return -1;
}
- babel_ifp->flags |= BABEL_IF_IS_UP;
+ SET_FLAG(babel_ifp->flags, BABEL_IF_IS_UP);
mtu = MIN(ifp->mtu, ifp->mtu6);
@@ -653,7 +654,7 @@ interface_recalculate(struct interface *ifp)
debugf(BABEL_DEBUG_COMMON,
"Upped interface %s (%s, cost=%d, channel=%d%s).",
ifp->name,
- (babel_ifp->flags & BABEL_IF_WIRED) ? "wired" : "wireless",
+ CHECK_FLAG(babel_ifp->flags, BABEL_IF_WIRED) ? "wired" : "wireless",
babel_ifp->cost,
babel_ifp->channel,
babel_ifp->ipv4 ? ", IPv4" : "");
@@ -673,11 +674,12 @@ interface_reset(struct interface *ifp)
struct ipv6_mreq mreq;
babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp);
- if (!(babel_ifp->flags & BABEL_IF_IS_UP))
+ if (!CHECK_FLAG(babel_ifp->flags, BABEL_IF_IS_UP))
return 0;
debugf(BABEL_DEBUG_IF, "interface reset: %s", ifp->name);
- babel_ifp->flags &= ~BABEL_IF_IS_UP;
+
+ UNSET_FLAG(babel_ifp->flags, BABEL_IF_IS_UP);
flush_interface_routes(ifp, 0);
babel_ifp->buffered = 0;
@@ -706,7 +708,7 @@ interface_reset(struct interface *ifp)
debugf(BABEL_DEBUG_COMMON,"Upped network %s (%s, cost=%d%s).",
ifp->name,
- (babel_ifp->flags & BABEL_IF_WIRED) ? "wired" : "wireless",
+ CHECK_FLAG(babel_ifp->flags, BABEL_IF_WIRED) ? "wired" : "wireless",
babel_ifp->cost,
babel_ifp->ipv4 ? ", IPv4" : "");
diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c
index 392b558805..572475f068 100644
--- a/bgpd/bgp_attr.c
+++ b/bgpd/bgp_attr.c
@@ -1864,7 +1864,7 @@ static int bgp_attr_atomic(struct bgp_attr_parser_args *args)
args->total);
}
- if (peer->discard_attrs[args->type])
+ if (peer->discard_attrs[args->type] || peer->withdraw_attrs[args->type])
goto atomic_ignore;
/* Set atomic aggregate flag. */
@@ -1875,11 +1875,7 @@ static int bgp_attr_atomic(struct bgp_attr_parser_args *args)
atomic_ignore:
stream_forward_getp(peer->curr, length);
- if (bgp_debug_update(peer, NULL, NULL, 1))
- zlog_debug("%pBP: Ignoring attribute %s", peer,
- lookup_msg(attr_str, args->type, NULL));
-
- return BGP_ATTR_PARSE_PROCEED;
+ return bgp_attr_ignore(peer, args->type);
}
/* Aggregator attribute */
@@ -1905,7 +1901,7 @@ static int bgp_attr_aggregator(struct bgp_attr_parser_args *args)
args->total);
}
- if (peer->discard_attrs[args->type])
+ if (peer->discard_attrs[args->type] || peer->withdraw_attrs[args->type])
goto aggregator_ignore;
if (CHECK_FLAG(peer->cap, PEER_CAP_AS4_RCV))
@@ -1938,11 +1934,7 @@ static int bgp_attr_aggregator(struct bgp_attr_parser_args *args)
aggregator_ignore:
stream_forward_getp(peer->curr, length);
- if (bgp_debug_update(peer, NULL, NULL, 1))
- zlog_debug("%pBP: Ignoring attribute %s", peer,
- lookup_msg(attr_str, args->type, NULL));
-
- return BGP_ATTR_PARSE_PROCEED;
+ return bgp_attr_ignore(peer, args->type);
}
/* New Aggregator attribute */
@@ -1963,7 +1955,7 @@ bgp_attr_as4_aggregator(struct bgp_attr_parser_args *args,
0);
}
- if (peer->discard_attrs[args->type])
+ if (peer->discard_attrs[args->type] || peer->withdraw_attrs[args->type])
goto as4_aggregator_ignore;
aggregator_as = stream_getl(peer->curr);
@@ -1993,11 +1985,7 @@ bgp_attr_as4_aggregator(struct bgp_attr_parser_args *args,
as4_aggregator_ignore:
stream_forward_getp(peer->curr, length);
- if (bgp_debug_update(peer, NULL, NULL, 1))
- zlog_debug("%pBP: Ignoring attribute %s", peer,
- lookup_msg(attr_str, args->type, NULL));
-
- return BGP_ATTR_PARSE_PROCEED;
+ return bgp_attr_ignore(peer, args->type);
}
/* Munge Aggregator and New-Aggregator, AS_PATH and NEW_AS_PATH.
@@ -2117,7 +2105,7 @@ bgp_attr_community(struct bgp_attr_parser_args *args)
args->total);
}
- if (peer->discard_attrs[args->type])
+ if (peer->discard_attrs[args->type] || peer->withdraw_attrs[args->type])
goto community_ignore;
bgp_attr_set_community(
@@ -2139,11 +2127,7 @@ bgp_attr_community(struct bgp_attr_parser_args *args)
community_ignore:
stream_forward_getp(peer->curr, length);
- if (bgp_debug_update(peer, NULL, NULL, 1))
- zlog_debug("%pBP: Ignoring attribute %s", peer,
- lookup_msg(attr_str, args->type, NULL));
-
- return BGP_ATTR_PARSE_PROCEED;
+ return bgp_attr_ignore(peer, args->type);
}
/* Originator ID attribute. */
@@ -2167,7 +2151,7 @@ bgp_attr_originator_id(struct bgp_attr_parser_args *args)
args->total);
}
- if (peer->discard_attrs[args->type])
+ if (peer->discard_attrs[args->type] || peer->withdraw_attrs[args->type])
goto originator_id_ignore;
attr->originator_id.s_addr = stream_get_ipv4(peer->curr);
@@ -2179,11 +2163,7 @@ bgp_attr_originator_id(struct bgp_attr_parser_args *args)
originator_id_ignore:
stream_forward_getp(peer->curr, length);
- if (bgp_debug_update(peer, NULL, NULL, 1))
- zlog_debug("%pBP: Ignoring attribute %s", peer,
- lookup_msg(attr_str, args->type, NULL));
-
- return BGP_ATTR_PARSE_PROCEED;
+ return bgp_attr_ignore(peer, args->type);
}
/* Cluster list attribute. */
@@ -2206,7 +2186,7 @@ bgp_attr_cluster_list(struct bgp_attr_parser_args *args)
args->total);
}
- if (peer->discard_attrs[args->type])
+ if (peer->discard_attrs[args->type] || peer->withdraw_attrs[args->type])
goto cluster_list_ignore;
bgp_attr_set_cluster(
@@ -2223,11 +2203,7 @@ bgp_attr_cluster_list(struct bgp_attr_parser_args *args)
cluster_list_ignore:
stream_forward_getp(peer->curr, length);
- if (bgp_debug_update(peer, NULL, NULL, 1))
- zlog_debug("%pBP: Ignoring attribute %s", peer,
- lookup_msg(attr_str, args->type, NULL));
-
- return BGP_ATTR_PARSE_PROCEED;
+ return bgp_attr_ignore(peer, args->type);
}
/* Multiprotocol reachability information parse. */
@@ -2487,7 +2463,7 @@ bgp_attr_large_community(struct bgp_attr_parser_args *args)
args->total);
}
- if (peer->discard_attrs[args->type])
+ if (peer->discard_attrs[args->type] || peer->withdraw_attrs[args->type])
goto large_community_ignore;
bgp_attr_set_lcommunity(
@@ -2504,11 +2480,7 @@ bgp_attr_large_community(struct bgp_attr_parser_args *args)
large_community_ignore:
stream_forward_getp(peer->curr, length);
- if (bgp_debug_update(peer, NULL, NULL, 1))
- zlog_debug("%pBP: Ignoring attribute %s", peer,
- lookup_msg(attr_str, args->type, NULL));
-
- return BGP_ATTR_PARSE_PROCEED;
+ return bgp_attr_ignore(peer, args->type);
}
/* Extended Community attribute. */
@@ -2600,7 +2572,7 @@ bgp_attr_ipv6_ext_communities(struct bgp_attr_parser_args *args)
args->total);
}
- if (peer->discard_attrs[args->type])
+ if (peer->discard_attrs[args->type] || peer->withdraw_attrs[args->type])
goto ipv6_ext_community_ignore;
ipv6_ecomm = ecommunity_parse_ipv6(
@@ -2621,11 +2593,7 @@ bgp_attr_ipv6_ext_communities(struct bgp_attr_parser_args *args)
ipv6_ext_community_ignore:
stream_forward_getp(peer->curr, length);
- if (bgp_debug_update(peer, NULL, NULL, 1))
- zlog_debug("%pBP: Ignoring attribute %s", peer,
- lookup_msg(attr_str, args->type, NULL));
-
- return BGP_ATTR_PARSE_PROCEED;
+ return bgp_attr_ignore(peer, args->type);
}
/* Parse Tunnel Encap attribute in an UPDATE */
@@ -3300,7 +3268,7 @@ static enum bgp_attr_parse_ret bgp_attr_aigp(struct bgp_attr_parser_args *args)
goto aigp_ignore;
}
- if (peer->discard_attrs[args->type])
+ if (peer->discard_attrs[args->type] || peer->withdraw_attrs[args->type])
goto aigp_ignore;
if (!bgp_attr_aigp_valid(s, length))
@@ -3313,11 +3281,7 @@ static enum bgp_attr_parse_ret bgp_attr_aigp(struct bgp_attr_parser_args *args)
aigp_ignore:
stream_forward_getp(peer->curr, length);
- if (bgp_debug_update(peer, NULL, NULL, 1))
- zlog_debug("%pBP: Ignoring attribute %s", peer,
- lookup_msg(attr_str, args->type, NULL));
-
- return BGP_ATTR_PARSE_PROCEED;
+ return bgp_attr_ignore(peer, args->type);
}
/* OTC attribute. */
@@ -3335,7 +3299,7 @@ static enum bgp_attr_parse_ret bgp_attr_otc(struct bgp_attr_parser_args *args)
args->total);
}
- if (peer->discard_attrs[args->type])
+ if (peer->discard_attrs[args->type] || peer->withdraw_attrs[args->type])
goto otc_ignore;
attr->otc = stream_getl(peer->curr);
@@ -3352,11 +3316,7 @@ static enum bgp_attr_parse_ret bgp_attr_otc(struct bgp_attr_parser_args *args)
otc_ignore:
stream_forward_getp(peer->curr, length);
- if (bgp_debug_update(peer, NULL, NULL, 1))
- zlog_debug("%pBP: Ignoring attribute %s", peer,
- lookup_msg(attr_str, args->type, NULL));
-
- return BGP_ATTR_PARSE_PROCEED;
+ return bgp_attr_ignore(peer, args->type);
}
/* BGP unknown attribute treatment. */
@@ -3380,13 +3340,8 @@ bgp_attr_unknown(struct bgp_attr_parser_args *args)
/* Forward read pointer of input stream. */
stream_forward_getp(peer->curr, length);
- if (peer->discard_attrs[type]) {
- if (bgp_debug_update(peer, NULL, NULL, 1))
- zlog_debug("%pBP: Ignoring attribute %s", peer,
- lookup_msg(attr_str, args->type, NULL));
-
- return BGP_ATTR_PARSE_PROCEED;
- }
+ if (peer->discard_attrs[type] || peer->withdraw_attrs[type])
+ return bgp_attr_ignore(peer, type);
/* If any of the mandatory well-known attributes are not recognized,
then the Error Subcode is set to Unrecognized Well-known
@@ -5165,3 +5120,86 @@ void bgp_path_attribute_discard_vty(struct vty *vty, struct peer *peer,
peer_clear_soft(peer, afi, safi, BGP_CLEAR_SOFT_IN);
}
}
+
+void bgp_path_attribute_withdraw_vty(struct vty *vty, struct peer *peer,
+ const char *withdraw_attrs, bool set)
+{
+ int i, num_attributes;
+ char **attributes;
+ afi_t afi;
+ safi_t safi;
+
+ /* If `no` command specified without arbitrary attributes,
+ * then flush all.
+ */
+ if (!withdraw_attrs) {
+ for (i = 0; i < BGP_ATTR_MAX; i++)
+ peer->withdraw_attrs[i] = false;
+ goto withdraw_soft_clear;
+ }
+
+ if (withdraw_attrs) {
+ frrstr_split(withdraw_attrs, " ", &attributes, &num_attributes);
+
+ if (set)
+ for (i = 0; i < BGP_ATTR_MAX; i++)
+ peer->withdraw_attrs[i] = false;
+
+ for (i = 0; i < num_attributes; i++) {
+ uint8_t attr_num = strtoul(attributes[i], NULL, 10);
+
+ XFREE(MTYPE_TMP, attributes[i]);
+
+ /* Some of the attributes, just can't be ignored. */
+ if (attr_num == BGP_ATTR_ORIGIN ||
+ attr_num == BGP_ATTR_AS_PATH ||
+ attr_num == BGP_ATTR_NEXT_HOP ||
+ attr_num == BGP_ATTR_MULTI_EXIT_DISC ||
+ attr_num == BGP_ATTR_MP_REACH_NLRI ||
+ attr_num == BGP_ATTR_MP_UNREACH_NLRI ||
+ attr_num == BGP_ATTR_EXT_COMMUNITIES) {
+ vty_out(vty,
+ "%% Can't treat-as-withdraw path-attribute %s, ignoring.\n",
+ lookup_msg(attr_str, attr_num, NULL));
+ continue;
+ }
+
+ /* Ignore local-pref, originator-id, cluster-list only
+ * for eBGP.
+ */
+ if (peer->sort != BGP_PEER_EBGP &&
+ (attr_num == BGP_ATTR_LOCAL_PREF ||
+ attr_num == BGP_ATTR_ORIGINATOR_ID ||
+ attr_num == BGP_ATTR_CLUSTER_LIST)) {
+ vty_out(vty,
+ "%% Can treat-as-withdraw path-attribute %s only for eBGP, ignoring.\n",
+ lookup_msg(attr_str, attr_num, NULL));
+ continue;
+ }
+
+ peer->withdraw_attrs[attr_num] = set;
+ }
+ XFREE(MTYPE_TMP, attributes);
+ withdraw_soft_clear:
+ /* Configuring path attributes to be treated as withdraw will
+ * trigger
+ * an inbound Route Refresh to ensure that the routing table
+ * is up to date.
+ */
+ FOREACH_AFI_SAFI (afi, safi)
+ peer_clear_soft(peer, afi, safi, BGP_CLEAR_SOFT_IN);
+ }
+}
+
+enum bgp_attr_parse_ret bgp_attr_ignore(struct peer *peer, uint8_t type)
+{
+ bool discard = peer->discard_attrs[type];
+ bool withdraw = peer->withdraw_attrs[type];
+
+ if (bgp_debug_update(peer, NULL, NULL, 1) && (discard || withdraw))
+ zlog_debug("%pBP: Ignoring attribute %s (%s)", peer,
+ lookup_msg(attr_str, type, NULL),
+ withdraw ? "treat-as-withdraw" : "discard");
+
+ return withdraw ? BGP_ATTR_PARSE_WITHDRAW : BGP_ATTR_PARSE_PROCEED;
+}
diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h
index 33283f4bf6..e3499079d5 100644
--- a/bgpd/bgp_attr.h
+++ b/bgpd/bgp_attr.h
@@ -416,6 +416,10 @@ extern unsigned long int attr_count(void);
extern unsigned long int attr_unknown_count(void);
extern void bgp_path_attribute_discard_vty(struct vty *vty, struct peer *peer,
const char *discard_attrs, bool set);
+extern void bgp_path_attribute_withdraw_vty(struct vty *vty, struct peer *peer,
+ const char *withdraw_attrs,
+ bool set);
+extern enum bgp_attr_parse_ret bgp_attr_ignore(struct peer *peer, uint8_t type);
/* Cluster list prototypes. */
extern bool cluster_loop_check(struct cluster_list *cluster,
diff --git a/bgpd/bgp_debug.c b/bgpd/bgp_debug.c
index f01c3e4f35..8e199820bb 100644
--- a/bgpd/bgp_debug.c
+++ b/bgpd/bgp_debug.c
@@ -20,7 +20,6 @@
#include <zebra.h>
-#include <lib/version.h>
#include "lib/bfd.h"
#include "lib/printfrr.h"
#include "prefix.h"
diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c
index d8acbcd19a..5fdf021104 100644
--- a/bgpd/bgp_evpn.c
+++ b/bgpd/bgp_evpn.c
@@ -55,6 +55,7 @@
#include "bgpd/bgp_vty.h"
#include "bgpd/bgp_nht.h"
#include "bgpd/bgp_trace.h"
+#include "bgpd/bgp_mpath.h"
/*
* Definitions and external declarations.
@@ -7178,3 +7179,66 @@ void bgp_evpn_handle_resolve_overlay_index_unset(struct hash_bucket *bucket,
bgp_evpn_remote_ip_hash_destroy(vpn);
}
+
+/*
+ * Helper function for getting the correct label index for l3vni.
+ *
+ * Returns the label with the l3vni of the path's label stack.
+ *
+ * L3vni is always last label. Type5 will only
+ * have one label, Type2 will have two.
+ *
+ */
+mpls_label_t *bgp_evpn_path_info_labels_get_l3vni(mpls_label_t *labels,
+ uint32_t num_labels)
+{
+ if (!labels)
+ return NULL;
+
+ if (!num_labels)
+ return NULL;
+
+ return &labels[num_labels - 1];
+}
+
+/*
+ * Returns the l3vni of the path converted from the label stack.
+ */
+vni_t bgp_evpn_path_info_get_l3vni(const struct bgp_path_info *pi)
+{
+ if (!pi->extra)
+ return 0;
+
+ return label2vni(bgp_evpn_path_info_labels_get_l3vni(
+ pi->extra->label, pi->extra->num_labels));
+}
+
+/*
+ * Returns true if the l3vni of any of this path doesn't match vrf's l3vni.
+ */
+static bool bgp_evpn_path_is_dvni(const struct bgp *bgp_vrf,
+ const struct bgp_path_info *pi)
+{
+ vni_t vni = 0;
+
+ vni = bgp_evpn_path_info_get_l3vni(pi);
+
+ if ((vni > 0) && (vni != bgp_vrf->l3vni))
+ return true;
+
+ return false;
+}
+
+/*
+ * Returns true if the l3vni of any of the mpath's doesn't match vrf's l3vni.
+ */
+bool bgp_evpn_mpath_has_dvni(const struct bgp *bgp_vrf,
+ struct bgp_path_info *mpinfo)
+{
+ for (; mpinfo; mpinfo = bgp_path_info_mpath_next(mpinfo)) {
+ if (bgp_evpn_path_is_dvni(bgp_vrf, mpinfo))
+ return true;
+ }
+
+ return false;
+}
diff --git a/bgpd/bgp_evpn.h b/bgpd/bgp_evpn.h
index 67659ea198..4f95b71b1d 100644
--- a/bgpd/bgp_evpn.h
+++ b/bgpd/bgp_evpn.h
@@ -36,27 +36,6 @@ static inline int is_evpn_enabled(void)
return bgp ? EVPN_ENABLED(bgp) : 0;
}
-static inline void vni2label(vni_t vni, mpls_label_t *label)
-{
- uint8_t *tag = (uint8_t *)label;
-
- tag[0] = (vni >> 16) & 0xFF;
- tag[1] = (vni >> 8) & 0xFF;
- tag[2] = vni & 0xFF;
-}
-
-static inline vni_t label2vni(mpls_label_t *label)
-{
- uint8_t *tag = (uint8_t *)label;
- vni_t vni;
-
- vni = ((uint32_t)*tag++ << 16);
- vni |= (uint32_t)*tag++ << 8;
- vni |= (uint32_t)(*tag & 0xFF);
-
- return vni;
-}
-
static inline int advertise_type5_routes(struct bgp *bgp_vrf,
afi_t afi)
{
@@ -229,5 +208,10 @@ bgp_evpn_handle_resolve_overlay_index_set(struct hash_bucket *bucket,
extern void
bgp_evpn_handle_resolve_overlay_index_unset(struct hash_bucket *bucket,
void *arg);
+extern mpls_label_t *bgp_evpn_path_info_labels_get_l3vni(mpls_label_t *labels,
+ uint32_t num_labels);
+extern vni_t bgp_evpn_path_info_get_l3vni(const struct bgp_path_info *pi);
+extern bool bgp_evpn_mpath_has_dvni(const struct bgp *bgp_vrf,
+ struct bgp_path_info *mpinfo);
#endif /* _QUAGGA_BGP_EVPN_H */
diff --git a/bgpd/bgp_evpn_mh.c b/bgpd/bgp_evpn_mh.c
index 7ad0816631..bd32b4772b 100644
--- a/bgpd/bgp_evpn_mh.c
+++ b/bgpd/bgp_evpn_mh.c
@@ -3184,6 +3184,10 @@ bool bgp_evpn_path_es_use_nhg(struct bgp *bgp_vrf, struct bgp_path_info *pi,
if (!memcmp(esi, zero_esi, sizeof(*esi)))
return false;
+ /* we don't support NHG for d-vni yet */
+ if (bgp_evpn_mpath_has_dvni(bgp_vrf, pi))
+ return false;
+
bgp_evpn_es_vrf_use_nhg(bgp_vrf, esi, &use_l3nhg, &is_l3nhg_active,
&es_vrf);
diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c
index d00bdd2571..5aa3ec4fd1 100644
--- a/bgpd/bgp_routemap.c
+++ b/bgpd/bgp_routemap.c
@@ -475,8 +475,13 @@ route_match_ip_address(void *rule, const struct prefix *prefix, void *object)
if (prefix->family == AF_INET) {
alist = access_list_lookup(AFI_IP, (char *)rule);
- if (alist == NULL)
+ if (alist == NULL) {
+ if (CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP_DETAIL))
+ zlog_debug(
+ "%s: Access-List Specified: %s does not exist defaulting to NO_MATCH",
+ __func__, (char *)rule);
return RMAP_NOMATCH;
+ }
return (access_list_apply(alist, prefix) == FILTER_DENY
? RMAP_NOMATCH
@@ -489,6 +494,13 @@ route_match_ip_address(void *rule, const struct prefix *prefix, void *object)
access-list name. */
static void *route_match_ip_address_compile(const char *arg)
{
+ struct access_list *alist;
+
+ alist = access_list_lookup(AFI_IP, arg);
+ if (!alist)
+ zlog_warn(
+ "Access List specified %s does not exist yet, default will be NO_MATCH until it is created",
+ arg);
return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
}
@@ -506,7 +518,7 @@ static const struct route_map_rule_cmd route_match_ip_address_cmd = {
route_match_ip_address_free
};
-/* `match ip next-hop IP_ADDRESS' */
+/* `match ip next-hop <IP_ADDRESS_ACCESS_LIST_NAME>' */
/* Match function return 1 if match is success else return zero. */
static enum route_map_cmd_result_t
@@ -523,8 +535,14 @@ route_match_ip_next_hop(void *rule, const struct prefix *prefix, void *object)
p.prefixlen = IPV4_MAX_BITLEN;
alist = access_list_lookup(AFI_IP, (char *)rule);
- if (alist == NULL)
+ if (alist == NULL) {
+ if (CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP_DETAIL))
+ zlog_debug(
+ "%s: Access-List Specified: %s does not exist defaulting to NO_MATCH",
+ __func__, (char *)rule);
+
return RMAP_NOMATCH;
+ }
return (access_list_apply(alist, &p) == FILTER_DENY
? RMAP_NOMATCH
@@ -577,8 +595,14 @@ route_match_ip_route_source(void *rule, const struct prefix *pfx, void *object)
p.prefixlen = IPV4_MAX_BITLEN;
alist = access_list_lookup(AFI_IP, (char *)rule);
- if (alist == NULL)
+ if (alist == NULL) {
+ if (CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP_DETAIL))
+ zlog_debug(
+ "%s: Access-List Specified: %s does not exist defaulting to NO_MATCH",
+ __func__, (char *)rule);
+
return RMAP_NOMATCH;
+ }
return (access_list_apply(alist, &p) == FILTER_DENY
? RMAP_NOMATCH
@@ -666,8 +690,13 @@ route_match_address_prefix_list(void *rule, afi_t afi,
struct prefix_list *plist;
plist = prefix_list_lookup(afi, (char *)rule);
- if (plist == NULL)
+ if (plist == NULL) {
+ if (CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP_DETAIL))
+ zlog_debug(
+ "%s: Prefix List %s specified does not exist defaulting to NO_MATCH",
+ __func__, (char *)rule);
return RMAP_NOMATCH;
+ }
if (prefix->family == AF_FLOWSPEC)
return route_match_prefix_list_flowspec(afi, plist,
@@ -722,8 +751,13 @@ route_match_ip_next_hop_prefix_list(void *rule, const struct prefix *prefix,
p.prefixlen = IPV4_MAX_BITLEN;
plist = prefix_list_lookup(AFI_IP, (char *)rule);
- if (plist == NULL)
+ if (plist == NULL) {
+ if (CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP_DETAIL))
+ zlog_debug(
+ "%s: Prefix List %s specified does not exist defaulting to NO_MATCH",
+ __func__, (char *)rule);
return RMAP_NOMATCH;
+ }
return (prefix_list_apply(plist, &p) == PREFIX_DENY
? RMAP_NOMATCH
@@ -766,8 +800,13 @@ route_match_ipv6_next_hop_prefix_list(void *rule, const struct prefix *prefix,
p.prefixlen = IPV6_MAX_BITLEN;
plist = prefix_list_lookup(AFI_IP6, (char *)rule);
- if (!plist)
+ if (!plist) {
+ if (CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP_DETAIL))
+ zlog_debug(
+ "%s: Prefix List %s specified does not exist defaulting to NO_MATCH",
+ __func__, (char *)rule);
return RMAP_NOMATCH;
+ }
if (prefix_list_apply(plist, &p) == PREFIX_PERMIT)
return RMAP_MATCH;
@@ -866,8 +905,13 @@ route_match_ip_route_source_prefix_list(void *rule, const struct prefix *prefix,
p.prefixlen = IPV4_MAX_BITLEN;
plist = prefix_list_lookup(AFI_IP, (char *)rule);
- if (plist == NULL)
+ if (plist == NULL) {
+ if (CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP_DETAIL))
+ zlog_debug(
+ "%s: Prefix List %s specified does not exist defaulting to NO_MATCH",
+ __func__, (char *)rule);
return RMAP_NOMATCH;
+ }
return (prefix_list_apply(plist, &p) == PREFIX_DENY
? RMAP_NOMATCH
@@ -926,11 +970,21 @@ route_match_mac_address(void *rule, const struct prefix *prefix, void *object)
struct prefix p;
alist = access_list_lookup(AFI_L2VPN, (char *)rule);
- if (alist == NULL)
- return RMAP_NOMATCH;
+ if (alist == NULL) {
+ if (CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP_DETAIL))
+ zlog_debug(
+ "%s: Access-List Specified: %s does not exist defaulting to NO_MATCH",
+ __func__, (char *)rule);
- if (prefix->u.prefix_evpn.route_type != BGP_EVPN_MAC_IP_ROUTE)
return RMAP_NOMATCH;
+ }
+ if (prefix->u.prefix_evpn.route_type != BGP_EVPN_MAC_IP_ROUTE) {
+ if (CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP_DETAIL))
+ zlog_debug(
+ "%s: Prefix %pFX is not a EVPN MAC IP ROUTE defaulting to NO_MATCH",
+ __func__, prefix);
+ return RMAP_NOMATCH;
+ }
p.family = AF_ETHERNET;
p.prefixlen = ETH_ALEN * 8;
@@ -3206,8 +3260,14 @@ route_match_ipv6_address(void *rule, const struct prefix *prefix, void *object)
if (prefix->family == AF_INET6) {
alist = access_list_lookup(AFI_IP6, (char *)rule);
- if (alist == NULL)
+ if (alist == NULL) {
+ if (CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP_DETAIL))
+ zlog_debug(
+ "%s: Access-List Specified: %s does not exist defaulting to NO_MATCH",
+ __func__, (char *)rule);
+
return RMAP_NOMATCH;
+ }
return (access_list_apply(alist, prefix) == FILTER_DENY
? RMAP_NOMATCH
@@ -3218,6 +3278,14 @@ route_match_ipv6_address(void *rule, const struct prefix *prefix, void *object)
static void *route_match_ipv6_address_compile(const char *arg)
{
+ struct access_list *alist;
+
+ alist = access_list_lookup(AFI_IP6, arg);
+ if (!alist)
+ zlog_warn(
+ "Access List specified %s does not exist yet, default will be NO_MATCH until it is created",
+ arg);
+
return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
}
@@ -3249,8 +3317,14 @@ route_match_ipv6_next_hop(void *rule, const struct prefix *prefix, void *object)
p.prefixlen = IPV6_MAX_BITLEN;
alist = access_list_lookup(AFI_IP6, (char *)rule);
- if (!alist)
+ if (!alist) {
+ if (CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP_DETAIL))
+ zlog_debug(
+ "%s: Access-List Specified: %s does not exist defaulting to NO_MATCH",
+ __func__, (char *)rule);
+
return RMAP_NOMATCH;
+ }
if (access_list_apply(alist, &p) == FILTER_PERMIT)
return RMAP_MATCH;
@@ -3332,7 +3406,7 @@ static const struct route_map_rule_cmd route_match_ipv6_next_hop_address_cmd = {
route_match_ipv6_next_hop_address_free
};
-/* `match ip next-hop IP_ADDRESS' */
+/* `match ip next-hop address IP_ADDRESS' */
static enum route_map_cmd_result_t
route_match_ipv4_next_hop(void *rule, const struct prefix *prefix, void *object)
diff --git a/bgpd/bgp_snmp_bgp4.c b/bgpd/bgp_snmp_bgp4.c
index bb8b7f4b19..5bc2bb2dc1 100644
--- a/bgpd/bgp_snmp_bgp4.c
+++ b/bgpd/bgp_snmp_bgp4.c
@@ -32,7 +32,6 @@
#include "filter.h"
#include "hook.h"
#include "libfrr.h"
-#include "lib/version.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_table.h"
diff --git a/bgpd/bgp_snmp_bgp4v2.c b/bgpd/bgp_snmp_bgp4v2.c
index d8d8549960..1755cd9710 100644
--- a/bgpd/bgp_snmp_bgp4v2.c
+++ b/bgpd/bgp_snmp_bgp4v2.c
@@ -33,7 +33,6 @@
#include "filter.h"
#include "hook.h"
#include "libfrr.h"
-#include "lib/version.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_table.h"
diff --git a/bgpd/bgp_updgrp_adv.c b/bgpd/bgp_updgrp_adv.c
index cbd5d05922..9d75abe5de 100644
--- a/bgpd/bgp_updgrp_adv.c
+++ b/bgpd/bgp_updgrp_adv.c
@@ -934,10 +934,14 @@ void subgroup_default_originate(struct update_subgroup *subgrp, int withdraw)
if (subgroup_announce_check(
dest, pi, subgrp,
bgp_dest_get_prefix(dest),
- &attr, NULL))
+ &attr, NULL)) {
+ struct attr *default_attr =
+ bgp_attr_intern(&attr);
+
bgp_adj_out_set_subgroup(
- dest, subgrp, &attr,
- pi);
+ dest, subgrp,
+ default_attr, pi);
+ }
}
bgp_dest_unlock_node(dest);
}
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
index daa435bb2d..27f0ea9b71 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -8840,6 +8840,59 @@ DEFPY(no_neighbor_path_attribute_discard,
return CMD_SUCCESS;
}
+DEFPY(neighbor_path_attribute_treat_as_withdraw,
+ neighbor_path_attribute_treat_as_withdraw_cmd,
+ "neighbor <A.B.C.D|X:X::X:X|WORD>$neighbor path-attribute treat-as-withdraw (1-255)...",
+ NEIGHBOR_STR
+ NEIGHBOR_ADDR_STR2
+ "Manipulate path attributes from incoming UPDATE messages\n"
+ "Treat-as-withdraw any incoming BGP UPDATE messages that contain the specified attribute\n"
+ "Attribute number\n")
+{
+ struct peer *peer;
+ int idx = 0;
+ const char *withdraw_attrs = NULL;
+
+ peer = peer_and_group_lookup_vty(vty, neighbor);
+ if (!peer)
+ return CMD_WARNING_CONFIG_FAILED;
+
+ argv_find(argv, argc, "(1-255)", &idx);
+ if (idx)
+ withdraw_attrs = argv_concat(argv, argc, idx);
+
+ bgp_path_attribute_withdraw_vty(vty, peer, withdraw_attrs, true);
+
+ return CMD_SUCCESS;
+}
+
+DEFPY(no_neighbor_path_attribute_treat_as_withdraw,
+ no_neighbor_path_attribute_treat_as_withdraw_cmd,
+ "no neighbor <A.B.C.D|X:X::X:X|WORD>$neighbor path-attribute treat-as-withdraw (1-255)...",
+ NO_STR
+ NEIGHBOR_STR
+ NEIGHBOR_ADDR_STR2
+ "Manipulate path attributes from incoming UPDATE messages\n"
+ "Treat-as-withdraw any incoming BGP UPDATE messages that contain the specified attribute\n"
+ "Attribute number\n")
+{
+ struct peer *peer;
+ int idx = 0;
+ const char *withdraw_attrs = NULL;
+
+ peer = peer_and_group_lookup_vty(vty, neighbor);
+ if (!peer)
+ return CMD_WARNING_CONFIG_FAILED;
+
+ argv_find(argv, argc, "(1-255)", &idx);
+ if (idx)
+ withdraw_attrs = argv_concat(argv, argc, idx);
+
+ bgp_path_attribute_withdraw_vty(vty, peer, withdraw_attrs, false);
+
+ return CMD_SUCCESS;
+}
+
static int set_ecom_list(struct vty *vty, int argc, struct cmd_token **argv,
struct ecommunity **list, bool is_rt6)
{
@@ -17480,6 +17533,16 @@ static void bgp_config_write_peer_global(struct vty *vty, struct bgp *bgp,
vty_out(vty, " neighbor %s path-attribute discard %s\n", addr,
discard_attrs_str);
+ /* path-attribute treat-as-withdraw */
+ char withdraw_attrs_str[BUFSIZ] = {0};
+ bool withdraw_attrs = bgp_path_attribute_treat_as_withdraw(
+ peer, withdraw_attrs_str, sizeof(withdraw_attrs_str));
+
+ if (withdraw_attrs)
+ vty_out(vty,
+ " neighbor %s path-attribute treat-as-withdraw %s\n",
+ addr, withdraw_attrs_str);
+
if (!CHECK_FLAG(peer->peer_gr_new_status_flag,
PEER_GRACEFUL_RESTART_NEW_STATE_INHERIT)) {
@@ -19591,6 +19654,12 @@ void bgp_vty_init(void)
install_element(BGP_NODE, &neighbor_path_attribute_discard_cmd);
install_element(BGP_NODE, &no_neighbor_path_attribute_discard_cmd);
+ /* "neighbor path-attribute treat-as-withdraw" commands. */
+ install_element(BGP_NODE,
+ &neighbor_path_attribute_treat_as_withdraw_cmd);
+ install_element(BGP_NODE,
+ &no_neighbor_path_attribute_treat_as_withdraw_cmd);
+
/* "neighbor passive" commands. */
install_element(BGP_NODE, &neighbor_passive_cmd);
install_element(BGP_NODE, &no_neighbor_passive_cmd);
diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c
index 95e80ba1bb..3a61989900 100644
--- a/bgpd/bgp_zebra.c
+++ b/bgpd/bgp_zebra.c
@@ -1310,8 +1310,10 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p,
struct bgp_path_info local_info;
struct bgp_path_info *mpinfo_cp = &local_info;
route_tag_t tag;
- mpls_label_t label;
struct bgp_sid_info *sid_info;
+ mpls_label_t *labels;
+ uint32_t num_labels = 0;
+ mpls_label_t nh_label;
int nh_othervrf = 0;
bool nh_updated = false;
bool do_wt_ecmp;
@@ -1402,8 +1404,11 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p,
}
for (; mpinfo; mpinfo = bgp_path_info_mpath_next(mpinfo)) {
+ labels = NULL;
+ num_labels = 0;
uint32_t nh_weight;
bool is_evpn;
+ bool is_parent_evpn;
if (valid_nh_count >= multipath_num)
break;
@@ -1469,13 +1474,13 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p,
BGP_ORIGINAL_UPDATE(bgp_orig, mpinfo, bgp);
- if (nh_family == AF_INET) {
- is_evpn = is_route_parent_evpn(mpinfo);
+ is_parent_evpn = is_route_parent_evpn(mpinfo);
+ if (nh_family == AF_INET) {
nh_updated = update_ipv4nh_for_route_install(
nh_othervrf, bgp_orig,
&mpinfo_cp->attr->nexthop, mpinfo_cp->attr,
- is_evpn, api_nh);
+ is_parent_evpn, api_nh);
} else {
ifindex_t ifindex = IFINDEX_INTERNAL;
struct in6_addr *nexthop;
@@ -1483,19 +1488,20 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p,
nexthop = bgp_path_info_to_ipv6_nexthop(mpinfo_cp,
&ifindex);
- is_evpn = is_route_parent_evpn(mpinfo);
-
if (!nexthop)
nh_updated = update_ipv4nh_for_route_install(
nh_othervrf, bgp_orig,
&mpinfo_cp->attr->nexthop,
- mpinfo_cp->attr, is_evpn, api_nh);
+ mpinfo_cp->attr, is_parent_evpn,
+ api_nh);
else
nh_updated = update_ipv6nh_for_route_install(
nh_othervrf, bgp_orig, nexthop, ifindex,
- mpinfo, info, is_evpn, api_nh);
+ mpinfo, info, is_parent_evpn, api_nh);
}
+ is_evpn = !!CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_EVPN);
+
/* Did we get proper nexthop info to update zebra? */
if (!nh_updated)
continue;
@@ -1509,16 +1515,28 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p,
|| mpinfo->peer->sort == BGP_PEER_CONFED))
allow_recursion = true;
- if (mpinfo->extra &&
- bgp_is_valid_label(&mpinfo->extra->label[0]) &&
- !CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_EVPN)) {
- mpls_lse_decode(mpinfo->extra->label[0], &label, &ttl,
- &exp, &bos);
+ if (mpinfo->extra) {
+ labels = mpinfo->extra->label;
+ num_labels = mpinfo->extra->num_labels;
+ }
+
+ if (labels && (num_labels > 0) &&
+ (is_evpn || bgp_is_valid_label(&labels[0]))) {
+ enum lsp_types_t nh_label_type = ZEBRA_LSP_NONE;
- SET_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_LABEL);
+ if (is_evpn) {
+ nh_label = *bgp_evpn_path_info_labels_get_l3vni(
+ labels, num_labels);
+ nh_label_type = ZEBRA_LSP_EVPN;
+ } else {
+ mpls_lse_decode(labels[0], &nh_label, &ttl,
+ &exp, &bos);
+ }
+ SET_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_LABEL);
api_nh->label_num = 1;
- api_nh->labels[0] = label;
+ api_nh->label_type = nh_label_type;
+ api_nh->labels[0] = nh_label;
}
if (is_evpn
@@ -1529,27 +1547,26 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p,
api_nh->weight = nh_weight;
- if (mpinfo->extra &&
- bgp_is_valid_label(&mpinfo->extra->label[0]) &&
- !sid_zero(&mpinfo->extra->sid[0].sid) &&
- !CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_EVPN)) {
+ if (mpinfo->extra && !is_evpn &&
+ bgp_is_valid_label(&labels[0]) &&
+ !sid_zero(&mpinfo->extra->sid[0].sid)) {
sid_info = &mpinfo->extra->sid[0];
memcpy(&api_nh->seg6_segs, &sid_info->sid,
sizeof(api_nh->seg6_segs));
if (sid_info->transposition_len != 0) {
- mpls_lse_decode(mpinfo->extra->label[0], &label,
- &ttl, &exp, &bos);
+ mpls_lse_decode(labels[0], &nh_label, &ttl,
+ &exp, &bos);
- if (label < MPLS_LABEL_UNRESERVED_MIN) {
+ if (nh_label < MPLS_LABEL_UNRESERVED_MIN) {
if (bgp_debug_zebra(&api.prefix))
zlog_debug(
"skip invalid SRv6 routes: transposition scheme is used, but label is too small");
continue;
}
- transpose_sid(&api_nh->seg6_segs, label,
+ transpose_sid(&api_nh->seg6_segs, nh_label,
sid_info->transposition_offset,
sid_info->transposition_len);
}
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index 39010e76f9..f4e823e212 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -4213,6 +4213,26 @@ bool bgp_path_attribute_discard(struct peer *peer, char *buf, size_t size)
return false;
}
+bool bgp_path_attribute_treat_as_withdraw(struct peer *peer, char *buf,
+ size_t size)
+{
+ if (!buf)
+ return false;
+
+ buf[0] = '\0';
+
+ for (unsigned int i = 0; i < BGP_ATTR_MAX; i++) {
+ if (peer->withdraw_attrs[i])
+ snprintf(buf + strlen(buf), size - strlen(buf), "%s%d",
+ (strlen(buf) > 0) ? " " : "", i);
+ }
+
+ if (strlen(buf) > 0)
+ return true;
+
+ return false;
+}
+
/* If peer is configured at least one address family return 1. */
bool peer_active(struct peer *peer)
{
diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h
index 61119ab6e0..64f016dfc5 100644
--- a/bgpd/bgpd.h
+++ b/bgpd/bgpd.h
@@ -1768,6 +1768,9 @@ struct peer {
/* Path attributes discard */
bool discard_attrs[BGP_ATTR_MAX];
+ /* Path attributes treat-as-withdraw */
+ bool withdraw_attrs[BGP_ATTR_MAX];
+
QOBJ_FIELDS;
};
DECLARE_QOBJ_TYPE(peer);
@@ -2635,6 +2638,8 @@ extern void peer_on_policy_change(struct peer *peer, afi_t afi, safi_t safi,
int outbound);
extern bool bgp_path_attribute_discard(struct peer *peer, char *buf,
size_t size);
+extern bool bgp_path_attribute_treat_as_withdraw(struct peer *peer, char *buf,
+ size_t size);
#ifdef _FRR_ATTRIBUTE_PRINTFRR
/* clang-format off */
#pragma FRR printfrr_ext "%pBP" (struct peer *)
diff --git a/bgpd/rfapi/vnc_debug.c b/bgpd/rfapi/vnc_debug.c
index 5c627efbee..322f98e160 100644
--- a/bgpd/rfapi/vnc_debug.c
+++ b/bgpd/rfapi/vnc_debug.c
@@ -19,7 +19,6 @@
#include "lib/zebra.h"
-#include <lib/version.h>
#include "lib/prefix.h"
#include "lib/linklist.h"
#include "lib/stream.h"
diff --git a/debian/changelog b/debian/changelog
index fae7924c16..008a97c7d5 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,8 +1,14 @@
-frr (8.5~dev-1) UNRELEASED; urgency=medium
+frr (9.0~dev-1) UNRELEASED; urgency=medium
- * FRR Dev 8.5
+ * FRR Dev 9.0
- -- Donatas Abraitis <donatas@opensourcerouting.org> Tue, 04 Oct 2022 16:00:00 +0500
+ -- Donatas Abraitis <donatas@opensourcerouting.org> Tue, 07 Feb 2023 16:00:00 +0500
+
+frr (8.5-1) UNRELEASED; urgency=medium
+
+ * New upstream release FRR 8.5
+
+ -- Donatas Abraitis <donatas@opensourcerouting.org> Tue, 07 Feb 2023 16:00:00 +0500
frr (8.4.2-1) unstable; urgency=medium
diff --git a/doc/user/basic.rst b/doc/user/basic.rst
index 4a64d8f949..254dad8303 100644
--- a/doc/user/basic.rst
+++ b/doc/user/basic.rst
@@ -294,6 +294,12 @@ Basic Config Commands
log files to quickly balloon in size. Remember to disable backtraces
when they're no longer needed.
+.. clicmd:: debug routemap [detail]
+
+ This command turns on debugging of routemaps. When detail is specified
+ more data is provided to the operator about the reasoning about what
+ is going on in the routemap code.
+
.. clicmd:: service password-encryption
Encrypt password.
diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst
index b17442f641..6979c77d73 100644
--- a/doc/user/bgp.rst
+++ b/doc/user/bgp.rst
@@ -1711,6 +1711,11 @@ Configuring Peers
If you do not want specific attributes, you can drop them using this command, and
let the BGP proceed by ignoring those attributes.
+.. clicmd:: neighbor <A.B.C.D|X:X::X:X|WORD> path-attribute treat-as-withdraw (1-255)...
+
+ Received BGP UPDATES that contain specified path attributes are treat-as-withdraw. If
+ there is an existing prefix in the BGP routing table, it will be removed.
+
.. clicmd:: neighbor <A.B.C.D|X:X::X:X|WORD> graceful-shutdown
Mark all routes from this neighbor as less preferred by setting ``graceful-shutdown``
diff --git a/doc/user/zebra.rst b/doc/user/zebra.rst
index 7d61cb3860..e7e2e5d2ed 100644
--- a/doc/user/zebra.rst
+++ b/doc/user/zebra.rst
@@ -618,6 +618,48 @@ nexthops are chosen to forward packets on. Currently the Linux kernel
has a ``fib_multipath_hash_policy`` sysctl which dictates how the hashing
algorithm is used to forward packets.
+.. _zebra-svd:
+
+Single Vxlan Device Support
+===========================
+
+FRR supports configuring VLAN-to-VNI mappings for EVPN-VXLAN,
+when working with the Linux kernel. In this new way, the mapping of a VLAN
+to a VNI is configured against a container VXLAN interface which is referred
+to as a ‘Single VXLAN device (SVD)’. Multiple VLAN to VNI mappings can be
+configured against the same SVD. This allows for a significant scaling of
+the number of VNIs since a separate VXLAN interface is no longer required
+for each VNI. Sample configuration of SVD with VLAN to VNI mappings is shown
+below.
+
+If you are using the Linux kernel as a Data Plane, this can be configured
+via `ip link`, `bridge link` and `bridge vlan` commands:
+
+.. code-block:: shell
+
+ # linux shell
+ ip link add dev bridge type bridge
+ ip link set dev bridge type bridge vlan_filtering 1
+ ip link add dev vxlan0 type vxlan external
+ ip link set dev vxlan0 master bridge
+ bridge link set dev vxlan0 vlan_tunnel on
+ bridge vlan add dev vxlan0 vid 100
+ bridge vlan add dev vxlan0 vid 100 tunnel_info id 100
+ bridge vlan tunnelshow
+ port vlan ids tunnel id
+ bridge None
+ vxlan0 100 100
+
+.. clicmd:: show evpn access-vlan [IFNAME VLAN-ID | detail] [json]
+
+ Show information for EVPN Access VLANs.
+
+ ::
+
+ VLAN SVI L2-VNI VXLAN-IF # Members
+ bridge.20 vlan20 20 vxlan0 0
+ bridge.10 vlan10 0 vxlan0 0
+
.. _zebra-mpls:
MPLS Commands
diff --git a/include/linux/if_bridge.h b/include/linux/if_bridge.h
index fb79481cb2..02198fc1d7 100644
--- a/include/linux/if_bridge.h
+++ b/include/linux/if_bridge.h
@@ -120,6 +120,8 @@ enum {
IFLA_BRIDGE_MODE,
IFLA_BRIDGE_VLAN_INFO,
IFLA_BRIDGE_VLAN_TUNNEL_INFO,
+ IFLA_BRIDGE_MRP,
+ IFLA_BRIDGE_CFM,
__IFLA_BRIDGE_MAX,
};
#define IFLA_BRIDGE_MAX (__IFLA_BRIDGE_MAX - 1)
@@ -130,6 +132,7 @@ enum {
#define BRIDGE_VLAN_INFO_RANGE_BEGIN (1<<3) /* VLAN is start of vlan range */
#define BRIDGE_VLAN_INFO_RANGE_END (1<<4) /* VLAN is end of vlan range */
#define BRIDGE_VLAN_INFO_BRENTRY (1<<5) /* Global bridge VLAN entry */
+#define BRIDGE_VLAN_INFO_ONLY_OPTS (1<<6) /* Skip create/delete/flags */
struct bridge_vlan_info {
__u16 flags;
@@ -156,6 +159,390 @@ struct bridge_vlan_xstats {
__u32 pad2;
};
+enum {
+ IFLA_BRIDGE_MRP_UNSPEC,
+ IFLA_BRIDGE_MRP_INSTANCE,
+ IFLA_BRIDGE_MRP_PORT_STATE,
+ IFLA_BRIDGE_MRP_PORT_ROLE,
+ IFLA_BRIDGE_MRP_RING_STATE,
+ IFLA_BRIDGE_MRP_RING_ROLE,
+ IFLA_BRIDGE_MRP_START_TEST,
+ IFLA_BRIDGE_MRP_INFO,
+ IFLA_BRIDGE_MRP_IN_ROLE,
+ IFLA_BRIDGE_MRP_IN_STATE,
+ IFLA_BRIDGE_MRP_START_IN_TEST,
+ __IFLA_BRIDGE_MRP_MAX,
+};
+
+#define IFLA_BRIDGE_MRP_MAX (__IFLA_BRIDGE_MRP_MAX - 1)
+
+enum {
+ IFLA_BRIDGE_MRP_INSTANCE_UNSPEC,
+ IFLA_BRIDGE_MRP_INSTANCE_RING_ID,
+ IFLA_BRIDGE_MRP_INSTANCE_P_IFINDEX,
+ IFLA_BRIDGE_MRP_INSTANCE_S_IFINDEX,
+ IFLA_BRIDGE_MRP_INSTANCE_PRIO,
+ __IFLA_BRIDGE_MRP_INSTANCE_MAX,
+};
+
+#define IFLA_BRIDGE_MRP_INSTANCE_MAX (__IFLA_BRIDGE_MRP_INSTANCE_MAX - 1)
+
+enum {
+ IFLA_BRIDGE_MRP_PORT_STATE_UNSPEC,
+ IFLA_BRIDGE_MRP_PORT_STATE_STATE,
+ __IFLA_BRIDGE_MRP_PORT_STATE_MAX,
+};
+
+#define IFLA_BRIDGE_MRP_PORT_STATE_MAX (__IFLA_BRIDGE_MRP_PORT_STATE_MAX - 1)
+
+enum {
+ IFLA_BRIDGE_MRP_PORT_ROLE_UNSPEC,
+ IFLA_BRIDGE_MRP_PORT_ROLE_ROLE,
+ __IFLA_BRIDGE_MRP_PORT_ROLE_MAX,
+};
+
+#define IFLA_BRIDGE_MRP_PORT_ROLE_MAX (__IFLA_BRIDGE_MRP_PORT_ROLE_MAX - 1)
+
+enum {
+ IFLA_BRIDGE_MRP_RING_STATE_UNSPEC,
+ IFLA_BRIDGE_MRP_RING_STATE_RING_ID,
+ IFLA_BRIDGE_MRP_RING_STATE_STATE,
+ __IFLA_BRIDGE_MRP_RING_STATE_MAX,
+};
+
+#define IFLA_BRIDGE_MRP_RING_STATE_MAX (__IFLA_BRIDGE_MRP_RING_STATE_MAX - 1)
+
+enum {
+ IFLA_BRIDGE_MRP_RING_ROLE_UNSPEC,
+ IFLA_BRIDGE_MRP_RING_ROLE_RING_ID,
+ IFLA_BRIDGE_MRP_RING_ROLE_ROLE,
+ __IFLA_BRIDGE_MRP_RING_ROLE_MAX,
+};
+
+#define IFLA_BRIDGE_MRP_RING_ROLE_MAX (__IFLA_BRIDGE_MRP_RING_ROLE_MAX - 1)
+
+enum {
+ IFLA_BRIDGE_MRP_START_TEST_UNSPEC,
+ IFLA_BRIDGE_MRP_START_TEST_RING_ID,
+ IFLA_BRIDGE_MRP_START_TEST_INTERVAL,
+ IFLA_BRIDGE_MRP_START_TEST_MAX_MISS,
+ IFLA_BRIDGE_MRP_START_TEST_PERIOD,
+ IFLA_BRIDGE_MRP_START_TEST_MONITOR,
+ __IFLA_BRIDGE_MRP_START_TEST_MAX,
+};
+
+#define IFLA_BRIDGE_MRP_START_TEST_MAX (__IFLA_BRIDGE_MRP_START_TEST_MAX - 1)
+
+enum {
+ IFLA_BRIDGE_MRP_INFO_UNSPEC,
+ IFLA_BRIDGE_MRP_INFO_RING_ID,
+ IFLA_BRIDGE_MRP_INFO_P_IFINDEX,
+ IFLA_BRIDGE_MRP_INFO_S_IFINDEX,
+ IFLA_BRIDGE_MRP_INFO_PRIO,
+ IFLA_BRIDGE_MRP_INFO_RING_STATE,
+ IFLA_BRIDGE_MRP_INFO_RING_ROLE,
+ IFLA_BRIDGE_MRP_INFO_TEST_INTERVAL,
+ IFLA_BRIDGE_MRP_INFO_TEST_MAX_MISS,
+ IFLA_BRIDGE_MRP_INFO_TEST_MONITOR,
+ IFLA_BRIDGE_MRP_INFO_I_IFINDEX,
+ IFLA_BRIDGE_MRP_INFO_IN_STATE,
+ IFLA_BRIDGE_MRP_INFO_IN_ROLE,
+ IFLA_BRIDGE_MRP_INFO_IN_TEST_INTERVAL,
+ IFLA_BRIDGE_MRP_INFO_IN_TEST_MAX_MISS,
+ __IFLA_BRIDGE_MRP_INFO_MAX,
+};
+
+#define IFLA_BRIDGE_MRP_INFO_MAX (__IFLA_BRIDGE_MRP_INFO_MAX - 1)
+
+enum {
+ IFLA_BRIDGE_MRP_IN_STATE_UNSPEC,
+ IFLA_BRIDGE_MRP_IN_STATE_IN_ID,
+ IFLA_BRIDGE_MRP_IN_STATE_STATE,
+ __IFLA_BRIDGE_MRP_IN_STATE_MAX,
+};
+
+#define IFLA_BRIDGE_MRP_IN_STATE_MAX (__IFLA_BRIDGE_MRP_IN_STATE_MAX - 1)
+
+enum {
+ IFLA_BRIDGE_MRP_IN_ROLE_UNSPEC,
+ IFLA_BRIDGE_MRP_IN_ROLE_RING_ID,
+ IFLA_BRIDGE_MRP_IN_ROLE_IN_ID,
+ IFLA_BRIDGE_MRP_IN_ROLE_ROLE,
+ IFLA_BRIDGE_MRP_IN_ROLE_I_IFINDEX,
+ __IFLA_BRIDGE_MRP_IN_ROLE_MAX,
+};
+
+#define IFLA_BRIDGE_MRP_IN_ROLE_MAX (__IFLA_BRIDGE_MRP_IN_ROLE_MAX - 1)
+
+enum {
+ IFLA_BRIDGE_MRP_START_IN_TEST_UNSPEC,
+ IFLA_BRIDGE_MRP_START_IN_TEST_IN_ID,
+ IFLA_BRIDGE_MRP_START_IN_TEST_INTERVAL,
+ IFLA_BRIDGE_MRP_START_IN_TEST_MAX_MISS,
+ IFLA_BRIDGE_MRP_START_IN_TEST_PERIOD,
+ __IFLA_BRIDGE_MRP_START_IN_TEST_MAX,
+};
+
+#define IFLA_BRIDGE_MRP_START_IN_TEST_MAX (__IFLA_BRIDGE_MRP_START_IN_TEST_MAX - 1)
+
+struct br_mrp_instance {
+ __u32 ring_id;
+ __u32 p_ifindex;
+ __u32 s_ifindex;
+ __u16 prio;
+};
+
+struct br_mrp_ring_state {
+ __u32 ring_id;
+ __u32 ring_state;
+};
+
+struct br_mrp_ring_role {
+ __u32 ring_id;
+ __u32 ring_role;
+};
+
+struct br_mrp_start_test {
+ __u32 ring_id;
+ __u32 interval;
+ __u32 max_miss;
+ __u32 period;
+ __u32 monitor;
+};
+
+struct br_mrp_in_state {
+ __u32 in_state;
+ __u16 in_id;
+};
+
+struct br_mrp_in_role {
+ __u32 ring_id;
+ __u32 in_role;
+ __u32 i_ifindex;
+ __u16 in_id;
+};
+
+struct br_mrp_start_in_test {
+ __u32 interval;
+ __u32 max_miss;
+ __u32 period;
+ __u16 in_id;
+};
+
+enum {
+ IFLA_BRIDGE_CFM_UNSPEC,
+ IFLA_BRIDGE_CFM_MEP_CREATE,
+ IFLA_BRIDGE_CFM_MEP_DELETE,
+ IFLA_BRIDGE_CFM_MEP_CONFIG,
+ IFLA_BRIDGE_CFM_CC_CONFIG,
+ IFLA_BRIDGE_CFM_CC_PEER_MEP_ADD,
+ IFLA_BRIDGE_CFM_CC_PEER_MEP_REMOVE,
+ IFLA_BRIDGE_CFM_CC_RDI,
+ IFLA_BRIDGE_CFM_CC_CCM_TX,
+ IFLA_BRIDGE_CFM_MEP_CREATE_INFO,
+ IFLA_BRIDGE_CFM_MEP_CONFIG_INFO,
+ IFLA_BRIDGE_CFM_CC_CONFIG_INFO,
+ IFLA_BRIDGE_CFM_CC_RDI_INFO,
+ IFLA_BRIDGE_CFM_CC_CCM_TX_INFO,
+ IFLA_BRIDGE_CFM_CC_PEER_MEP_INFO,
+ IFLA_BRIDGE_CFM_MEP_STATUS_INFO,
+ IFLA_BRIDGE_CFM_CC_PEER_STATUS_INFO,
+ __IFLA_BRIDGE_CFM_MAX,
+};
+
+#define IFLA_BRIDGE_CFM_MAX (__IFLA_BRIDGE_CFM_MAX - 1)
+
+enum {
+ IFLA_BRIDGE_CFM_MEP_CREATE_UNSPEC,
+ IFLA_BRIDGE_CFM_MEP_CREATE_INSTANCE,
+ IFLA_BRIDGE_CFM_MEP_CREATE_DOMAIN,
+ IFLA_BRIDGE_CFM_MEP_CREATE_DIRECTION,
+ IFLA_BRIDGE_CFM_MEP_CREATE_IFINDEX,
+ __IFLA_BRIDGE_CFM_MEP_CREATE_MAX,
+};
+
+#define IFLA_BRIDGE_CFM_MEP_CREATE_MAX (__IFLA_BRIDGE_CFM_MEP_CREATE_MAX - 1)
+
+enum {
+ IFLA_BRIDGE_CFM_MEP_DELETE_UNSPEC,
+ IFLA_BRIDGE_CFM_MEP_DELETE_INSTANCE,
+ __IFLA_BRIDGE_CFM_MEP_DELETE_MAX,
+};
+
+#define IFLA_BRIDGE_CFM_MEP_DELETE_MAX (__IFLA_BRIDGE_CFM_MEP_DELETE_MAX - 1)
+
+enum {
+ IFLA_BRIDGE_CFM_MEP_CONFIG_UNSPEC,
+ IFLA_BRIDGE_CFM_MEP_CONFIG_INSTANCE,
+ IFLA_BRIDGE_CFM_MEP_CONFIG_UNICAST_MAC,
+ IFLA_BRIDGE_CFM_MEP_CONFIG_MDLEVEL,
+ IFLA_BRIDGE_CFM_MEP_CONFIG_MEPID,
+ __IFLA_BRIDGE_CFM_MEP_CONFIG_MAX,
+};
+
+#define IFLA_BRIDGE_CFM_MEP_CONFIG_MAX (__IFLA_BRIDGE_CFM_MEP_CONFIG_MAX - 1)
+
+enum {
+ IFLA_BRIDGE_CFM_CC_CONFIG_UNSPEC,
+ IFLA_BRIDGE_CFM_CC_CONFIG_INSTANCE,
+ IFLA_BRIDGE_CFM_CC_CONFIG_ENABLE,
+ IFLA_BRIDGE_CFM_CC_CONFIG_EXP_INTERVAL,
+ IFLA_BRIDGE_CFM_CC_CONFIG_EXP_MAID,
+ __IFLA_BRIDGE_CFM_CC_CONFIG_MAX,
+};
+
+#define IFLA_BRIDGE_CFM_CC_CONFIG_MAX (__IFLA_BRIDGE_CFM_CC_CONFIG_MAX - 1)
+
+enum {
+ IFLA_BRIDGE_CFM_CC_PEER_MEP_UNSPEC,
+ IFLA_BRIDGE_CFM_CC_PEER_MEP_INSTANCE,
+ IFLA_BRIDGE_CFM_CC_PEER_MEPID,
+ __IFLA_BRIDGE_CFM_CC_PEER_MEP_MAX,
+};
+
+#define IFLA_BRIDGE_CFM_CC_PEER_MEP_MAX (__IFLA_BRIDGE_CFM_CC_PEER_MEP_MAX - 1)
+
+enum {
+ IFLA_BRIDGE_CFM_CC_RDI_UNSPEC,
+ IFLA_BRIDGE_CFM_CC_RDI_INSTANCE,
+ IFLA_BRIDGE_CFM_CC_RDI_RDI,
+ __IFLA_BRIDGE_CFM_CC_RDI_MAX,
+};
+
+#define IFLA_BRIDGE_CFM_CC_RDI_MAX (__IFLA_BRIDGE_CFM_CC_RDI_MAX - 1)
+
+enum {
+ IFLA_BRIDGE_CFM_CC_CCM_TX_UNSPEC,
+ IFLA_BRIDGE_CFM_CC_CCM_TX_INSTANCE,
+ IFLA_BRIDGE_CFM_CC_CCM_TX_DMAC,
+ IFLA_BRIDGE_CFM_CC_CCM_TX_SEQ_NO_UPDATE,
+ IFLA_BRIDGE_CFM_CC_CCM_TX_PERIOD,
+ IFLA_BRIDGE_CFM_CC_CCM_TX_IF_TLV,
+ IFLA_BRIDGE_CFM_CC_CCM_TX_IF_TLV_VALUE,
+ IFLA_BRIDGE_CFM_CC_CCM_TX_PORT_TLV,
+ IFLA_BRIDGE_CFM_CC_CCM_TX_PORT_TLV_VALUE,
+ __IFLA_BRIDGE_CFM_CC_CCM_TX_MAX,
+};
+
+#define IFLA_BRIDGE_CFM_CC_CCM_TX_MAX (__IFLA_BRIDGE_CFM_CC_CCM_TX_MAX - 1)
+
+enum {
+ IFLA_BRIDGE_CFM_MEP_STATUS_UNSPEC,
+ IFLA_BRIDGE_CFM_MEP_STATUS_INSTANCE,
+ IFLA_BRIDGE_CFM_MEP_STATUS_OPCODE_UNEXP_SEEN,
+ IFLA_BRIDGE_CFM_MEP_STATUS_VERSION_UNEXP_SEEN,
+ IFLA_BRIDGE_CFM_MEP_STATUS_RX_LEVEL_LOW_SEEN,
+ __IFLA_BRIDGE_CFM_MEP_STATUS_MAX,
+};
+
+#define IFLA_BRIDGE_CFM_MEP_STATUS_MAX (__IFLA_BRIDGE_CFM_MEP_STATUS_MAX - 1)
+
+enum {
+ IFLA_BRIDGE_CFM_CC_PEER_STATUS_UNSPEC,
+ IFLA_BRIDGE_CFM_CC_PEER_STATUS_INSTANCE,
+ IFLA_BRIDGE_CFM_CC_PEER_STATUS_PEER_MEPID,
+ IFLA_BRIDGE_CFM_CC_PEER_STATUS_CCM_DEFECT,
+ IFLA_BRIDGE_CFM_CC_PEER_STATUS_RDI,
+ IFLA_BRIDGE_CFM_CC_PEER_STATUS_PORT_TLV_VALUE,
+ IFLA_BRIDGE_CFM_CC_PEER_STATUS_IF_TLV_VALUE,
+ IFLA_BRIDGE_CFM_CC_PEER_STATUS_SEEN,
+ IFLA_BRIDGE_CFM_CC_PEER_STATUS_TLV_SEEN,
+ IFLA_BRIDGE_CFM_CC_PEER_STATUS_SEQ_UNEXP_SEEN,
+ __IFLA_BRIDGE_CFM_CC_PEER_STATUS_MAX,
+};
+
+#define IFLA_BRIDGE_CFM_CC_PEER_STATUS_MAX (__IFLA_BRIDGE_CFM_CC_PEER_STATUS_MAX - 1)
+
+struct bridge_stp_xstats {
+ __u64 transition_blk;
+ __u64 transition_fwd;
+ __u64 rx_bpdu;
+ __u64 tx_bpdu;
+ __u64 rx_tcn;
+ __u64 tx_tcn;
+};
+
+#ifndef BRVLAN_RTA
+#define BRVLAN_RTA(r) \
+ ((struct rtattr *)(((char *)(r)) \
+ + NLMSG_ALIGN(sizeof(struct br_vlan_msg))))
+#endif
+/* Bridge vlan RTM header */
+struct br_vlan_msg {
+ __u8 family;
+ __u8 reserved1;
+ __u16 reserved2;
+ __u32 ifindex;
+};
+
+enum {
+ BRIDGE_VLANDB_DUMP_UNSPEC,
+ BRIDGE_VLANDB_DUMP_FLAGS,
+ __BRIDGE_VLANDB_DUMP_MAX,
+};
+#define BRIDGE_VLANDB_DUMP_MAX (__BRIDGE_VLANDB_DUMP_MAX - 1)
+
+/* flags used in BRIDGE_VLANDB_DUMP_FLAGS attribute to affect dumps */
+#define BRIDGE_VLANDB_DUMPF_STATS (1 << 0) /* Include stats in the dump */
+
+/* Bridge vlan RTM attributes
+ * [BRIDGE_VLANDB_ENTRY] = {
+ * [BRIDGE_VLANDB_ENTRY_INFO]
+ * ...
+ * }
+ */
+enum {
+ BRIDGE_VLANDB_UNSPEC,
+ BRIDGE_VLANDB_ENTRY,
+ __BRIDGE_VLANDB_MAX,
+};
+#define BRIDGE_VLANDB_MAX (__BRIDGE_VLANDB_MAX - 1)
+
+enum {
+ BRIDGE_VLANDB_ENTRY_UNSPEC,
+ BRIDGE_VLANDB_ENTRY_INFO,
+ BRIDGE_VLANDB_ENTRY_RANGE,
+ BRIDGE_VLANDB_ENTRY_STATE,
+ BRIDGE_VLANDB_ENTRY_TUNNEL_INFO,
+ BRIDGE_VLANDB_ENTRY_STATS,
+ __BRIDGE_VLANDB_ENTRY_MAX,
+};
+#define BRIDGE_VLANDB_ENTRY_MAX (__BRIDGE_VLANDB_ENTRY_MAX - 1)
+
+/* [BRIDGE_VLANDB_ENTRY] = {
+ * [BRIDGE_VLANDB_ENTRY_TUNNEL_INFO] = {
+ * [BRIDGE_VLANDB_TINFO_ID]
+ * ...
+ * }
+ * }
+ */
+enum {
+ BRIDGE_VLANDB_TINFO_UNSPEC,
+ BRIDGE_VLANDB_TINFO_ID,
+ BRIDGE_VLANDB_TINFO_CMD,
+ __BRIDGE_VLANDB_TINFO_MAX,
+};
+#define BRIDGE_VLANDB_TINFO_MAX (__BRIDGE_VLANDB_TINFO_MAX - 1)
+
+/* [BRIDGE_VLANDB_ENTRY] = {
+ * [BRIDGE_VLANDB_ENTRY_STATS] = {
+ * [BRIDGE_VLANDB_STATS_RX_BYTES]
+ * ...
+ * }
+ * ...
+ * }
+ */
+enum {
+ BRIDGE_VLANDB_STATS_UNSPEC,
+ BRIDGE_VLANDB_STATS_RX_BYTES,
+ BRIDGE_VLANDB_STATS_RX_PACKETS,
+ BRIDGE_VLANDB_STATS_TX_BYTES,
+ BRIDGE_VLANDB_STATS_TX_PACKETS,
+ BRIDGE_VLANDB_STATS_PAD,
+ __BRIDGE_VLANDB_STATS_MAX,
+};
+#define BRIDGE_VLANDB_STATS_MAX (__BRIDGE_VLANDB_STATS_MAX - 1)
+
/* Bridge multicast database attributes
* [MDBA_MDB] = {
* [MDBA_MDB_ENTRY] = {
@@ -198,10 +585,33 @@ enum {
enum {
MDBA_MDB_EATTR_UNSPEC,
MDBA_MDB_EATTR_TIMER,
+ MDBA_MDB_EATTR_SRC_LIST,
+ MDBA_MDB_EATTR_GROUP_MODE,
+ MDBA_MDB_EATTR_SOURCE,
+ MDBA_MDB_EATTR_RTPROT,
__MDBA_MDB_EATTR_MAX
};
#define MDBA_MDB_EATTR_MAX (__MDBA_MDB_EATTR_MAX - 1)
+/* per mdb entry source */
+enum {
+ MDBA_MDB_SRCLIST_UNSPEC,
+ MDBA_MDB_SRCLIST_ENTRY,
+ __MDBA_MDB_SRCLIST_MAX
+};
+#define MDBA_MDB_SRCLIST_MAX (__MDBA_MDB_SRCLIST_MAX - 1)
+
+/* per mdb entry per source attributes
+ * these are embedded in MDBA_MDB_SRCLIST_ENTRY
+ */
+enum {
+ MDBA_MDB_SRCATTR_UNSPEC,
+ MDBA_MDB_SRCATTR_ADDRESS,
+ MDBA_MDB_SRCATTR_TIMER,
+ __MDBA_MDB_SRCATTR_MAX
+};
+#define MDBA_MDB_SRCATTR_MAX (__MDBA_MDB_SRCATTR_MAX - 1)
+
/* multicast router types */
enum {
MDB_RTR_TYPE_DISABLED,
@@ -238,12 +648,15 @@ struct br_mdb_entry {
__u8 state;
#define MDB_FLAGS_OFFLOAD (1 << 0)
#define MDB_FLAGS_FAST_LEAVE (1 << 1)
+#define MDB_FLAGS_STAR_EXCL (1 << 2)
+#define MDB_FLAGS_BLOCKED (1 << 3)
__u8 flags;
__u16 vid;
struct {
union {
__be32 ip4;
struct in6_addr ip6;
+ unsigned char mac_addr[ETH_ALEN];
} u;
__be16 proto;
} addr;
@@ -252,16 +665,30 @@ struct br_mdb_entry {
enum {
MDBA_SET_ENTRY_UNSPEC,
MDBA_SET_ENTRY,
+ MDBA_SET_ENTRY_ATTRS,
__MDBA_SET_ENTRY_MAX,
};
#define MDBA_SET_ENTRY_MAX (__MDBA_SET_ENTRY_MAX - 1)
+/* [MDBA_SET_ENTRY_ATTRS] = {
+ * [MDBE_ATTR_xxx]
+ * ...
+ * }
+ */
+enum {
+ MDBE_ATTR_UNSPEC,
+ MDBE_ATTR_SOURCE,
+ __MDBE_ATTR_MAX,
+};
+#define MDBE_ATTR_MAX (__MDBE_ATTR_MAX - 1)
+
/* Embedded inside LINK_XSTATS_TYPE_BRIDGE */
enum {
BRIDGE_XSTATS_UNSPEC,
BRIDGE_XSTATS_VLAN,
BRIDGE_XSTATS_MCAST,
BRIDGE_XSTATS_PAD,
+ BRIDGE_XSTATS_STP,
__BRIDGE_XSTATS_MAX
};
#define BRIDGE_XSTATS_MAX (__BRIDGE_XSTATS_MAX - 1)
@@ -293,4 +720,25 @@ struct br_mcast_stats {
__u64 mcast_bytes[BR_MCAST_DIR_SIZE];
__u64 mcast_packets[BR_MCAST_DIR_SIZE];
};
+
+/* bridge boolean options
+ * BR_BOOLOPT_NO_LL_LEARN - disable learning from link-local packets
+ *
+ * IMPORTANT: if adding a new option do not forget to handle
+ * it in br_boolopt_toggle/get and bridge sysfs
+ */
+enum br_boolopt_id {
+ BR_BOOLOPT_NO_LL_LEARN,
+ BR_BOOLOPT_MAX
+};
+
+/* struct br_boolopt_multi - change multiple bridge boolean options
+ *
+ * @optval: new option values (bit per option)
+ * @optmask: options to change (bit per option)
+ */
+struct br_boolopt_multi {
+ __u32 optval;
+ __u32 optmask;
+};
#endif /* _UAPI_LINUX_IF_BRIDGE_H */
diff --git a/isisd/isis_spf.c b/isisd/isis_spf.c
index 22625ed247..215108a280 100644
--- a/isisd/isis_spf.c
+++ b/isisd/isis_spf.c
@@ -2285,7 +2285,8 @@ static void isis_print_route(struct ttable *tt, const struct prefix *prefix,
label2str(
nexthop->label_stack->label[i],
- buf_label, sizeof(buf_label));
+ 0, buf_label,
+ sizeof(buf_label));
if (i != 0)
strlcat(buf_labels, "/",
sizeof(buf_labels));
@@ -2293,7 +2294,7 @@ static void isis_print_route(struct ttable *tt, const struct prefix *prefix,
sizeof(buf_labels));
}
} else if (nexthop->sr.present)
- label2str(nexthop->sr.label, buf_labels,
+ label2str(nexthop->sr.label, 0, buf_labels,
sizeof(buf_labels));
else
strlcpy(buf_labels, "-", sizeof(buf_labels));
diff --git a/lib/mpls.c b/lib/mpls.c
index ac5792a686..1b21dd29ff 100644
--- a/lib/mpls.c
+++ b/lib/mpls.c
@@ -80,7 +80,7 @@ int mpls_str2label(const char *label_str, uint8_t *num_labels,
* Label to string conversion, labels in string separated by '/'.
*/
char *mpls_label2str(uint8_t num_labels, const mpls_label_t *labels, char *buf,
- int len, int pretty)
+ int len, enum lsp_types_t type, int pretty)
{
char label_buf[BUFSIZ];
int i;
@@ -90,9 +90,14 @@ char *mpls_label2str(uint8_t num_labels, const mpls_label_t *labels, char *buf,
if (i != 0)
strlcat(buf, "/", len);
if (pretty)
- label2str(labels[i], label_buf, sizeof(label_buf));
+ label2str(labels[i], type, label_buf,
+ sizeof(label_buf));
else
- snprintf(label_buf, sizeof(label_buf), "%u", labels[i]);
+ snprintf(label_buf, sizeof(label_buf), "%u",
+ ((type == ZEBRA_LSP_EVPN)
+ ? label2vni(&labels[i])
+ : labels[i]));
+
strlcat(buf, label_buf, len);
}
diff --git a/lib/mpls.h b/lib/mpls.h
index 74bd7aae3e..069e560f80 100644
--- a/lib/mpls.h
+++ b/lib/mpls.h
@@ -23,6 +23,7 @@
#define _QUAGGA_MPLS_H
#include <zebra.h>
+#include <vxlan.h>
#include <arpa/inet.h>
#ifdef __cplusplus
@@ -129,10 +130,36 @@ enum lsp_types_t {
ZEBRA_LSP_ISIS_SR = 5,/* IS-IS Segment Routing LSP. */
ZEBRA_LSP_SHARP = 6, /* Identifier for test protocol */
ZEBRA_LSP_SRTE = 7, /* SR-TE LSP */
+ ZEBRA_LSP_EVPN = 8, /* EVPN VNI Label */
};
/* Functions for basic label operations. */
+static inline void vni2label(vni_t vni, mpls_label_t *label)
+{
+ uint8_t *tag = (uint8_t *)label;
+
+ assert(tag);
+
+ tag[0] = (vni >> 16) & 0xFF;
+ tag[1] = (vni >> 8) & 0xFF;
+ tag[2] = vni & 0xFF;
+}
+
+static inline vni_t label2vni(const mpls_label_t *label)
+{
+ uint8_t *tag = (uint8_t *)label;
+ vni_t vni;
+
+ assert(tag);
+
+ vni = ((uint32_t)*tag++ << 16);
+ vni |= (uint32_t)*tag++ << 8;
+ vni |= (uint32_t)(*tag & 0xFF);
+
+ return vni;
+}
+
/* Encode a label stack entry from fields; convert to network byte-order as
* the Netlink interface expects MPLS labels to be in this format.
*/
@@ -168,8 +195,14 @@ static inline void mpls_lse_decode(mpls_lse_t lse, mpls_label_t *label,
#define MPLS_INVALID_LABEL_INDEX 0xFFFFFFFF
/* Printable string for labels (with consideration for reserved values). */
-static inline char *label2str(mpls_label_t label, char *buf, size_t len)
+static inline char *label2str(mpls_label_t label, enum lsp_types_t type,
+ char *buf, size_t len)
{
+ if (type == ZEBRA_LSP_EVPN) {
+ snprintf(buf, len, "%u", label2vni(&label));
+ return (buf);
+ }
+
switch (label) {
case MPLS_LABEL_IPV4_EXPLICIT_NULL:
strlcpy(buf, "IPv4 Explicit Null", len);
@@ -200,7 +233,7 @@ static inline char *label2str(mpls_label_t label, char *buf, size_t len)
snprintf(buf, len, "Reserved (%u)", label);
else
snprintf(buf, len, "%u", label);
- return (buf);
+ return buf;
}
}
@@ -217,7 +250,7 @@ int mpls_str2label(const char *label_str, uint8_t *num_labels,
* Label to string conversion, labels in string separated by '/'.
*/
char *mpls_label2str(uint8_t num_labels, const mpls_label_t *labels, char *buf,
- int len, int pretty);
+ int len, enum lsp_types_t type, int pretty);
#ifdef __cplusplus
}
diff --git a/lib/nexthop_group.c b/lib/nexthop_group.c
index 41fe64606b..fd7eee213c 100644
--- a/lib/nexthop_group.c
+++ b/lib/nexthop_group.c
@@ -41,6 +41,7 @@ struct nexthop_hold {
char *intf;
bool onlink;
char *labels;
+ vni_t vni;
uint32_t weight;
char *backup_str;
};
@@ -131,6 +132,18 @@ nexthop_group_active_nexthop_num_no_recurse(const struct nexthop_group *nhg)
return num;
}
+bool nexthop_group_has_label(const struct nexthop_group *nhg)
+{
+ struct nexthop *nhop;
+
+ for (ALL_NEXTHOPS_PTR(nhg, nhop)) {
+ if (nhop->nh_label)
+ return true;
+ }
+
+ return false;
+}
+
struct nexthop *nexthop_exists(const struct nexthop_group *nhg,
const struct nexthop *nh)
{
@@ -791,12 +804,13 @@ static bool nexthop_group_parse_nexthop(struct nexthop *nhop,
const union sockunion *addr,
const char *intf, bool onlink,
const char *name, const char *labels,
- int *lbl_ret, uint32_t weight,
- const char *backup_str)
+ vni_t vni, int *lbl_ret,
+ uint32_t weight, const char *backup_str)
{
int ret = 0;
struct vrf *vrf;
int num;
+ uint8_t labelnum = 0;
memset(nhop, 0, sizeof(*nhop));
@@ -837,10 +851,9 @@ static bool nexthop_group_parse_nexthop(struct nexthop *nhop,
nhop->type = NEXTHOP_TYPE_IFINDEX;
if (labels) {
- uint8_t num = 0;
mpls_label_t larray[MPLS_MAX_LABELS];
- ret = mpls_str2label(labels, &num, larray);
+ ret = mpls_str2label(labels, &labelnum, larray);
/* Return label parse result */
if (lbl_ret)
@@ -848,9 +861,14 @@ static bool nexthop_group_parse_nexthop(struct nexthop *nhop,
if (ret < 0)
return false;
- else if (num > 0)
- nexthop_add_labels(nhop, ZEBRA_LSP_NONE,
- num, larray);
+ else if (labelnum > 0)
+ nexthop_add_labels(nhop, ZEBRA_LSP_NONE, labelnum,
+ larray);
+ } else if (vni) {
+ mpls_label_t label = MPLS_INVALID_LABEL;
+
+ vni2label(vni, &label);
+ nexthop_add_labels(nhop, ZEBRA_LSP_EVPN, 1, &label);
}
nhop->weight = weight;
@@ -877,7 +895,7 @@ static bool nexthop_group_parse_nhh(struct nexthop *nhop,
{
return (nexthop_group_parse_nexthop(
nhop, nhh->addr, nhh->intf, nhh->onlink, nhh->nhvrf_name,
- nhh->labels, NULL, nhh->weight, nhh->backup_str));
+ nhh->labels, nhh->vni, NULL, nhh->weight, nhh->backup_str));
}
DEFPY(ecmp_nexthops, ecmp_nexthops_cmd,
@@ -889,6 +907,7 @@ DEFPY(ecmp_nexthops, ecmp_nexthops_cmd,
[{ \
nexthop-vrf NAME$vrf_name \
|label WORD \
+ |vni (1-16777215) \
|weight (1-255) \
|backup-idx WORD \
}]",
@@ -903,6 +922,8 @@ DEFPY(ecmp_nexthops, ecmp_nexthops_cmd,
"The nexthop-vrf Name\n"
"Specify label(s) for this nexthop\n"
"One or more labels in the range (16-1048575) separated by '/'\n"
+ "Specify VNI(s) for this nexthop\n"
+ "VNI in the range (1-16777215)\n"
"Weight to be used by the nexthop for purposes of ECMP\n"
"Weight value to be used\n"
"Specify backup nexthop indexes in another group\n"
@@ -927,8 +948,8 @@ DEFPY(ecmp_nexthops, ecmp_nexthops_cmd,
}
legal = nexthop_group_parse_nexthop(&nhop, addr, intf, !!onlink,
- vrf_name, label, &lbl_ret, weight,
- backup_idx);
+ vrf_name, label, vni, &lbl_ret,
+ weight, backup_idx);
if (nhop.type == NEXTHOP_TYPE_IPV6
&& IN6_IS_ADDR_LINKLOCAL(&nhop.gate.ipv6)) {
@@ -1058,9 +1079,8 @@ void nexthop_group_write_nexthop(struct vty *vty, const struct nexthop *nh)
if (nh->nh_label && nh->nh_label->num_labels > 0) {
char buf[200];
- mpls_label2str(nh->nh_label->num_labels,
- nh->nh_label->label,
- buf, sizeof(buf), 0);
+ mpls_label2str(nh->nh_label->num_labels, nh->nh_label->label,
+ buf, sizeof(buf), nh->nh_label_type, 0);
vty_out(vty, " label %s", buf);
}
@@ -1117,7 +1137,7 @@ void nexthop_group_json_nexthop(json_object *j, const struct nexthop *nh)
char buf[200];
mpls_label2str(nh->nh_label->num_labels, nh->nh_label->label,
- buf, sizeof(buf), 0);
+ buf, sizeof(buf), nh->nh_label_type, 0);
json_object_string_add(j, "label", buf);
}
@@ -1155,6 +1175,9 @@ static void nexthop_group_write_nexthop_internal(struct vty *vty,
if (nh->labels)
vty_out(vty, " label %s", nh->labels);
+ if (nh->vni)
+ vty_out(vty, " vni %u", nh->vni);
+
if (nh->weight)
vty_out(vty, " weight %u", nh->weight);
diff --git a/lib/nexthop_group.h b/lib/nexthop_group.h
index 0ea0b7c185..4d560fc438 100644
--- a/lib/nexthop_group.h
+++ b/lib/nexthop_group.h
@@ -170,6 +170,8 @@ nexthop_group_active_nexthop_num(const struct nexthop_group *nhg);
extern uint8_t
nexthop_group_active_nexthop_num_no_recurse(const struct nexthop_group *nhg);
+extern bool nexthop_group_has_label(const struct nexthop_group *nhg);
+
#ifdef __cplusplus
}
#endif
diff --git a/lib/routemap.c b/lib/routemap.c
index f56e6a6122..4b9033594c 100644
--- a/lib/routemap.c
+++ b/lib/routemap.c
@@ -36,6 +36,8 @@
#include "json.h"
#include "jhash.h"
+#include "lib/routemap_clippy.c"
+
DEFINE_MTYPE_STATIC(LIB, ROUTE_MAP, "Route map");
DEFINE_MTYPE(LIB, ROUTE_MAP_NAME, "Route map name");
DEFINE_MTYPE_STATIC(LIB, ROUTE_MAP_INDEX, "Route map index");
@@ -613,7 +615,8 @@ static unsigned int route_map_dep_hash_make_key(const void *p);
static void route_map_clear_all_references(char *rmap_name);
static void route_map_rule_delete(struct route_map_rule_list *,
struct route_map_rule *);
-static bool rmap_debug;
+
+uint32_t rmap_debug;
/* New route map allocation. Please note route map's name must be
specified. */
@@ -681,7 +684,7 @@ static struct route_map *route_map_add(const char *name)
if (!map->ipv6_prefix_table)
map->ipv6_prefix_table = route_table_init();
- if (rmap_debug)
+ if (CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP))
zlog_debug("Add route-map %s", name);
return map;
}
@@ -701,7 +704,7 @@ static void route_map_free_map(struct route_map *map)
while ((index = map->head) != NULL)
route_map_index_delete(index, 0);
- if (rmap_debug)
+ if (CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP))
zlog_debug("Deleting route-map %s", map->name);
list = &route_map_master;
@@ -1132,7 +1135,7 @@ void route_map_index_delete(struct route_map_index *index, int notify)
QOBJ_UNREG(index);
- if (rmap_debug)
+ if (CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP))
zlog_debug("Deleting route-map %s sequence %d",
index->map->name, index->pref);
@@ -1243,7 +1246,7 @@ route_map_index_add(struct route_map *map, enum route_map_type type, int pref)
route_map_notify_dependencies(map->name, RMAP_EVENT_CALL_ADDED);
}
- if (rmap_debug)
+ if (CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP))
zlog_debug("Route-map %s add sequence %d, type: %s",
map->name, pref, route_map_type_str(type));
@@ -2580,13 +2583,13 @@ route_map_result_t route_map_apply_ext(struct route_map *map,
&match_ret);
if (index) {
index->applied++;
- if (rmap_debug)
+ if (CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP))
zlog_debug(
"Best match route-map: %s, sequence: %d for pfx: %pFX, result: %s",
map->name, index->pref, prefix,
route_map_cmd_result_str(match_ret));
} else {
- if (rmap_debug)
+ if (CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP))
zlog_debug(
"No best match sequence for pfx: %pFX in route-map: %s, result: %s",
prefix, map->name,
@@ -2612,7 +2615,7 @@ route_map_result_t route_map_apply_ext(struct route_map *map,
/* Apply this index. */
match_ret = route_map_apply_match(&index->match_list,
prefix, match_object);
- if (rmap_debug) {
+ if (CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP)) {
zlog_debug(
"Route-map: %s, sequence: %d, prefix: %pFX, result: %s",
map->name, index->pref, prefix,
@@ -2725,7 +2728,7 @@ route_map_result_t route_map_apply_ext(struct route_map *map,
}
route_map_apply_end:
- if (rmap_debug)
+ if (CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP))
zlog_debug("Route-map: %s, prefix: %pFX, result: %s",
(map ? map->name : "null"), prefix,
route_map_result_str(ret));
@@ -2780,7 +2783,7 @@ static void route_map_clear_reference(struct hash_bucket *bucket, void *arg)
tmp_dep_data.rname = arg;
dep_data = hash_release(dep->dep_rmap_hash, &tmp_dep_data);
if (dep_data) {
- if (rmap_debug)
+ if (CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP))
zlog_debug("Clearing reference for %s to %s count: %d",
dep->dep_name, tmp_dep_data.rname,
dep_data->refcnt);
@@ -2800,7 +2803,7 @@ static void route_map_clear_all_references(char *rmap_name)
{
int i;
- if (rmap_debug)
+ if (CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP))
zlog_debug("Clearing references for %s", rmap_name);
for (i = 1; i < ROUTE_MAP_DEP_MAX; i++) {
@@ -2876,7 +2879,7 @@ static int route_map_dep_update(struct hash *dephash, const char *dep_name,
case RMAP_EVENT_LLIST_ADDED:
case RMAP_EVENT_CALL_ADDED:
case RMAP_EVENT_FILTER_ADDED:
- if (rmap_debug)
+ if (CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP))
zlog_debug("Adding dependency for filter %s in route-map %s",
dep_name, rmap_name);
dep = (struct route_map_dep *)hash_get(
@@ -2905,7 +2908,7 @@ static int route_map_dep_update(struct hash *dephash, const char *dep_name,
case RMAP_EVENT_LLIST_DELETED:
case RMAP_EVENT_CALL_DELETED:
case RMAP_EVENT_FILTER_DELETED:
- if (rmap_debug)
+ if (CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP))
zlog_debug("Deleting dependency for filter %s in route-map %s",
dep_name, rmap_name);
dep = (struct route_map_dep *)hash_get(dephash, dname, NULL);
@@ -2959,7 +2962,7 @@ static int route_map_dep_update(struct hash *dephash, const char *dep_name,
}
if (dep) {
- if (rmap_debug)
+ if (CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP))
hash_iterate(dep->dep_rmap_hash,
route_map_print_dependency, dname);
}
@@ -3031,7 +3034,7 @@ static void route_map_process_dependency(struct hash_bucket *bucket, void *data)
dep_data = bucket->data;
rmap_name = dep_data->rname;
- if (rmap_debug)
+ if (CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP))
zlog_debug("Notifying %s of dependency", rmap_name);
if (route_map_master.event_hook)
(*route_map_master.event_hook)(rmap_name);
@@ -3079,7 +3082,7 @@ void route_map_notify_dependencies(const char *affected_name,
if (!dep->this_hash)
dep->this_hash = upd8_hash;
- if (rmap_debug)
+ if (CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP))
zlog_debug("Filter %s updated", dep->dep_name);
hash_iterate(dep->dep_rmap_hash, route_map_process_dependency,
(void *)event);
@@ -3157,24 +3160,34 @@ DEFUN (rmap_show_unused,
return vty_show_unused_route_map(vty);
}
-DEFUN (debug_rmap,
+DEFPY (debug_rmap,
debug_rmap_cmd,
- "debug route-map",
+ "debug route-map [detail]$detail",
DEBUG_STR
- "Debug option set for route-maps\n")
+ "Debug option set for route-maps\n"
+ "Detailed output\n")
{
- rmap_debug = true;
+ if (!detail)
+ SET_FLAG(rmap_debug, DEBUG_ROUTEMAP);
+ else
+ SET_FLAG(rmap_debug, DEBUG_ROUTEMAP | DEBUG_ROUTEMAP_DETAIL);
+
return CMD_SUCCESS;
}
-DEFUN (no_debug_rmap,
+DEFPY (no_debug_rmap,
no_debug_rmap_cmd,
- "no debug route-map",
+ "no debug route-map [detail]$detail",
NO_STR
DEBUG_STR
- "Debug option set for route-maps\n")
+ "Debug option set for route-maps\n"
+ "Detailed output\n")
{
- rmap_debug = false;
+ if (!detail)
+ UNSET_FLAG(rmap_debug, DEBUG_ROUTEMAP);
+ else
+ UNSET_FLAG(rmap_debug, DEBUG_ROUTEMAP | DEBUG_ROUTEMAP_DETAIL);
+
return CMD_SUCCESS;
}
@@ -3189,7 +3202,7 @@ static struct cmd_node rmap_debug_node = {
void route_map_show_debug(struct vty *vty)
{
- if (rmap_debug)
+ if (CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP))
vty_out(vty, "debug route-map\n");
}
@@ -3198,7 +3211,7 @@ static int rmap_config_write_debug(struct vty *vty)
{
int write = 0;
- if (rmap_debug) {
+ if (CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP)) {
vty_out(vty, "debug route-map\n");
write++;
}
@@ -3400,7 +3413,7 @@ void route_map_init(void)
8, route_map_dep_hash_make_key, route_map_dep_hash_cmp,
"Route Map Dep Hash");
- rmap_debug = false;
+ UNSET_FLAG(rmap_debug, DEBUG_ROUTEMAP);
route_map_cli_init();
diff --git a/lib/routemap.h b/lib/routemap.h
index 9c78e15735..ddcb8f2ddb 100644
--- a/lib/routemap.h
+++ b/lib/routemap.h
@@ -37,6 +37,10 @@ DECLARE_MTYPE(ROUTE_MAP_NAME);
DECLARE_MTYPE(ROUTE_MAP_RULE);
DECLARE_MTYPE(ROUTE_MAP_COMPILED);
+#define DEBUG_ROUTEMAP 0x01
+#define DEBUG_ROUTEMAP_DETAIL 0x02
+extern uint32_t rmap_debug;
+
/* Route map's type. */
enum route_map_type { RMAP_PERMIT, RMAP_DENY, RMAP_ANY };
diff --git a/lib/subdir.am b/lib/subdir.am
index ba576a80ed..8d00668c8c 100644
--- a/lib/subdir.am
+++ b/lib/subdir.am
@@ -158,6 +158,7 @@ clippy_scan += \
lib/nexthop_group.c \
lib/northbound_cli.c \
lib/plist.c \
+ lib/routemap.c \
lib/routemap_cli.c \
lib/thread.c \
lib/vty.c \
diff --git a/lib/yang_translator.c b/lib/yang_translator.c
index 67b7f9aa70..de5dc4d434 100644
--- a/lib/yang_translator.c
+++ b/lib/yang_translator.c
@@ -127,10 +127,15 @@ static void yang_mapping_add(struct yang_translator *translator, int dir,
}
}
+static void yang_tmodule_delete(struct yang_tmodule *tmodule)
+{
+ XFREE(MTYPE_YANG_TRANSLATOR_MODULE, tmodule);
+}
+
struct yang_translator *yang_translator_load(const char *path)
{
struct yang_translator *translator;
- struct yang_tmodule *tmodule;
+ struct yang_tmodule *tmodule = NULL;
const char *family;
struct lyd_node *dnode;
struct ly_set *set;
@@ -160,6 +165,7 @@ struct yang_translator *yang_translator_load(const char *path)
flog_warn(EC_LIB_YANG_TRANSLATOR_LOAD,
"%s: module translator \"%s\" is loaded already",
__func__, family);
+ yang_dnode_free(dnode);
return NULL;
}
@@ -282,15 +288,11 @@ struct yang_translator *yang_translator_load(const char *path)
error:
yang_dnode_free(dnode);
yang_translator_unload(translator);
+ yang_tmodule_delete(tmodule);
return NULL;
}
-static void yang_tmodule_delete(struct yang_tmodule *tmodule)
-{
- XFREE(MTYPE_YANG_TRANSLATOR_MODULE, tmodule);
-}
-
void yang_translator_unload(struct yang_translator *translator)
{
for (size_t i = 0; i < YANG_TRANSLATE_MAX; i++)
diff --git a/lib/zclient.c b/lib/zclient.c
index 413ae2c9f3..57c038a03f 100644
--- a/lib/zclient.c
+++ b/lib/zclient.c
@@ -1035,6 +1035,7 @@ int zapi_nexthop_encode(struct stream *s, const struct zapi_nexthop *api_nh,
*/
if (api_nh->label_num > 0) {
stream_putc(s, api_nh->label_num);
+ stream_putc(s, api_nh->label_type);
stream_put(s, &api_nh->labels[0],
api_nh->label_num * sizeof(mpls_label_t));
}
@@ -1397,6 +1398,7 @@ int zapi_nexthop_decode(struct stream *s, struct zapi_nexthop *api_nh,
/* MPLS labels for BGP-LU or Segment Routing */
if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_LABEL)) {
STREAM_GETC(s, api_nh->label_num);
+ STREAM_GETC(s, api_nh->label_type);
if (api_nh->label_num > MPLS_MAX_LABELS) {
flog_err(
EC_LIB_ZAPI_ENCODE,
@@ -1948,6 +1950,7 @@ int zapi_nexthop_from_nexthop(struct zapi_nexthop *znh,
znh->labels[i] = nh->nh_label->label[i];
znh->label_num = i;
+ znh->label_type = nh->nh_label_type;
SET_FLAG(znh->flags, ZAPI_NEXTHOP_FLAG_LABEL);
}
diff --git a/lib/zclient.h b/lib/zclient.h
index 8c4ce1b777..55957e4bee 100644
--- a/lib/zclient.h
+++ b/lib/zclient.h
@@ -427,6 +427,7 @@ struct zapi_nexthop {
/* MPLS labels for BGP-LU or Segment Routing */
uint8_t label_num;
+ enum lsp_types_t label_type;
mpls_label_t labels[MPLS_MAX_LABELS];
struct ethaddr rmac;
diff --git a/lib/zebra.h b/lib/zebra.h
index b2f5e5a848..8b783c514b 100644
--- a/lib/zebra.h
+++ b/lib/zebra.h
@@ -75,15 +75,6 @@
#include <endian.h>
#endif
-/* machine dependent includes */
-#ifdef HAVE_LINUX_VERSION_H
-#include <linux/version.h>
-#endif /* HAVE_LINUX_VERSION_H */
-
-#ifdef HAVE_ASM_TYPES_H
-#include <asm/types.h>
-#endif /* HAVE_ASM_TYPES_H */
-
/* misc include group */
#include <stdarg.h>
@@ -338,6 +329,14 @@ struct in_pktinfo {
#define strmatch(a,b) (!strcmp((a), (b)))
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define htonll(x) (((uint64_t)htonl((x)&0xFFFFFFFF) << 32) | htonl((x) >> 32))
+#define ntohll(x) (((uint64_t)ntohl((x)&0xFFFFFFFF) << 32) | ntohl((x) >> 32))
+#else
+#define htonll(x) (x)
+#define ntohll(x) (x)
+#endif
+
#ifndef INADDR_LOOPBACK
#define INADDR_LOOPBACK 0x7f000001 /* Internet address 127.0.0.1. */
#endif
@@ -375,17 +374,25 @@ typedef enum {
for (safi = SAFI_UNICAST; safi <= SAFI_MPLS_VPN; safi++)
/* Default Administrative Distance of each protocol. */
-#define ZEBRA_KERNEL_DISTANCE_DEFAULT 0
-#define ZEBRA_CONNECT_DISTANCE_DEFAULT 0
-#define ZEBRA_STATIC_DISTANCE_DEFAULT 1
-#define ZEBRA_RIP_DISTANCE_DEFAULT 120
-#define ZEBRA_RIPNG_DISTANCE_DEFAULT 120
-#define ZEBRA_OSPF_DISTANCE_DEFAULT 110
-#define ZEBRA_OSPF6_DISTANCE_DEFAULT 110
-#define ZEBRA_ISIS_DISTANCE_DEFAULT 115
-#define ZEBRA_IBGP_DISTANCE_DEFAULT 200
-#define ZEBRA_EBGP_DISTANCE_DEFAULT 20
-#define ZEBRA_TABLE_DISTANCE_DEFAULT 15
+#define ZEBRA_KERNEL_DISTANCE_DEFAULT 0
+#define ZEBRA_CONNECT_DISTANCE_DEFAULT 0
+#define ZEBRA_STATIC_DISTANCE_DEFAULT 1
+#define ZEBRA_RIP_DISTANCE_DEFAULT 120
+#define ZEBRA_RIPNG_DISTANCE_DEFAULT 120
+#define ZEBRA_OSPF_DISTANCE_DEFAULT 110
+#define ZEBRA_OSPF6_DISTANCE_DEFAULT 110
+#define ZEBRA_ISIS_DISTANCE_DEFAULT 115
+#define ZEBRA_IBGP_DISTANCE_DEFAULT 200
+#define ZEBRA_EBGP_DISTANCE_DEFAULT 20
+#define ZEBRA_TABLE_DISTANCE_DEFAULT 15
+#define ZEBRA_EIGRP_DISTANCE_DEFAULT 90
+#define ZEBRA_NHRP_DISTANCE_DEFAULT 10
+#define ZEBRA_LDP_DISTANCE_DEFAULT 150
+#define ZEBRA_BABEL_DISTANCE_DEFAULT 100
+#define ZEBRA_SHARP_DISTANCE_DEFAULT 150
+#define ZEBRA_PBR_DISTANCE_DEFAULT 200
+#define ZEBRA_OPENFABRIC_DISTANCE_DEFAULT 115
+#define ZEBRA_MAX_DISTANCE_DEFAULT 255
/* Flag manipulation macros. */
#define CHECK_FLAG(V,F) ((V) & (F))
@@ -411,9 +418,6 @@ typedef uint32_t route_tag_t;
#define ROUTE_TAG_MAX UINT32_MAX
#define ROUTE_TAG_PRI PRIu32
-/* Name of hook calls */
-#define ZEBRA_ON_RIB_PROCESS_HOOK_CALL "on_rib_process_dplane_results"
-
#ifdef __cplusplus
}
#endif
diff --git a/ospfd/ospf_routemap.c b/ospfd/ospf_routemap.c
index b1216626c4..63460c773e 100644
--- a/ospfd/ospf_routemap.c
+++ b/ospfd/ospf_routemap.c
@@ -134,8 +134,13 @@ route_match_ip_nexthop(void *rule, const struct prefix *prefix, void *object)
p.prefixlen = IPV4_MAX_BITLEN;
alist = access_list_lookup(AFI_IP, (char *)rule);
- if (alist == NULL)
+ if (alist == NULL) {
+ if (CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP_DETAIL))
+ zlog_debug(
+ "%s: Access-List Specified: %s does not exist defaulting to NO_MATCH",
+ __func__, (char *)rule);
return RMAP_NOMATCH;
+ }
return (access_list_apply(alist, &p) == FILTER_DENY ? RMAP_NOMATCH
: RMAP_MATCH);
@@ -177,8 +182,13 @@ route_match_ip_next_hop_prefix_list(void *rule, const struct prefix *prefix,
p.prefixlen = IPV4_MAX_BITLEN;
plist = prefix_list_lookup(AFI_IP, (char *)rule);
- if (plist == NULL)
+ if (plist == NULL) {
+ if (CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP_DETAIL))
+ zlog_debug(
+ "%s: Prefix List %s specified does not exist defaulting to NO_MATCH",
+ __func__, (char *)rule);
return RMAP_NOMATCH;
+ }
return (prefix_list_apply(plist, &p) == PREFIX_DENY ? RMAP_NOMATCH
: RMAP_MATCH);
@@ -249,8 +259,13 @@ route_match_ip_address(void *rule, const struct prefix *prefix, void *object)
/* struct prefix_ipv4 match; */
alist = access_list_lookup(AFI_IP, (char *)rule);
- if (alist == NULL)
+ if (alist == NULL) {
+ if (CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP_DETAIL))
+ zlog_debug(
+ "%s: Access-List Specified: %s does not exist defaulting to NO_MATCH",
+ __func__, (char *)rule);
return RMAP_NOMATCH;
+ }
return (access_list_apply(alist, prefix) == FILTER_DENY ? RMAP_NOMATCH
: RMAP_MATCH);
@@ -285,8 +300,14 @@ route_match_ip_address_prefix_list(void *rule, const struct prefix *prefix,
struct prefix_list *plist;
plist = prefix_list_lookup(AFI_IP, (char *)rule);
- if (plist == NULL)
+ if (plist == NULL) {
+ if (CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP_DETAIL))
+ zlog_debug(
+ "%s: Prefix List %s specified does not exist defaulting to NO_MATCH",
+ __func__, (char *)rule);
+
return RMAP_NOMATCH;
+ }
return (prefix_list_apply(plist, prefix) == PREFIX_DENY ? RMAP_NOMATCH
: RMAP_MATCH);
diff --git a/ospfd/ospf_ti_lfa.c b/ospfd/ospf_ti_lfa.c
index 28d24bcbe6..76f61f783e 100644
--- a/ospfd/ospf_ti_lfa.c
+++ b/ospfd/ospf_ti_lfa.c
@@ -723,7 +723,7 @@ static void ospf_ti_lfa_generate_q_spaces(struct ospf_area *area,
if (q_space->label_stack) {
mpls_label2str(q_space->label_stack->num_labels,
q_space->label_stack->label, label_buf,
- MPLS_LABEL_STRLEN, true);
+ MPLS_LABEL_STRLEN, 0, true);
zlog_info(
"%s: Generated label stack %s for root %pI4 and destination %pI4 for %s",
__func__, label_buf, &p_space->root->id,
@@ -1050,7 +1050,7 @@ void ospf_ti_lfa_insert_backup_paths(struct ospf_area *area,
path->srni.backup_label_stack
->num_labels,
path->srni.backup_label_stack->label,
- label_buf, MPLS_LABEL_STRLEN, true);
+ label_buf, MPLS_LABEL_STRLEN, 0, true);
if (IS_DEBUG_OSPF_TI_LFA)
zlog_debug(
"%s: inserted backup path %s for prefix %pFX, router id %pI4 and nexthop %pI4.",
diff --git a/pathd/path_pcep_controller.c b/pathd/path_pcep_controller.c
index 380d1ab221..84b74aed86 100644
--- a/pathd/path_pcep_controller.c
+++ b/pathd/path_pcep_controller.c
@@ -22,7 +22,6 @@
#include "command.h"
#include "libfrr.h"
#include "printfrr.h"
-#include "lib/version.h"
#include "northbound.h"
#include "frr_pthread.h"
#include "jhash.h"
diff --git a/pathd/path_pcep_pcc.c b/pathd/path_pcep_pcc.c
index 524c77c1fb..6ad5d6caff 100644
--- a/pathd/path_pcep_pcc.c
+++ b/pathd/path_pcep_pcc.c
@@ -33,7 +33,6 @@
#include "command.h"
#include "libfrr.h"
#include "printfrr.h"
-#include "lib/version.h"
#include "northbound.h"
#include "frr_pthread.h"
#include "jhash.h"
diff --git a/pimd/pim6_mld.c b/pimd/pim6_mld.c
index dc5e67e2c5..6faa53afe0 100644
--- a/pimd/pim6_mld.c
+++ b/pimd/pim6_mld.c
@@ -2737,7 +2737,7 @@ static void gm_show_joins_one(struct vty *vty, struct gm_if *gm_ifp,
}
js_src = json_object_new_object();
- json_object_object_addf(js_group, js_src, "%pPA",
+ json_object_object_addf(js_group, js_src, "%pPAs",
&sg->sgaddr.src);
json_object_string_add(js_src, "state", gm_states[sg->state]);
@@ -2800,6 +2800,7 @@ static void gm_show_joins_vrf(struct vty *vty, struct vrf *vrf,
if (js) {
js_vrf = json_object_new_object();
+ json_object_string_add(js_vrf, "vrf", vrf->name);
json_object_object_add(js, vrf->name, js_vrf);
}
diff --git a/pimd/pim_main.c b/pimd/pim_main.c
index c168c0b098..dadc7827c4 100644
--- a/pimd/pim_main.c
+++ b/pimd/pim_main.c
@@ -32,7 +32,6 @@
#include "filter.h"
#include "vty.h"
#include "sigevent.h"
-#include "lib/version.h"
#include "prefix.h"
#include "plist.h"
#include "vrf.h"
diff --git a/redhat/frr.spec.in b/redhat/frr.spec.in
index a3f5f6b0cd..14973ba890 100644
--- a/redhat/frr.spec.in
+++ b/redhat/frr.spec.in
@@ -793,7 +793,9 @@ sed -i 's/ -M rpki//' %{_sysconfdir}/frr/daemons
%changelog
-* Tue Nov 01 2022 Martin Winter <mwinter@opensourcerouting.org> - %{version}
+* Tue Feb 07 2023 Martin Winter <mwinter@opensourcerouting.org> - %{version}
+
+* Tue Feb 07 2023 Donatas Abraitis <donatas@opensourcerouting.org> - 8.5
* Tue Nov 01 2022 Jafar Al-Gharaibeh <jafar@atcorp.com> - 8.4
- New BGP command (neighbor PEER soo) to configure SoO to prevent routing loops and suboptimal routing on dual-homed sites.
diff --git a/sharpd/sharp_zebra.c b/sharpd/sharp_zebra.c
index bf5b98544e..fcea484b34 100644
--- a/sharpd/sharp_zebra.c
+++ b/sharpd/sharp_zebra.c
@@ -271,6 +271,11 @@ static bool route_add(const struct prefix *p, vrf_id_t vrf_id, uint8_t instance,
api.nhgid = nhgid;
} else {
for (ALL_NEXTHOPS_PTR(nhg, nh)) {
+ /* Check if we set a VNI label */
+ if (nh->nh_label &&
+ (nh->nh_label_type == ZEBRA_LSP_EVPN))
+ SET_FLAG(api.flags, ZEBRA_FLAG_EVPN_ROUTE);
+
api_nh = &api.nexthops[i];
zapi_nexthop_from_nexthop(api_nh, nh);
diff --git a/tests/ospfd/common.c b/tests/ospfd/common.c
index eb30c4016e..ef5e3ed177 100644
--- a/tests/ospfd/common.c
+++ b/tests/ospfd/common.c
@@ -74,7 +74,8 @@ void print_route_table(struct vty *vty, struct route_table *rt)
label_stack = path->srni.backup_label_stack;
mpls_label2str(label_stack->num_labels,
label_stack->label, buf,
- MPLS_LABEL_STRLEN, true);
+ MPLS_LABEL_STRLEN,
+ ZEBRA_LSP_NONE, true);
vty_out(vty, " and backup path %s", buf);
}
vty_out(vty, "\n");
diff --git a/tests/ospfd/test_ospf_spf.c b/tests/ospfd/test_ospf_spf.c
index 73f2e29834..b8a2aef69e 100644
--- a/tests/ospfd/test_ospf_spf.c
+++ b/tests/ospfd/test_ospf_spf.c
@@ -107,7 +107,7 @@ static void test_run_spf(struct vty *vty, struct ospf *ospf,
->num_labels,
q_space->label_stack->label,
label_buf, MPLS_LABEL_STRLEN,
- true);
+ ZEBRA_LSP_NONE, true);
vty_out(vty, "\nLabel stack: %s\n",
label_buf);
} else {
diff --git a/tests/topotests/bgp_default_originate_withdraw/__init__.py b/tests/topotests/bgp_default_originate_withdraw/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/topotests/bgp_default_originate_withdraw/__init__.py
diff --git a/tests/topotests/bgp_default_originate_withdraw/r1/bgpd.conf b/tests/topotests/bgp_default_originate_withdraw/r1/bgpd.conf
new file mode 100644
index 0000000000..6813b02be7
--- /dev/null
+++ b/tests/topotests/bgp_default_originate_withdraw/r1/bgpd.conf
@@ -0,0 +1,12 @@
+router bgp 65001
+ no bgp ebgp-requires-policy
+ neighbor 192.168.1.2 remote-as external
+ neighbor 192.168.1.2 timers 1 3
+ neighbor 192.168.1.2 timers connect 1
+ neighbor 192.168.2.2 remote-as external
+ neighbor 192.168.2.2 timers 1 3
+ neighbor 192.168.2.2 timers connect 1
+ address-family ipv4
+ neighbor 192.168.1.2 default-originate
+ exit-address-family
+!
diff --git a/tests/topotests/bgp_default_originate_withdraw/r1/zebra.conf b/tests/topotests/bgp_default_originate_withdraw/r1/zebra.conf
new file mode 100644
index 0000000000..3692361fb3
--- /dev/null
+++ b/tests/topotests/bgp_default_originate_withdraw/r1/zebra.conf
@@ -0,0 +1,7 @@
+!
+interface r1-eth0
+ ip address 192.168.1.1/24
+!
+interface r1-eth1
+ ip address 192.168.2.1/24
+!
diff --git a/tests/topotests/bgp_default_originate_withdraw/r2/bgpd.conf b/tests/topotests/bgp_default_originate_withdraw/r2/bgpd.conf
new file mode 100644
index 0000000000..60e6236801
--- /dev/null
+++ b/tests/topotests/bgp_default_originate_withdraw/r2/bgpd.conf
@@ -0,0 +1,9 @@
+router bgp 65002
+ no bgp ebgp-requires-policy
+ neighbor 192.168.1.1 remote-as external
+ neighbor 192.168.1.1 timers 1 3
+ neighbor 192.168.1.1 timers connect 1
+ address-family ipv4 unicast
+ network 192.168.2.0/24
+ exit-address-family
+!
diff --git a/tests/topotests/bgp_default_originate_withdraw/r2/zebra.conf b/tests/topotests/bgp_default_originate_withdraw/r2/zebra.conf
new file mode 100644
index 0000000000..0c95656663
--- /dev/null
+++ b/tests/topotests/bgp_default_originate_withdraw/r2/zebra.conf
@@ -0,0 +1,4 @@
+!
+interface r2-eth0
+ ip address 192.168.1.2/24
+!
diff --git a/tests/topotests/bgp_default_originate_withdraw/r3/bgpd.conf b/tests/topotests/bgp_default_originate_withdraw/r3/bgpd.conf
new file mode 100644
index 0000000000..547cf86b3f
--- /dev/null
+++ b/tests/topotests/bgp_default_originate_withdraw/r3/bgpd.conf
@@ -0,0 +1,9 @@
+router bgp 65003
+ no bgp ebgp-requires-policy
+ neighbor 192.168.2.1 remote-as external
+ neighbor 192.168.2.1 timers 1 3
+ neighbor 192.168.2.1 timers connect 1
+ address-family ipv4 unicast
+ network 0.0.0.0/0
+ exit-address-family
+!
diff --git a/tests/topotests/bgp_default_originate_withdraw/r3/zebra.conf b/tests/topotests/bgp_default_originate_withdraw/r3/zebra.conf
new file mode 100644
index 0000000000..7ccdcfd0d8
--- /dev/null
+++ b/tests/topotests/bgp_default_originate_withdraw/r3/zebra.conf
@@ -0,0 +1,5 @@
+!
+interface r3-eth0
+ ip address 192.168.2.2/24
+!
+ip route 0.0.0.0/0 Null0
diff --git a/tests/topotests/bgp_default_originate_withdraw/test_bgp_default_originate_withdraw.py b/tests/topotests/bgp_default_originate_withdraw/test_bgp_default_originate_withdraw.py
new file mode 100644
index 0000000000..e25f85af85
--- /dev/null
+++ b/tests/topotests/bgp_default_originate_withdraw/test_bgp_default_originate_withdraw.py
@@ -0,0 +1,159 @@
+#!/usr/bin/env python
+# SPDX-License-Identifier: ISC
+
+#
+# Copyright (c) 2022 by
+# Donatas Abraitis <donatas@opensourcerouting.org>
+#
+
+"""
+Check if bgpd do not crash if we use default-originate while
+received a default route from the neighbor as well. 0.0.0.0/0
+MUST be kept in RIB even if we remove default-originate from
+the neighbor.
+"""
+
+import os
+import sys
+import json
+import pytest
+import functools
+
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+
+# pylint: disable=C0413
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.common_config import step
+
+pytestmark = [pytest.mark.bgpd]
+
+
+def build_topo(tgen):
+ for routern in range(1, 4):
+ tgen.add_router("r{}".format(routern))
+
+ switch = tgen.add_switch("s1")
+ switch.add_link(tgen.gears["r1"])
+ switch.add_link(tgen.gears["r2"])
+
+ switch = tgen.add_switch("s2")
+ switch.add_link(tgen.gears["r1"])
+ switch.add_link(tgen.gears["r3"])
+
+
+def setup_module(mod):
+ tgen = Topogen(build_topo, mod.__name__)
+ tgen.start_topology()
+
+ router_list = tgen.routers()
+
+ for i, (rname, router) in enumerate(router_list.items(), 1):
+ router.load_config(
+ TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
+ )
+ router.load_config(
+ TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname))
+ )
+
+ tgen.start_router()
+
+
+def teardown_module(mod):
+ tgen = get_topogen()
+ tgen.stop_topology()
+
+
+def test_bgp_default_originate_with_default_received():
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ r1 = tgen.gears["r1"]
+
+ def _bgp_default_received_from_r3():
+ output = json.loads(r1.vtysh_cmd("show bgp ipv4 unicast 0.0.0.0/0 json"))
+ expected = {
+ "paths": [
+ {
+ "nexthops": [
+ {
+ "hostname": "r3",
+ "ip": "192.168.2.2",
+ }
+ ],
+ }
+ ],
+ }
+ return topotest.json_cmp(output, expected)
+
+ test_func = functools.partial(_bgp_default_received_from_r3)
+ _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+ assert result is None, "Cannot see default route received from r3"
+
+ def _bgp_advertised_default_originate_to_r2():
+ output = json.loads(
+ r1.vtysh_cmd(
+ "show bgp ipv4 unicast neighbors 192.168.1.2 advertised-routes json"
+ )
+ )
+ expected = {
+ "bgpOriginatingDefaultNetwork": "0.0.0.0/0",
+ }
+ return topotest.json_cmp(output, expected)
+
+ test_func = functools.partial(_bgp_advertised_default_originate_to_r2)
+ _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+ assert result is None, "Cannot see default-originate route advertised to r2"
+
+ step("Disable default-originate for r2")
+ r1.vtysh_cmd(
+ """
+ configure
+ router bgp
+ address-family ipv4 unicast
+ no neighbor 192.168.1.2 default-originate
+ """
+ )
+
+ def _bgp_advertised_default_from_r3_to_r2():
+ output = json.loads(
+ r1.vtysh_cmd(
+ "show bgp ipv4 unicast neighbors 192.168.1.2 advertised-routes json"
+ )
+ )
+ expected = {
+ "bgpOriginatingDefaultNetwork": None,
+ "advertisedRoutes": {
+ "0.0.0.0/0": {
+ "valid": True,
+ }
+ },
+ }
+ return topotest.json_cmp(output, expected)
+
+ test_func = functools.partial(_bgp_advertised_default_from_r3_to_r2)
+ _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+ assert result is None, "Cannot see default route advertised to r2"
+
+ step("Enable default-originate for r2")
+ r1.vtysh_cmd(
+ """
+ configure
+ router bgp
+ address-family ipv4 unicast
+ neighbor 192.168.1.2 default-originate
+ do clear ip bgp *
+ """
+ )
+
+ step("Check if default-originate route advertised to r2")
+ test_func = functools.partial(_bgp_advertised_default_originate_to_r2)
+ _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+ assert result is None, "Cannot see default-originate route advertised to r2"
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/bgp_evpn_vxlan_svd_topo1/P1/bgpd.conf b/tests/topotests/bgp_evpn_vxlan_svd_topo1/P1/bgpd.conf
new file mode 100644
index 0000000000..cdf4cb4feb
--- /dev/null
+++ b/tests/topotests/bgp_evpn_vxlan_svd_topo1/P1/bgpd.conf
@@ -0,0 +1 @@
+!
diff --git a/tests/topotests/bgp_evpn_vxlan_svd_topo1/P1/ospfd.conf b/tests/topotests/bgp_evpn_vxlan_svd_topo1/P1/ospfd.conf
new file mode 100644
index 0000000000..2db7edb806
--- /dev/null
+++ b/tests/topotests/bgp_evpn_vxlan_svd_topo1/P1/ospfd.conf
@@ -0,0 +1,13 @@
+!
+router ospf
+ network 10.20.0.0/16 area 0
+ network 10.20.20.20/32 area 0
+!
+int P1-eth0
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
+!
+int P1-eth1
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
+!
diff --git a/tests/topotests/bgp_evpn_vxlan_svd_topo1/P1/zebra.conf b/tests/topotests/bgp_evpn_vxlan_svd_topo1/P1/zebra.conf
new file mode 100644
index 0000000000..95b5da8402
--- /dev/null
+++ b/tests/topotests/bgp_evpn_vxlan_svd_topo1/P1/zebra.conf
@@ -0,0 +1,7 @@
+!
+interface lo
+ ip address 10.20.20.20/32
+interface P1-eth0
+ ip address 10.20.1.2/24
+interface P1-eth1
+ ip address 10.20.2.2/24
diff --git a/tests/topotests/bgp_evpn_vxlan_svd_topo1/PE1/bgpd.conf b/tests/topotests/bgp_evpn_vxlan_svd_topo1/PE1/bgpd.conf
new file mode 100644
index 0000000000..39ac8ca69c
--- /dev/null
+++ b/tests/topotests/bgp_evpn_vxlan_svd_topo1/PE1/bgpd.conf
@@ -0,0 +1,19 @@
+router bgp 65000
+ timers 3 9
+ bgp router-id 10.10.10.10
+ no bgp default ipv4-unicast
+ neighbor 10.30.30.30 remote-as 65000
+ neighbor 10.30.30.30 update-source lo
+ neighbor 10.30.30.30 timers 3 10
+ address-family l2vpn evpn
+ neighbor 10.30.30.30 activate
+ advertise-all-vni
+ advertise-svi-ip
+!
+router bgp 65000 vrf vrf-red
+ !
+ address-family l2vpn evpn
+ route-target import *:300
+ route-target import auto
+ exit-address-family
+!
diff --git a/tests/topotests/bgp_evpn_vxlan_svd_topo1/PE1/evpn.vni.json b/tests/topotests/bgp_evpn_vxlan_svd_topo1/PE1/evpn.vni.json
new file mode 100644
index 0000000000..98ae92ce55
--- /dev/null
+++ b/tests/topotests/bgp_evpn_vxlan_svd_topo1/PE1/evpn.vni.json
@@ -0,0 +1,16 @@
+{
+ "vni":101,
+ "type":"L2",
+ "vrf":"default",
+ "vxlanInterface":"vxlan0",
+ "vtepIp":"10.10.10.10",
+ "mcastGroup":"0.0.0.0",
+ "advertiseGatewayMacip":"No",
+ "remoteVteps":[
+ {
+ "ip":"10.30.30.30",
+ "flood":"HER"
+ }
+ ]
+}
+
diff --git a/tests/topotests/bgp_evpn_vxlan_svd_topo1/PE1/ospfd.conf b/tests/topotests/bgp_evpn_vxlan_svd_topo1/PE1/ospfd.conf
new file mode 100644
index 0000000000..f1c2b42dc1
--- /dev/null
+++ b/tests/topotests/bgp_evpn_vxlan_svd_topo1/PE1/ospfd.conf
@@ -0,0 +1,9 @@
+!
+router ospf
+ network 10.20.0.0/16 area 0
+ network 10.10.10.10/32 area 0
+!
+int PE1-eth1
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
+!
diff --git a/tests/topotests/bgp_evpn_vxlan_svd_topo1/PE1/zebra.conf b/tests/topotests/bgp_evpn_vxlan_svd_topo1/PE1/zebra.conf
new file mode 100644
index 0000000000..8c6cf3e6d4
--- /dev/null
+++ b/tests/topotests/bgp_evpn_vxlan_svd_topo1/PE1/zebra.conf
@@ -0,0 +1,13 @@
+!
+log file zebra.log
+!
+vrf vrf-red
+ vni 100
+ exit-vrf
+!
+!
+interface lo
+ ip address 10.10.10.10/32
+interface PE1-eth1
+ ip address 10.20.1.1/24
+!
diff --git a/tests/topotests/bgp_evpn_vxlan_svd_topo1/PE2/bgpd.conf b/tests/topotests/bgp_evpn_vxlan_svd_topo1/PE2/bgpd.conf
new file mode 100644
index 0000000000..10809da283
--- /dev/null
+++ b/tests/topotests/bgp_evpn_vxlan_svd_topo1/PE2/bgpd.conf
@@ -0,0 +1,24 @@
+!
+router bgp 65000
+ timers bgp 3 9
+ bgp router-id 10.30.30.30
+ no bgp default ipv4-unicast
+ neighbor 10.10.10.10 remote-as 65000
+ neighbor 10.10.10.10 update-source lo
+ neighbor 10.10.10.10 timers 3 10
+ !
+ address-family l2vpn evpn
+ neighbor 10.10.10.10 activate
+ advertise-all-vni
+ advertise-svi-ip
+!
+router bgp 65000 vrf vrf-blue
+ !
+ address-family ipv4 unicast
+ redistribute static
+ exit-address-family
+ !
+ address-family l2vpn evpn
+ advertise ipv4 unicast
+ exit-address-family
+!
diff --git a/tests/topotests/bgp_evpn_vxlan_svd_topo1/PE2/evpn.vni.json b/tests/topotests/bgp_evpn_vxlan_svd_topo1/PE2/evpn.vni.json
new file mode 100644
index 0000000000..5c059786b2
--- /dev/null
+++ b/tests/topotests/bgp_evpn_vxlan_svd_topo1/PE2/evpn.vni.json
@@ -0,0 +1,15 @@
+{
+ "vni":101,
+ "type":"L2",
+ "vrf":"default",
+ "vxlanInterface":"vxlan0",
+ "vtepIp":"10.30.30.30",
+ "mcastGroup":"0.0.0.0",
+ "advertiseGatewayMacip":"No",
+ "remoteVteps":[
+ {
+ "ip":"10.10.10.10",
+ "flood":"HER"
+ }
+ ]
+}
diff --git a/tests/topotests/bgp_evpn_vxlan_svd_topo1/PE2/ospfd.conf b/tests/topotests/bgp_evpn_vxlan_svd_topo1/PE2/ospfd.conf
new file mode 100644
index 0000000000..065c993303
--- /dev/null
+++ b/tests/topotests/bgp_evpn_vxlan_svd_topo1/PE2/ospfd.conf
@@ -0,0 +1,9 @@
+!
+router ospf
+ network 10.20.0.0/16 area 0
+ network 10.30.30.30/32 area 0
+!
+int PE2-eth0
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
+!
diff --git a/tests/topotests/bgp_evpn_vxlan_svd_topo1/PE2/zebra.conf b/tests/topotests/bgp_evpn_vxlan_svd_topo1/PE2/zebra.conf
new file mode 100644
index 0000000000..cee4355e40
--- /dev/null
+++ b/tests/topotests/bgp_evpn_vxlan_svd_topo1/PE2/zebra.conf
@@ -0,0 +1,17 @@
+vrf vrf-blue
+ vni 300
+ exit-vrf
+!
+vrf vrf-red
+ vni 100
+ exit-vrf
+!
+interface lo
+ ip address 10.30.30.30/32
+interface PE2-eth0
+ ip address 10.20.2.3/24
+!
+interface vrf-blue
+ ip address 30.0.0.3/24
+!
+ip route 4.4.4.1/32 30.0.0.100 vrf vrf-blue
diff --git a/tests/topotests/bgp_evpn_vxlan_svd_topo1/__init__.py b/tests/topotests/bgp_evpn_vxlan_svd_topo1/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/topotests/bgp_evpn_vxlan_svd_topo1/__init__.py
diff --git a/tests/topotests/bgp_evpn_vxlan_svd_topo1/host1/bgpd.conf b/tests/topotests/bgp_evpn_vxlan_svd_topo1/host1/bgpd.conf
new file mode 100644
index 0000000000..cdf4cb4feb
--- /dev/null
+++ b/tests/topotests/bgp_evpn_vxlan_svd_topo1/host1/bgpd.conf
@@ -0,0 +1 @@
+!
diff --git a/tests/topotests/bgp_evpn_vxlan_svd_topo1/host1/ospfd.conf b/tests/topotests/bgp_evpn_vxlan_svd_topo1/host1/ospfd.conf
new file mode 100644
index 0000000000..cdf4cb4feb
--- /dev/null
+++ b/tests/topotests/bgp_evpn_vxlan_svd_topo1/host1/ospfd.conf
@@ -0,0 +1 @@
+!
diff --git a/tests/topotests/bgp_evpn_vxlan_svd_topo1/host1/zebra.conf b/tests/topotests/bgp_evpn_vxlan_svd_topo1/host1/zebra.conf
new file mode 100644
index 0000000000..91fae9eeba
--- /dev/null
+++ b/tests/topotests/bgp_evpn_vxlan_svd_topo1/host1/zebra.conf
@@ -0,0 +1,3 @@
+!
+int host1-eth0
+ ip address 10.10.1.55/24
diff --git a/tests/topotests/bgp_evpn_vxlan_svd_topo1/host2/bgpd.conf b/tests/topotests/bgp_evpn_vxlan_svd_topo1/host2/bgpd.conf
new file mode 100644
index 0000000000..cdf4cb4feb
--- /dev/null
+++ b/tests/topotests/bgp_evpn_vxlan_svd_topo1/host2/bgpd.conf
@@ -0,0 +1 @@
+!
diff --git a/tests/topotests/bgp_evpn_vxlan_svd_topo1/host2/ospfd.conf b/tests/topotests/bgp_evpn_vxlan_svd_topo1/host2/ospfd.conf
new file mode 100644
index 0000000000..cdf4cb4feb
--- /dev/null
+++ b/tests/topotests/bgp_evpn_vxlan_svd_topo1/host2/ospfd.conf
@@ -0,0 +1 @@
+!
diff --git a/tests/topotests/bgp_evpn_vxlan_svd_topo1/host2/zebra.conf b/tests/topotests/bgp_evpn_vxlan_svd_topo1/host2/zebra.conf
new file mode 100644
index 0000000000..df9adeb3b5
--- /dev/null
+++ b/tests/topotests/bgp_evpn_vxlan_svd_topo1/host2/zebra.conf
@@ -0,0 +1,3 @@
+!
+interface host2-eth0
+ ip address 10.10.1.56/24
diff --git a/tests/topotests/bgp_evpn_vxlan_svd_topo1/test_bgp_evpn_vxlan_svd.py b/tests/topotests/bgp_evpn_vxlan_svd_topo1/test_bgp_evpn_vxlan_svd.py
new file mode 100755
index 0000000000..f8af210ed7
--- /dev/null
+++ b/tests/topotests/bgp_evpn_vxlan_svd_topo1/test_bgp_evpn_vxlan_svd.py
@@ -0,0 +1,534 @@
+#!/usr/bin/env python
+
+#
+# test_bgp_evpn_vxlan_svd.py
+# Part of NetDEF Topology Tests
+#
+# Copyright (c) 2020 NVIDIA Corporation
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+"""
+test_bgp_evpn_vxlan.py: Test VXLAN EVPN MAC and route signalling over BGP
+using Single Vxlan Device Configurtion
+"""
+
+import os
+import sys
+import json
+from functools import partial
+from time import sleep
+import pytest
+
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.topolog import logger
+from lib.common_config import required_linux_kernel_version
+
+# Required to instantiate the topology builder class.
+
+pytestmark = [pytest.mark.bgpd, pytest.mark.ospfd]
+
+
+def build_topo(tgen):
+ "Build function"
+
+ # This function only purpose is to define allocation and relationship
+ # between routers, switches and hosts.
+ #
+ #
+ # Create routers
+ tgen.add_router("P1")
+ tgen.add_router("PE1")
+ tgen.add_router("PE2")
+ tgen.add_router("host1")
+ tgen.add_router("host2")
+
+ # Host1-PE1
+ switch = tgen.add_switch("s1")
+ switch.add_link(tgen.gears["host1"])
+ switch.add_link(tgen.gears["PE1"])
+
+ # PE1-P1
+ switch = tgen.add_switch("s2")
+ switch.add_link(tgen.gears["PE1"])
+ switch.add_link(tgen.gears["P1"])
+
+ # P1-PE2
+ switch = tgen.add_switch("s3")
+ switch.add_link(tgen.gears["P1"])
+ switch.add_link(tgen.gears["PE2"])
+
+ # PE2-host2
+ switch = tgen.add_switch("s4")
+ switch.add_link(tgen.gears["PE2"])
+ switch.add_link(tgen.gears["host2"])
+
+def setup_pe_router(tgen, pe_name, tunnel_local_ip, svi_ip, intf):
+ pe = tgen.gears[pe_name]
+
+ # configure vlan aware bridge
+ pe.run("ip link add name bridge type bridge stp_state 0")
+ pe.run("ip link set dev bridge type bridge vlan_filtering 1")
+ pe.run("bridge vlan add vid 1 dev bridge self")
+ pe.run("ip link set dev bridge up")
+
+ # setup svi
+ pe.run("ip link add link bridge name vlan1 type vlan id 1 protocol 802.1q")
+ pe.run("ip link set dev vlan1 up")
+ pe.run("ip addr add {0} dev vlan1".format(svi_ip))
+ pe.run("/sbin/sysctl net.ipv4.conf.vlan1.arp_accept=1")
+
+ # setup single vxlan device
+ pe.run(
+ "ip link add dev vxlan0 type vxlan dstport 4789 local {0} nolearning external".format(tunnel_local_ip)
+ )
+ pe.run("ip link set dev vxlan0 master bridge")
+ pe.run("bridge link set dev vxlan0 vlan_tunnel on")
+ pe.run("bridge link set dev vxlan0 neigh_suppress on")
+ pe.run("bridge link set dev vxlan0 learning off")
+ pe.run("bridge vlan add dev vxlan0 vid 1")
+ pe.run("bridge vlan add dev vxlan0 vid 1 tunnel_info id 101")
+ pe.run("ip link set up dev vxlan0")
+
+ # setup PE interface
+ pe.run("ip link set dev {0}-{1} master bridge".format(pe_name, intf))
+ pe.run("bridge vlan del vid 1 dev {0}-{1}".format(pe_name, intf))
+ pe.run("bridge vlan del vid 1 untagged pvid dev {0}-{1}".format(pe_name, intf))
+ pe.run("bridge vlan add vid 1 dev {0}-{1}".format(pe_name, intf))
+ pe.run("bridge vlan add vid 1 pvid untagged dev {0}-{1}".format(pe_name, intf))
+
+ # l3vni 100
+ pe.run("ip link add vrf-red type vrf table 1400")
+ pe.run("ip link add link bridge name vlan100 type vlan id 100 protocol 802.1q")
+ pe.run("ip link set dev vlan100 master vrf-blue")
+ pe.run("ip link set dev vlan100 up")
+ pe.run("bridge vlan add vid 100 dev bridge self")
+ pe.run("bridge vlan add dev vxlan0 vid 100")
+ pe.run("bridge vlan add dev vxlan0 vid 100 tunnel_info id 100")
+
+ # add a vrf for testing DVNI
+ if pe_name == "PE2":
+ pe.run("ip link add vrf-blue type vrf table 2400")
+ pe.run("ip link add link bridge name vlan300 type vlan id 300 protocol 802.1q")
+ pe.run("ip link set dev vlan300 master vrf-blue")
+ pe.run("ip link set dev vlan300 up")
+ pe.run("bridge vlan add vid 300 dev bridge self")
+ pe.run("bridge vlan add dev vxlan0 vid 300")
+ pe.run("bridge vlan add dev vxlan0 vid 300 tunnel_info id 300")
+
+def setup_p_router(tgen, p_name):
+ p1 = tgen.gears[p_name]
+ p1.run("sysctl -w net.ipv4.ip_forward=1")
+
+def setup_module(mod):
+ "Sets up the pytest environment"
+
+ result = required_linux_kernel_version("5.7")
+ if result is not True:
+ pytest.skip("Kernel requirements are not met, kernel version should be >= 5.7")
+
+ # This function initiates the topology build with Topogen...
+ tgen = Topogen(build_topo, mod.__name__)
+
+ # ... and here it calls Mininet initialization functions.
+ tgen.start_topology()
+
+ setup_pe_router(tgen, "PE1", "10.10.10.10", "10.10.1.1/24", "eth0")
+ setup_pe_router(tgen, "PE2", "10.30.30.30", "10.10.1.3/24", "eth1")
+ setup_p_router(tgen, "P1")
+
+ # This is a sample of configuration loading.
+ router_list = tgen.routers()
+
+ # For all registred routers, load the zebra configuration file
+ for rname, router in router_list.items():
+ router.load_config(
+ TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
+ )
+ router.load_config(
+ TopoRouter.RD_OSPF, os.path.join(CWD, "{}/ospfd.conf".format(rname))
+ )
+ router.load_config(
+ TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname))
+ )
+
+ # After loading the configurations, this function loads configured daemons.
+ tgen.start_router()
+
+
+def teardown_module(mod):
+ "Teardown the pytest environment"
+ tgen = get_topogen()
+
+ #tgen.mininet_cli()
+ # This function tears down the whole topology.
+ tgen.stop_topology()
+
+
+def show_vni_json_elide_ifindex(pe, vni, expected):
+ output_json = pe.vtysh_cmd("show evpn vni {} json".format(vni), isjson=True)
+
+ if "ifindex" in output_json:
+ output_json.pop("ifindex")
+
+ return topotest.json_cmp(output_json, expected)
+
+
+def check_vni_macs_present(tgen, router, vni, maclist):
+ result = router.vtysh_cmd("show evpn mac vni {} json".format(vni), isjson=True)
+ for rname, ifname in maclist:
+ m = tgen.net.macs[(rname, ifname)]
+ if m not in result["macs"]:
+ return "MAC ({}) for interface {} on {} missing on {} from {}".format(
+ m, ifname, rname, router.name, json.dumps(result, indent=4)
+ )
+ return None
+
+def check_flood_entry_present(pe, vni, vtep):
+ if not topotest.iproute2_is_fdb_get_capable():
+ return None
+
+ output = pe.run("bridge fdb get 00:00:00:00:00:00 dev vxlan0 vni {} self".format(vni))
+
+ if str(vtep) not in output:
+ return output
+
+ return None
+
+def test_pe1_converge_evpn():
+ "Wait for protocol convergence"
+
+ tgen = get_topogen()
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ pe1 = tgen.gears["PE1"]
+ json_file = "{}/{}/evpn.vni.json".format(CWD, pe1.name)
+ expected = json.loads(open(json_file).read())
+
+ test_func = partial(show_vni_json_elide_ifindex, pe1, 101, expected)
+ _, result = topotest.run_and_expect(test_func, None, count=45, wait=1)
+ assertmsg = '"{}" JSON output mismatches'.format(pe1.name)
+
+ test_func = partial(
+ check_vni_macs_present,
+ tgen,
+ pe1,
+ 101,
+ (("host1", "host1-eth0"), ("host2", "host2-eth0")),
+ )
+ _, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
+ if result:
+ logger.warning("%s", result)
+ assert None, '"{}" missing expected MACs'.format(pe1.name)
+
+ vtep = "10.30.30.30"
+ test_func = partial(check_flood_entry_present, pe1, 101, vtep)
+ _, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
+ assertmsg = '"{}" Flood FDB Entry for VTEP {} not found'.format(pe1.name, vtep)
+ assert result is None, assertmsg
+
+def test_pe2_converge_evpn():
+ "Wait for protocol convergence"
+
+ tgen = get_topogen()
+#Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ pe2 = tgen.gears["PE2"]
+ json_file = "{}/{}/evpn.vni.json".format(CWD, pe2.name)
+ expected = json.loads(open(json_file).read())
+
+ test_func = partial(show_vni_json_elide_ifindex, pe2, 101, expected)
+ _, result = topotest.run_and_expect(test_func, None, count=45, wait=1)
+ assertmsg = '"{}" JSON output mismatches'.format(pe2.name)
+ assert result is None, assertmsg
+
+ test_func = partial(
+ check_vni_macs_present,
+ tgen,
+ pe2,
+ 101,
+ (("host1", "host1-eth0"), ("host2", "host2-eth0")),
+ )
+ _, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
+ if result:
+ logger.warning("%s", result)
+ assert None, '"{}" missing expected MACs'.format(pe2.name)
+
+ vtep = "10.10.10.10"
+ test_func = partial(check_flood_entry_present, pe2, 101, vtep)
+ _, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
+ assertmsg = '"{}" Flood FDB Entry for VTEP {} not found'.format(pe2.name, vtep)
+ assert result is None, assertmsg
+
+def mac_learn_test(host, local):
+ "check the host MAC gets learned by the VNI"
+
+ host_output = host.vtysh_cmd("show interface {}-eth0".format(host.name))
+ int_lines = host_output.splitlines()
+ for line in int_lines:
+ line_items = line.split(": ")
+ if "HWaddr" in line_items[0]:
+ mac = line_items[1]
+ break
+
+ mac_output = local.vtysh_cmd("show evpn mac vni 101 mac {} json".format(mac))
+ mac_output_json = json.loads(mac_output)
+ assertmsg = "Local MAC output does not match interface mac {}".format(mac)
+ assert mac_output_json[mac]["type"] == "local", assertmsg
+
+
+def mac_test_local_remote(local, remote):
+ "test MAC transfer between local and remote"
+
+ local_output = local.vtysh_cmd("show evpn mac vni all json")
+ remote_output = remote.vtysh_cmd("show evpn mac vni all json")
+ local_output_vni = local.vtysh_cmd("show evpn vni detail json")
+ local_output_json = json.loads(local_output)
+ remote_output_json = json.loads(remote_output)
+ local_output_vni_json = json.loads(local_output_vni)
+
+ for vni in local_output_json:
+ if vni not in remote_output_json:
+ continue
+
+ mac_list = local_output_json[vni]["macs"]
+ for mac in mac_list:
+ if mac_list[mac]["type"] == "local" and mac_list[mac]["intf"] != "br101":
+ assertmsg = "JSON output mismatches local: {} remote: {}".format(
+ local_output_vni_json[0]["vtepIp"],
+ remote_output_json[vni]["macs"][mac]["remoteVtep"],
+ )
+ assert (
+ remote_output_json[vni]["macs"][mac]["remoteVtep"]
+ == local_output_vni_json[0]["vtepIp"]
+ ), assertmsg
+
+
+def test_learning_pe1():
+ "test MAC learning on PE1"
+
+ tgen = get_topogen()
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ host1 = tgen.gears["host1"]
+ pe1 = tgen.gears["PE1"]
+ mac_learn_test(host1, pe1)
+
+
+def test_learning_pe2():
+ "test MAC learning on PE2"
+
+ tgen = get_topogen()
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ host2 = tgen.gears["host2"]
+ pe2 = tgen.gears["PE2"]
+ mac_learn_test(host2, pe2)
+
+
+def test_local_remote_mac_pe1():
+ "Test MAC transfer PE1 local and PE2 remote"
+
+ tgen = get_topogen()
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ pe1 = tgen.gears["PE1"]
+ pe2 = tgen.gears["PE2"]
+ mac_test_local_remote(pe1, pe2)
+
+
+def test_local_remote_mac_pe2():
+ "Test MAC transfer PE2 local and PE1 remote"
+
+ tgen = get_topogen()
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ pe1 = tgen.gears["PE1"]
+ pe2 = tgen.gears["PE2"]
+ mac_test_local_remote(pe2, pe1)
+
+
+def ip_learn_test(tgen, host, local, remote, ip_addr):
+ "check the host IP gets learned by the VNI"
+ host_output = host.vtysh_cmd("show interface {}-eth0".format(host.name))
+ int_lines = host_output.splitlines()
+ for line in int_lines:
+ line_items = line.split(": ")
+ if "HWaddr" in line_items[0]:
+ mac = line_items[1]
+ break
+ #print(host_output)
+
+ # check we have a local association between the MAC and IP
+ local_output = local.vtysh_cmd("show evpn mac vni 101 mac {} json".format(mac))
+ #print(local_output)
+ local_output_json = json.loads(local_output)
+ mac_type = local_output_json[mac]["type"]
+ assertmsg = "Failed to learn local IP address on host {}".format(host.name)
+ assert local_output_json[mac]["neighbors"] != "none", assertmsg
+ learned_ip = local_output_json[mac]["neighbors"]["active"][0]
+
+ assertmsg = "local learned mac wrong type: {} ".format(mac_type)
+ assert mac_type == "local", assertmsg
+
+ assertmsg = (
+ "learned address mismatch with configured address host: {} learned: {}".format(
+ ip_addr, learned_ip
+ )
+ )
+ assert ip_addr == learned_ip, assertmsg
+
+ # now lets check the remote
+ count = 0
+ converged = False
+ while count < 30:
+ remote_output = remote.vtysh_cmd(
+ "show evpn mac vni 101 mac {} json".format(mac)
+ )
+ #print(remote_output)
+ remote_output_json = json.loads(remote_output)
+ type = remote_output_json[mac]["type"]
+ if not remote_output_json[mac]["neighbors"] == "none":
+ # due to a kernel quirk, learned IPs can be inactive
+ if (
+ remote_output_json[mac]["neighbors"]["active"]
+ or remote_output_json[mac]["neighbors"]["inactive"]
+ ):
+ converged = True
+ break
+ count += 1
+ sleep(1)
+
+ #print("tries: {}".format(count))
+ assertmsg = "{} remote learned mac no address: {} ".format(host.name, mac)
+ # some debug for this failure
+ if not converged == True:
+ log_output = remote.run("cat zebra.log")
+ #print(log_output)
+
+ assert converged == True, assertmsg
+ if remote_output_json[mac]["neighbors"]["active"]:
+ learned_ip = remote_output_json[mac]["neighbors"]["active"][0]
+ else:
+ learned_ip = remote_output_json[mac]["neighbors"]["inactive"][0]
+ assertmsg = "remote learned mac wrong type: {} ".format(type)
+ assert type == "remote", assertmsg
+
+ assertmsg = "remote learned address mismatch with configured address host: {} learned: {}".format(
+ ip_addr, learned_ip
+ )
+ assert ip_addr == learned_ip, assertmsg
+
+
+def test_ip_pe1_learn():
+ "run the IP learn test for PE1"
+
+ tgen = get_topogen()
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ host1 = tgen.gears["host1"]
+ pe1 = tgen.gears["PE1"]
+ pe2 = tgen.gears["PE2"]
+ pe2.vtysh_cmd("debug zebra vxlan")
+ pe2.vtysh_cmd("debug zebra kernel")
+ # lets populate that arp cache
+ host1.run("ping -c1 10.10.1.1")
+ ip_learn_test(tgen, host1, pe1, pe2, "10.10.1.55")
+ # tgen.mininet_cli()
+
+
+def test_ip_pe2_learn():
+ "run the IP learn test for PE2"
+
+ tgen = get_topogen()
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ host2 = tgen.gears["host2"]
+ pe1 = tgen.gears["PE1"]
+ pe2 = tgen.gears["PE2"]
+ pe1.vtysh_cmd("debug zebra vxlan")
+ pe1.vtysh_cmd("debug zebra kernel")
+ # lets populate that arp cache
+ host2.run("ping -c1 10.10.1.3")
+ ip_learn_test(tgen, host2, pe2, pe1, "10.10.1.56")
+ # tgen.mininet_cli()
+
+def show_dvni_route(pe, vni, prefix, vrf):
+ output = pe.vtysh_cmd("show ip route vrf {} {}".format(vrf, prefix))
+
+ if str(vni) not in output:
+ return output
+
+ output = pe.run("ip route show vrf {} {}".format(vrf, prefix))
+
+ if str(vni) not in output:
+ return output
+
+ return None
+
+def test_dvni():
+ "test Downstream VNI works as expected importing into PE1"
+
+ tgen = get_topogen()
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ pe1 = tgen.gears["PE1"]
+
+ prefix = "4.4.4.1/32"
+ test_func = partial(show_dvni_route, pe1, 300, prefix, "vrf-red")
+ _, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
+ assertmsg = '"{}" DVNI route {} not found'.format(pe1.name, prefix)
+ assert result is None, assertmsg
+ #tgen.mininet_cli()
+
+
+def test_memory_leak():
+ "Run the memory leak test and report results."
+ tgen = get_topogen()
+ if not tgen.is_memleak_enabled():
+ pytest.skip("Memory leak test/report is disabled")
+
+ tgen.report_memory_leaks()
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/bgp_path_attribute_treat_as_withdraw/__init__.py b/tests/topotests/bgp_path_attribute_treat_as_withdraw/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/topotests/bgp_path_attribute_treat_as_withdraw/__init__.py
diff --git a/tests/topotests/bgp_path_attribute_treat_as_withdraw/r1/bgpd.conf b/tests/topotests/bgp_path_attribute_treat_as_withdraw/r1/bgpd.conf
new file mode 100644
index 0000000000..4286b98409
--- /dev/null
+++ b/tests/topotests/bgp_path_attribute_treat_as_withdraw/r1/bgpd.conf
@@ -0,0 +1,14 @@
+!
+router bgp 65001
+ no bgp ebgp-requires-policy
+ no bgp network import-check
+ neighbor 10.0.0.2 remote-as external
+ neighbor 10.0.0.2 timers 3 10
+ address-family ipv4 unicast
+ network 10.10.10.10/32 route-map atomic
+ network 10.10.10.20/32
+ exit-address-family
+!
+route-map atomic permit 10
+ set atomic-aggregate
+!
diff --git a/tests/topotests/bgp_path_attribute_treat_as_withdraw/r1/zebra.conf b/tests/topotests/bgp_path_attribute_treat_as_withdraw/r1/zebra.conf
new file mode 100644
index 0000000000..51a1b2657c
--- /dev/null
+++ b/tests/topotests/bgp_path_attribute_treat_as_withdraw/r1/zebra.conf
@@ -0,0 +1,4 @@
+!
+interface r1-eth0
+ ip address 10.0.0.1/24
+!
diff --git a/tests/topotests/bgp_path_attribute_treat_as_withdraw/r2/bgpd.conf b/tests/topotests/bgp_path_attribute_treat_as_withdraw/r2/bgpd.conf
new file mode 100644
index 0000000000..2e63fd8c44
--- /dev/null
+++ b/tests/topotests/bgp_path_attribute_treat_as_withdraw/r2/bgpd.conf
@@ -0,0 +1,6 @@
+!
+router bgp 65002
+ no bgp ebgp-requires-policy
+ neighbor 10.0.0.1 remote-as external
+ neighbor 10.0.0.1 timers 3 10
+!
diff --git a/tests/topotests/bgp_path_attribute_treat_as_withdraw/r2/zebra.conf b/tests/topotests/bgp_path_attribute_treat_as_withdraw/r2/zebra.conf
new file mode 100644
index 0000000000..12d3731b3a
--- /dev/null
+++ b/tests/topotests/bgp_path_attribute_treat_as_withdraw/r2/zebra.conf
@@ -0,0 +1,4 @@
+!
+interface r2-eth0
+ ip address 10.0.0.2/24
+!
diff --git a/tests/topotests/bgp_path_attribute_treat_as_withdraw/test_bgp_path_attribute_treat_as_withdraw.py b/tests/topotests/bgp_path_attribute_treat_as_withdraw/test_bgp_path_attribute_treat_as_withdraw.py
new file mode 100644
index 0000000000..4aa297511a
--- /dev/null
+++ b/tests/topotests/bgp_path_attribute_treat_as_withdraw/test_bgp_path_attribute_treat_as_withdraw.py
@@ -0,0 +1,143 @@
+#!/usr/bin/env python
+
+#
+# Copyright (c) 2022 by
+# Donatas Abraitis <donatas@opensourcerouting.org>
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+"""
+Test if `neighbor path-attribute treat-as-withdraw` command works correctly,
+can withdraw unwanted prefixes from BGP table.
+"""
+
+import os
+import sys
+import json
+import pytest
+import functools
+
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+
+# pylint: disable=C0413
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.common_config import step
+
+pytestmark = [pytest.mark.bgpd]
+
+
+def build_topo(tgen):
+ r1 = tgen.add_router("r1")
+ r2 = tgen.add_router("r2")
+
+ switch = tgen.add_switch("s1")
+ switch.add_link(r1)
+ switch.add_link(r2)
+
+
+def setup_module(mod):
+ tgen = Topogen(build_topo, mod.__name__)
+ tgen.start_topology()
+
+ r1 = tgen.gears["r1"]
+ r1.load_config(TopoRouter.RD_ZEBRA, os.path.join(CWD, "r1/zebra.conf"))
+ r1.load_config(TopoRouter.RD_BGP, os.path.join(CWD, "r1/bgpd.conf"))
+ r1.start()
+
+ r2 = tgen.gears["r2"]
+ r2.load_config(TopoRouter.RD_ZEBRA, os.path.join(CWD, "r2/zebra.conf"))
+ r2.load_config(TopoRouter.RD_BGP, os.path.join(CWD, "r2/bgpd.conf"))
+ r2.start()
+
+
+def teardown_module(mod):
+ tgen = get_topogen()
+ tgen.stop_topology()
+
+
+def test_bgp_path_attribute_treat_as_withdraw():
+ tgen = get_topogen()
+
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ r2 = tgen.gears["r2"]
+
+ def _bgp_converge():
+ output = json.loads(r2.vtysh_cmd("show bgp ipv4 unicast json detail"))
+ expected = {
+ "routes": {
+ "10.10.10.10/32": [
+ {
+ "valid": True,
+ "atomicAggregate": True,
+ }
+ ],
+ "10.10.10.20/32": [
+ {
+ "valid": True,
+ }
+ ],
+ }
+ }
+ return topotest.json_cmp(output, expected)
+
+ test_func = functools.partial(_bgp_converge)
+ _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+ assert result is None, "Failed bgp convergence"
+
+ step("Withdraw prefixes with atomic-aggregate from r1")
+ r2.vtysh_cmd(
+ """
+ configure terminal
+ router bgp
+ neighbor 10.0.0.1 path-attribute treat-as-withdraw 6
+ """
+ )
+
+ def _bgp_check_if_route_withdrawn():
+ output = json.loads(r2.vtysh_cmd("show bgp ipv4 unicast json detail"))
+ expected = {
+ "routes": {
+ "10.10.10.10/32": None,
+ "10.10.10.20/32": [
+ {
+ "valid": True,
+ }
+ ],
+ }
+ }
+ return topotest.json_cmp(output, expected)
+
+ test_func = functools.partial(_bgp_check_if_route_withdrawn)
+ _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+ assert result is None, "Failed to withdraw prefixes with atomic-aggregate attribute"
+
+
+def test_memory_leak():
+ "Run the memory leak test and report results."
+ tgen = get_topogen()
+ if not tgen.is_memleak_enabled():
+ pytest.skip("Memory leak test/report is disabled")
+
+ tgen.report_memory_leaks()
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/lib/topotest.py b/tests/topotests/lib/topotest.py
index 7f68b4ccf3..699b53303a 100644
--- a/tests/topotests/lib/topotest.py
+++ b/tests/topotests/lib/topotest.py
@@ -595,6 +595,29 @@ def iproute2_is_vrf_capable():
pass
return False
+def iproute2_is_fdb_get_capable():
+ """
+ Checks if the iproute2 version installed on the system is capable of
+ handling `bridge fdb get` commands to query neigh table resolution.
+
+ Returns True if capability can be detected, returns False otherwise.
+ """
+
+ if is_linux():
+ try:
+ subp = subprocess.Popen(
+ ["bridge", "fdb", "get", "help"],
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ stdin=subprocess.PIPE,
+ )
+ iproute2_out = subp.communicate()[1].splitlines()[0].split()[0]
+
+ if "Usage" in str(iproute2_out):
+ return True
+ except Exception:
+ pass
+ return False
def module_present_linux(module, load):
"""
diff --git a/vrrpd/vrrp.c b/vrrpd/vrrp.c
index e1bb40c28d..c3ab1abbd6 100644
--- a/vrrpd/vrrp.c
+++ b/vrrpd/vrrp.c
@@ -671,6 +671,9 @@ void vrrp_vrouter_destroy(struct vrrp_vrouter *vr)
struct vrrp_vrouter *vrrp_lookup(const struct interface *ifp, uint8_t vrid)
{
+ if (!ifp)
+ return NULL;
+
struct vrrp_vrouter vr;
vr.vrid = vrid;
diff --git a/zebra/dplane_fpm_nl.c b/zebra/dplane_fpm_nl.c
index 0a9fecc9df..6a0f02bab4 100644
--- a/zebra/dplane_fpm_nl.c
+++ b/zebra/dplane_fpm_nl.c
@@ -45,9 +45,10 @@
#include "zebra/zebra_dplane.h"
#include "zebra/zebra_mpls.h"
#include "zebra/zebra_router.h"
+#include "zebra/interface.h"
+#include "zebra/zebra_vxlan_private.h"
#include "zebra/zebra_evpn.h"
#include "zebra/zebra_evpn_mac.h"
-#include "zebra/zebra_vxlan_private.h"
#include "zebra/kernel_netlink.h"
#include "zebra/rt_netlink.h"
#include "zebra/debug.h"
@@ -1189,7 +1190,7 @@ static void fpm_enqueue_rmac_table(struct hash_bucket *bucket, void *arg)
struct fpm_rmac_arg *fra = arg;
struct zebra_mac *zrmac = bucket->data;
struct zebra_if *zif = fra->zl3vni->vxlan_if->info;
- const struct zebra_l2info_vxlan *vxl = &zif->l2info.vxl;
+ struct zebra_vxlan_vni *vni;
struct zebra_if *br_zif;
vlanid_t vid;
bool sticky;
@@ -1201,14 +1202,15 @@ static void fpm_enqueue_rmac_table(struct hash_bucket *bucket, void *arg)
sticky = !!CHECK_FLAG(zrmac->flags,
(ZEBRA_MAC_STICKY | ZEBRA_MAC_REMOTE_DEF_GW));
br_zif = (struct zebra_if *)(zif->brslave_info.br_if->info);
- vid = IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(br_zif) ? vxl->access_vlan : 0;
+ vni = zebra_vxlan_if_vni_find(zif, fra->zl3vni->vni);
+ vid = IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(br_zif) ? vni->access_vlan : 0;
dplane_ctx_reset(fra->ctx);
dplane_ctx_set_op(fra->ctx, DPLANE_OP_MAC_INSTALL);
dplane_mac_init(fra->ctx, fra->zl3vni->vxlan_if,
- zif->brslave_info.br_if, vid,
- &zrmac->macaddr, zrmac->fwd_info.r_vtep_ip, sticky,
- 0 /*nhg*/, 0 /*update_flags*/);
+ zif->brslave_info.br_if, vid, &zrmac->macaddr, vni->vni,
+ zrmac->fwd_info.r_vtep_ip, sticky, 0 /*nhg*/,
+ 0 /*update_flags*/);
if (fpm_nl_enqueue(fra->fnc, fra->ctx) == -1) {
thread_add_timer(zrouter.master, fpm_rmac_send,
fra->fnc, 1, &fra->fnc->t_rmacwalk);
diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c
index 835659332b..6e5fef3b3f 100644
--- a/zebra/if_netlink.c
+++ b/zebra/if_netlink.c
@@ -544,7 +544,7 @@ static int netlink_extract_bridge_info(struct rtattr *link_data,
memset(bridge_info, 0, sizeof(*bridge_info));
netlink_parse_rtattr_nested(attr, IFLA_BR_MAX, link_data);
if (attr[IFLA_BR_VLAN_FILTERING])
- bridge_info->vlan_aware =
+ bridge_info->bridge.vlan_aware =
*(uint8_t *)RTA_DATA(attr[IFLA_BR_VLAN_FILTERING]);
return 0;
}
@@ -612,6 +612,7 @@ static int netlink_extract_gre_info(struct rtattr *link_data,
static int netlink_extract_vxlan_info(struct rtattr *link_data,
struct zebra_l2info_vxlan *vxl_info)
{
+ uint8_t svd = 0;
struct rtattr *attr[IFLA_VXLAN_MAX + 1];
vni_t vni_in_msg;
struct in_addr vtep_ip_in_msg;
@@ -619,15 +620,33 @@ static int netlink_extract_vxlan_info(struct rtattr *link_data,
memset(vxl_info, 0, sizeof(*vxl_info));
netlink_parse_rtattr_nested(attr, IFLA_VXLAN_MAX, link_data);
- if (!attr[IFLA_VXLAN_ID]) {
+ if (attr[IFLA_VXLAN_COLLECT_METADATA]) {
+ svd = *(uint8_t *)RTA_DATA(attr[IFLA_VXLAN_COLLECT_METADATA]);
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug(
- "IFLA_VXLAN_ID missing from VXLAN IF message");
- return -1;
+ "IFLA_VXLAN_COLLECT_METADATA=%u in VXLAN IF message",
+ svd);
+ }
+
+ if (!svd) {
+ /*
+ * In case of svd we will not get vni info directly from the
+ * device
+ */
+ if (!attr[IFLA_VXLAN_ID]) {
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ zlog_debug(
+ "IFLA_VXLAN_ID missing from VXLAN IF message");
+ return -1;
+ }
+
+ vxl_info->vni_info.iftype = ZEBRA_VXLAN_IF_VNI;
+ vni_in_msg = *(vni_t *)RTA_DATA(attr[IFLA_VXLAN_ID]);
+ vxl_info->vni_info.vni.vni = vni_in_msg;
+ } else {
+ vxl_info->vni_info.iftype = ZEBRA_VXLAN_IF_SVD;
}
- vni_in_msg = *(vni_t *)RTA_DATA(attr[IFLA_VXLAN_ID]);
- vxl_info->vni = vni_in_msg;
if (!attr[IFLA_VXLAN_LOCAL]) {
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug(
@@ -639,8 +658,10 @@ static int netlink_extract_vxlan_info(struct rtattr *link_data,
}
if (attr[IFLA_VXLAN_GROUP]) {
- vxl_info->mcast_grp =
- *(struct in_addr *)RTA_DATA(attr[IFLA_VXLAN_GROUP]);
+ if (!svd)
+ vxl_info->vni_info.vni.mcast_grp =
+ *(struct in_addr *)RTA_DATA(
+ attr[IFLA_VXLAN_GROUP]);
}
if (!attr[IFLA_VXLAN_LINK]) {
@@ -701,16 +722,113 @@ static void netlink_interface_update_l2info(struct interface *ifp,
}
}
+static int netlink_bridge_vxlan_vlan_vni_map_update(struct interface *ifp,
+ struct rtattr *af_spec)
+{
+ int rem;
+ vni_t vni_id;
+ vlanid_t vid;
+ uint16_t flags;
+ struct rtattr *i;
+ struct zebra_vxlan_vni vni;
+ struct zebra_vxlan_vni *vnip;
+ struct hash *vni_table = NULL;
+ struct zebra_vxlan_vni vni_end;
+ struct zebra_vxlan_vni vni_start;
+ struct rtattr *aftb[IFLA_BRIDGE_VLAN_TUNNEL_MAX + 1];
+
+ memset(&vni_start, 0, sizeof(vni_start));
+ memset(&vni_end, 0, sizeof(vni_end));
+
+ for (i = RTA_DATA(af_spec), rem = RTA_PAYLOAD(af_spec); RTA_OK(i, rem);
+ i = RTA_NEXT(i, rem)) {
+
+ if (i->rta_type != IFLA_BRIDGE_VLAN_TUNNEL_INFO)
+ continue;
+
+ memset(aftb, 0, sizeof(aftb));
+ netlink_parse_rtattr_nested(aftb, IFLA_BRIDGE_VLAN_TUNNEL_MAX,
+ i);
+ if (!aftb[IFLA_BRIDGE_VLAN_TUNNEL_ID] ||
+ !aftb[IFLA_BRIDGE_VLAN_TUNNEL_VID])
+ /* vlan-vni info missing */
+ return 0;
+
+ flags = 0;
+ memset(&vni, 0, sizeof(vni));
+
+ vni.vni = *(vni_t *)RTA_DATA(aftb[IFLA_BRIDGE_VLAN_TUNNEL_ID]);
+ vni.access_vlan = *(vlanid_t *)RTA_DATA(
+ aftb[IFLA_BRIDGE_VLAN_TUNNEL_VID]);
+
+ if (aftb[IFLA_BRIDGE_VLAN_TUNNEL_FLAGS])
+ flags = *(uint16_t *)RTA_DATA(
+ aftb[IFLA_BRIDGE_VLAN_TUNNEL_FLAGS]);
+
+ if (flags & BRIDGE_VLAN_INFO_RANGE_BEGIN) {
+ vni_start = vni;
+ continue;
+ }
+
+ if (flags & BRIDGE_VLAN_INFO_RANGE_END)
+ vni_end = vni;
+
+ if (!(flags & BRIDGE_VLAN_INFO_RANGE_END)) {
+ vni_start = vni;
+ vni_end = vni;
+ }
+
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ zlog_debug(
+ "Vlan-Vni(%d:%d-%d:%d) update for VxLAN IF %s(%u)",
+ vni_start.access_vlan, vni_end.access_vlan,
+ vni_start.vni, vni_end.vni, ifp->name,
+ ifp->ifindex);
+
+ if (!vni_table) {
+ vni_table = zebra_vxlan_vni_table_create();
+ if (!vni_table)
+ return 0;
+ }
+
+ for (vid = vni_start.access_vlan, vni_id = vni_start.vni;
+ vid <= vni_end.access_vlan; vid++, vni_id++) {
+
+ memset(&vni, 0, sizeof(vni));
+ vni.vni = vni_id;
+ vni.access_vlan = vid;
+ vnip = hash_get(vni_table, &vni, zebra_vxlan_vni_alloc);
+ if (!vnip)
+ return 0;
+ }
+
+ memset(&vni_start, 0, sizeof(vni_start));
+ memset(&vni_end, 0, sizeof(vni_end));
+ }
+
+ if (vni_table)
+ zebra_vxlan_if_vni_table_add_update(ifp, vni_table);
+
+ return 0;
+}
+
static int netlink_bridge_vxlan_update(struct interface *ifp,
struct rtattr *af_spec)
{
struct rtattr *aftb[IFLA_BRIDGE_MAX + 1];
struct bridge_vlan_info *vinfo;
+ struct zebra_if *zif;
vlanid_t access_vlan;
if (!af_spec)
return 0;
+ zif = (struct zebra_if *)ifp->info;
+
+ /* Single vxlan devices has vni-vlan range to update */
+ if (IS_ZEBRA_VXLAN_IF_SVD(zif))
+ return netlink_bridge_vxlan_vlan_vni_map_update(ifp, af_spec);
+
/* There is a 1-to-1 mapping of VLAN to VxLAN - hence
* only 1 access VLAN is accepted.
*/
@@ -2404,4 +2522,235 @@ int netlink_tunneldump_read(struct zebra_ns *zns)
return 0;
}
+
+static const char *port_state2str(uint8_t state)
+{
+ switch (state) {
+ case BR_STATE_DISABLED:
+ return "DISABLED";
+ case BR_STATE_LISTENING:
+ return "LISTENING";
+ case BR_STATE_LEARNING:
+ return "LEARNING";
+ case BR_STATE_FORWARDING:
+ return "FORWARDING";
+ case BR_STATE_BLOCKING:
+ return "BLOCKING";
+ }
+
+ return "UNKNOWN";
+}
+
+static void vxlan_vni_state_change(struct zebra_if *zif, uint16_t id,
+ uint8_t state)
+{
+ struct zebra_vxlan_vni *vnip;
+
+ vnip = zebra_vxlan_if_vlanid_vni_find(zif, id);
+
+ if (!vnip) {
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug(
+ "Cannot find VNI for VID (%u) IF %s for vlan state update",
+ id, zif->ifp->name);
+
+ return;
+ }
+
+ switch (state) {
+ case BR_STATE_FORWARDING:
+ zebra_vxlan_if_vni_up(zif->ifp, vnip);
+ break;
+ case BR_STATE_BLOCKING:
+ zebra_vxlan_if_vni_down(zif->ifp, vnip);
+ break;
+ case BR_STATE_DISABLED:
+ case BR_STATE_LISTENING:
+ case BR_STATE_LEARNING:
+ default:
+ /* Not used for anything at the moment */
+ break;
+ }
+}
+
+static void vlan_id_range_state_change(struct interface *ifp, uint16_t id_start,
+ uint16_t id_end, uint8_t state)
+{
+ struct zebra_if *zif;
+
+ zif = (struct zebra_if *)ifp->info;
+
+ if (!zif)
+ return;
+
+ for (uint16_t i = id_start; i <= id_end; i++)
+ vxlan_vni_state_change(zif, i, state);
+}
+
+/**
+ * netlink_vlan_change() - Read in change about vlans from the kernel
+ *
+ * @h: Netlink message header
+ * @ns_id: Namspace id
+ * @startup: Are we reading under startup conditions?
+ *
+ * Return: Result status
+ */
+int netlink_vlan_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
+{
+ int len, rem;
+ struct interface *ifp;
+ struct br_vlan_msg *bvm;
+ struct bridge_vlan_info *vinfo;
+ struct rtattr *vtb[BRIDGE_VLANDB_ENTRY_MAX + 1] = {};
+ struct rtattr *attr;
+ uint8_t state;
+ uint32_t vrange;
+ int type;
+
+ /* We only care about state changes for now */
+ if (!(h->nlmsg_type == RTM_NEWVLAN))
+ return 0;
+
+ len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct br_vlan_msg));
+ if (len < 0) {
+ zlog_warn(
+ "%s: Message received from netlink is of a broken size %d %zu",
+ __func__, h->nlmsg_len,
+ (size_t)NLMSG_LENGTH(sizeof(struct br_vlan_msg)));
+ return -1;
+ }
+
+ bvm = NLMSG_DATA(h);
+
+ if (bvm->family != AF_BRIDGE)
+ return 0;
+
+ ifp = if_lookup_by_index_per_ns(zebra_ns_lookup(ns_id), bvm->ifindex);
+ if (!ifp) {
+ zlog_debug("Cannot find bridge-vlan IF (%u) for vlan update",
+ bvm->ifindex);
+ return 0;
+ }
+
+ if (!IS_ZEBRA_IF_VXLAN(ifp)) {
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ zlog_debug("Ignoring non-vxlan IF (%s) for vlan update",
+ ifp->name);
+
+ return 0;
+ }
+
+ if (IS_ZEBRA_DEBUG_KERNEL || IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug("%s %s IF %s NS %u",
+ nl_msg_type_to_str(h->nlmsg_type),
+ nl_family_to_str(bvm->family), ifp->name, ns_id);
+
+ /* Loop over "ALL" BRIDGE_VLANDB_ENTRY */
+ rem = len;
+ for (attr = BRVLAN_RTA(bvm); RTA_OK(attr, rem);
+ attr = RTA_NEXT(attr, rem)) {
+ vinfo = NULL;
+ vrange = 0;
+
+ type = attr->rta_type & NLA_TYPE_MASK;
+
+ if (type != BRIDGE_VLANDB_ENTRY)
+ continue;
+
+ /* Parse nested entry data */
+ netlink_parse_rtattr_nested(vtb, BRIDGE_VLANDB_ENTRY_MAX, attr);
+
+ /* It must have info for the ID */
+ if (!vtb[BRIDGE_VLANDB_ENTRY_INFO])
+ continue;
+
+ vinfo = (struct bridge_vlan_info *)RTA_DATA(
+ vtb[BRIDGE_VLANDB_ENTRY_INFO]);
+
+ /*
+ * We only care about state info, if there is none, just ignore
+ * it.
+ */
+ if (!vtb[BRIDGE_VLANDB_ENTRY_STATE])
+ continue;
+
+ state = *(uint8_t *)RTA_DATA(vtb[BRIDGE_VLANDB_ENTRY_STATE]);
+
+ if (vtb[BRIDGE_VLANDB_ENTRY_RANGE])
+ vrange = *(uint32_t *)RTA_DATA(
+ vtb[BRIDGE_VLANDB_ENTRY_RANGE]);
+
+ if (IS_ZEBRA_DEBUG_KERNEL || IS_ZEBRA_DEBUG_VXLAN) {
+ if (vrange)
+ zlog_debug("VLANDB_ENTRY: VID (%u-%u) state=%s",
+ vinfo->vid, vrange,
+ port_state2str(state));
+ else
+ zlog_debug("VLANDB_ENTRY: VID (%u) state=%s",
+ vinfo->vid, port_state2str(state));
+ }
+
+ vlan_id_range_state_change(
+ ifp, vinfo->vid, (vrange ? vrange : vinfo->vid), state);
+ }
+
+ return 0;
+}
+
+/**
+ * netlink_request_vlan() - Request vlan information from the kernel
+ * @zns: Zebra namespace
+ * @family: AF_* netlink family
+ * @type: RTM_* type
+ *
+ * Return: Result status
+ */
+static int netlink_request_vlan(struct zebra_ns *zns, int family, int type)
+{
+ struct {
+ struct nlmsghdr n;
+ struct br_vlan_msg bvm;
+ char buf[256];
+ } req;
+
+ /* Form the request, specifying filter (rtattr) if needed. */
+ memset(&req, 0, sizeof(req));
+ req.n.nlmsg_type = type;
+ req.n.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
+ req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct br_vlan_msg));
+ req.bvm.family = family;
+
+ nl_attr_put32(&req.n, sizeof(req), BRIDGE_VLANDB_DUMP_FLAGS,
+ BRIDGE_VLANDB_DUMPF_STATS);
+
+ return netlink_request(&zns->netlink_cmd, &req);
+}
+
+/**
+ * netlink_vlan_read() - Vlan read function using netlink interface
+ *
+ * @zns: Zebra name space
+ *
+ * Return: Result status
+ * Only called at bootstrap time.
+ */
+int netlink_vlan_read(struct zebra_ns *zns)
+{
+ int ret;
+ struct zebra_dplane_info dp_info;
+
+ zebra_dplane_info_from_zns(&dp_info, zns, true /*is_cmd*/);
+
+ /* Get bridg vlan info */
+ ret = netlink_request_vlan(zns, PF_BRIDGE, RTM_GETVLAN);
+ if (ret < 0)
+ return ret;
+
+ ret = netlink_parse_info(netlink_vlan_change, &zns->netlink_cmd,
+ &dp_info, 0, 1);
+
+ return ret;
+}
+
#endif /* GNU_LINUX */
diff --git a/zebra/if_netlink.h b/zebra/if_netlink.h
index 21ae1713be..f215968657 100644
--- a/zebra/if_netlink.h
+++ b/zebra/if_netlink.h
@@ -40,6 +40,9 @@ int netlink_interface_addr_dplane(struct nlmsghdr *h, ns_id_t ns_id,
extern int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup);
extern int interface_lookup_netlink(struct zebra_ns *zns);
+extern int netlink_vlan_change(struct nlmsghdr *h, ns_id_t ns_id, int startup);
+extern int netlink_vlan_read(struct zebra_ns *zns);
+
extern ssize_t netlink_intf_msg_encode(uint16_t cmd,
const struct zebra_dplane_ctx *ctx,
void *buf, size_t buflen);
diff --git a/zebra/interface.c b/zebra/interface.c
index a24f55dbba..5c60d355c2 100644
--- a/zebra/interface.c
+++ b/zebra/interface.c
@@ -229,6 +229,7 @@ static int if_zebra_delete_hook(struct interface *ifp)
rtadv_if_fini(zebra_if);
+ zebra_l2_bridge_if_cleanup(ifp);
zebra_evpn_if_cleanup(zebra_if);
zebra_evpn_mac_ifp_del(ifp);
@@ -807,12 +808,12 @@ void if_delete_update(struct interface **pifp)
/* Reset some zebra interface params to default values. */
zif = ifp->info;
if (zif) {
+ zebra_evpn_if_cleanup(zif);
zif->zif_type = ZEBRA_IF_OTHER;
zif->zif_slave_type = ZEBRA_IF_SLAVE_NONE;
memset(&zif->l2info, 0, sizeof(union zebra_l2if_info));
memset(&zif->brslave_info, 0,
sizeof(struct zebra_l2info_brslave));
- zebra_evpn_if_cleanup(zif);
zebra_evpn_mac_ifp_del(ifp);
}
@@ -1890,6 +1891,63 @@ static inline bool if_is_protodown_applicable(struct interface *ifp)
return true;
}
+static void zebra_vxlan_if_vni_dump_vty(struct vty *vty,
+ struct zebra_vxlan_vni *vni)
+{
+ char str[INET6_ADDRSTRLEN];
+
+ vty_out(vty, " VxLAN Id %u", vni->vni);
+ if (vni->access_vlan)
+ vty_out(vty, " Access VLAN Id %u\n", vni->access_vlan);
+
+ if (vni->mcast_grp.s_addr != INADDR_ANY)
+ vty_out(vty, " Mcast Group %s",
+ inet_ntop(AF_INET, &vni->mcast_grp, str, sizeof(str)));
+}
+
+static void zebra_vxlan_if_vni_hash_dump_vty(struct hash_bucket *bucket,
+ void *ctxt)
+{
+ struct vty *vty;
+ struct zebra_vxlan_vni *vni;
+
+ vni = (struct zebra_vxlan_vni *)bucket->data;
+ vty = (struct vty *)ctxt;
+
+ zebra_vxlan_if_vni_dump_vty(vty, vni);
+}
+
+static void zebra_vxlan_if_dump_vty(struct vty *vty, struct zebra_if *zebra_if)
+{
+ struct zebra_l2info_vxlan *vxlan_info;
+ struct zebra_vxlan_vni_info *vni_info;
+
+ vxlan_info = &zebra_if->l2info.vxl;
+ vni_info = &vxlan_info->vni_info;
+
+ if (vxlan_info->vtep_ip.s_addr != INADDR_ANY)
+ vty_out(vty, " VTEP IP: %pI4", &vxlan_info->vtep_ip);
+
+ if (vxlan_info->ifindex_link && (vxlan_info->link_nsid != NS_UNKNOWN)) {
+ struct interface *ifp;
+
+ ifp = if_lookup_by_index_per_ns(
+ zebra_ns_lookup(vxlan_info->link_nsid),
+ vxlan_info->ifindex_link);
+ vty_out(vty, " Link Interface %s",
+ ifp == NULL ? "Unknown" : ifp->name);
+ }
+
+ if (IS_ZEBRA_VXLAN_IF_VNI(zebra_if)) {
+ zebra_vxlan_if_vni_dump_vty(vty, &vni_info->vni);
+ } else {
+ hash_iterate(vni_info->vni_table,
+ zebra_vxlan_if_vni_hash_dump_vty, vty);
+ }
+
+ vty_out(vty, "\n");
+}
+
/* Interface's information print out to vty interface. */
static void if_dump_vty(struct vty *vty, struct interface *ifp)
{
@@ -1998,42 +2056,15 @@ static void if_dump_vty(struct vty *vty, struct interface *ifp)
zebra_zifslavetype_2str(zebra_if->zif_slave_type));
if (IS_ZEBRA_IF_BRIDGE(ifp)) {
- struct zebra_l2info_bridge *bridge_info;
-
- bridge_info = &zebra_if->l2info.br;
vty_out(vty, " Bridge VLAN-aware: %s\n",
- bridge_info->vlan_aware ? "yes" : "no");
+ IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(zebra_if) ? "yes" : "no");
} else if (IS_ZEBRA_IF_VLAN(ifp)) {
struct zebra_l2info_vlan *vlan_info;
vlan_info = &zebra_if->l2info.vl;
vty_out(vty, " VLAN Id %u\n", vlan_info->vid);
} else if (IS_ZEBRA_IF_VXLAN(ifp)) {
- struct zebra_l2info_vxlan *vxlan_info;
-
- vxlan_info = &zebra_if->l2info.vxl;
- vty_out(vty, " VxLAN Id %u", vxlan_info->vni);
- if (vxlan_info->vtep_ip.s_addr != INADDR_ANY)
- vty_out(vty, " VTEP IP: %pI4",
- &vxlan_info->vtep_ip);
- if (vxlan_info->access_vlan)
- vty_out(vty, " Access VLAN Id %u\n",
- vxlan_info->access_vlan);
- if (vxlan_info->mcast_grp.s_addr != INADDR_ANY)
- vty_out(vty, " Mcast Group %pI4",
- &vxlan_info->mcast_grp);
- if (vxlan_info->ifindex_link &&
- (vxlan_info->link_nsid != NS_UNKNOWN)) {
- struct interface *ifp;
-
- ifp = if_lookup_by_index_per_ns(
- zebra_ns_lookup(vxlan_info->link_nsid),
- vxlan_info->ifindex_link);
- vty_out(vty, " Link Interface %s",
- ifp == NULL ? "Unknown" :
- ifp->name);
- }
- vty_out(vty, "\n");
+ zebra_vxlan_if_dump_vty(vty, zebra_if);
} else if (IS_ZEBRA_IF_GRE(ifp)) {
struct zebra_l2info_gre *gre_info;
@@ -2226,6 +2257,59 @@ static void if_dump_vty(struct vty *vty, struct interface *ifp)
#endif /* HAVE_NET_RT_IFLIST */
}
+static void zebra_vxlan_if_vni_dump_vty_json(json_object *json_if,
+ struct zebra_vxlan_vni *vni)
+{
+ json_object_int_add(json_if, "vxlanId", vni->vni);
+ if (vni->access_vlan)
+ json_object_int_add(json_if, "accessVlanId", vni->access_vlan);
+ if (vni->mcast_grp.s_addr != INADDR_ANY)
+ json_object_string_addf(json_if, "mcastGroup", "%pI4",
+ &vni->mcast_grp);
+}
+
+static void zebra_vxlan_if_vni_hash_dump_vty_json(struct hash_bucket *bucket,
+ void *ctxt)
+{
+ json_object *json_if;
+ struct zebra_vxlan_vni *vni;
+
+ vni = (struct zebra_vxlan_vni *)bucket->data;
+ json_if = (json_object *)ctxt;
+
+ zebra_vxlan_if_vni_dump_vty_json(json_if, vni);
+}
+
+static void zebra_vxlan_if_dump_vty_json(json_object *json_if,
+ struct zebra_if *zebra_if)
+{
+ struct zebra_l2info_vxlan *vxlan_info;
+ struct zebra_vxlan_vni_info *vni_info;
+
+ vxlan_info = &zebra_if->l2info.vxl;
+ vni_info = &vxlan_info->vni_info;
+
+ if (vxlan_info->vtep_ip.s_addr != INADDR_ANY)
+ json_object_string_addf(json_if, "vtepIp", "%pI4",
+ &vxlan_info->vtep_ip);
+
+ if (vxlan_info->ifindex_link && (vxlan_info->link_nsid != NS_UNKNOWN)) {
+ struct interface *ifp;
+
+ ifp = if_lookup_by_index_per_ns(
+ zebra_ns_lookup(vxlan_info->link_nsid),
+ vxlan_info->ifindex_link);
+ json_object_string_add(json_if, "linkInterface",
+ ifp == NULL ? "Unknown" : ifp->name);
+ }
+ if (IS_ZEBRA_VXLAN_IF_VNI(zebra_if)) {
+ zebra_vxlan_if_vni_dump_vty_json(json_if, &vni_info->vni);
+ } else {
+ hash_iterate(vni_info->vni_table,
+ zebra_vxlan_if_vni_hash_dump_vty_json, json_if);
+ }
+}
+
static void if_dump_vty_json(struct vty *vty, struct interface *ifp,
json_object *json)
{
@@ -2353,37 +2437,15 @@ static void if_dump_vty_json(struct vty *vty, struct interface *ifp,
bridge_info = &zebra_if->l2info.br;
json_object_boolean_add(json_if, "bridgeVlanAware",
- bridge_info->vlan_aware);
+ bridge_info->bridge.vlan_aware);
} else if (IS_ZEBRA_IF_VLAN(ifp)) {
struct zebra_l2info_vlan *vlan_info;
vlan_info = &zebra_if->l2info.vl;
json_object_int_add(json_if, "vlanId", vlan_info->vid);
} else if (IS_ZEBRA_IF_VXLAN(ifp)) {
- struct zebra_l2info_vxlan *vxlan_info;
-
- vxlan_info = &zebra_if->l2info.vxl;
- json_object_int_add(json_if, "vxlanId", vxlan_info->vni);
- if (vxlan_info->vtep_ip.s_addr != INADDR_ANY)
- json_object_string_addf(json_if, "vtepIp", "%pI4",
- &vxlan_info->vtep_ip);
- if (vxlan_info->access_vlan)
- json_object_int_add(json_if, "accessVlanId",
- vxlan_info->access_vlan);
- if (vxlan_info->mcast_grp.s_addr != INADDR_ANY)
- json_object_string_addf(json_if, "mcastGroup", "%pI4",
- &vxlan_info->mcast_grp);
- if (vxlan_info->ifindex_link
- && (vxlan_info->link_nsid != NS_UNKNOWN)) {
- struct interface *ifp;
+ zebra_vxlan_if_dump_vty_json(json_if, zebra_if);
- ifp = if_lookup_by_index_per_ns(
- zebra_ns_lookup(vxlan_info->link_nsid),
- vxlan_info->ifindex_link);
- json_object_string_add(json_if, "linkInterface",
- ifp == NULL ? "Unknown"
- : ifp->name);
- }
} else if (IS_ZEBRA_IF_GRE(ifp)) {
struct zebra_l2info_gre *gre_info;
diff --git a/zebra/interface.h b/zebra/interface.h
index 8e39ca8c96..7e52990002 100644
--- a/zebra/interface.h
+++ b/zebra/interface.h
@@ -28,6 +28,7 @@
#include "bitfield.h"
#include "zebra/zebra_l2.h"
+#include "zebra/zebra_l2_bridge_if.h"
#include "zebra/zebra_nhg_private.h"
#include "zebra/zebra_router.h"
#include "zebra/rtadv.h"
diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c
index 42afe61469..fac6acae0c 100644
--- a/zebra/kernel_netlink.c
+++ b/zebra/kernel_netlink.c
@@ -124,6 +124,9 @@ static const struct message nlmsg_str[] = {{RTM_NEWROUTE, "RTM_NEWROUTE"},
{RTM_NEWTFILTER, "RTM_NEWTFILTER"},
{RTM_DELTFILTER, "RTM_DELTFILTER"},
{RTM_GETTFILTER, "RTM_GETTFILTER"},
+ {RTM_NEWVLAN, "RTM_NEWVLAN"},
+ {RTM_DELVLAN, "RTM_DELVLAN"},
+ {RTM_GETVLAN, "RTM_GETVLAN"},
{0}};
static const struct message rtproto_str[] = {
@@ -432,6 +435,10 @@ static int netlink_information_fetch(struct nlmsghdr *h, ns_id_t ns_id,
case RTM_NEWTFILTER:
case RTM_DELTFILTER:
return netlink_tfilter_change(h, ns_id, startup);
+ case RTM_NEWVLAN:
+ return netlink_vlan_change(h, ns_id, startup);
+ case RTM_DELVLAN:
+ return netlink_vlan_change(h, ns_id, startup);
/* Messages handled in the dplane thread */
case RTM_NEWADDR:
@@ -705,6 +712,12 @@ bool nl_attr_put32(struct nlmsghdr *n, unsigned int maxlen, int type,
return nl_attr_put(n, maxlen, type, &data, sizeof(uint32_t));
}
+bool nl_attr_put64(struct nlmsghdr *n, unsigned int maxlen, int type,
+ uint64_t data)
+{
+ return nl_attr_put(n, maxlen, type, &data, sizeof(uint64_t));
+}
+
struct rtattr *nl_attr_nest(struct nlmsghdr *n, unsigned int maxlen, int type)
{
struct rtattr *nest = NLMSG_TAIL(n);
@@ -1080,7 +1093,8 @@ static int netlink_parse_error(const struct nlsock *nl, struct nlmsghdr *h,
nl_msg_type_to_str(msg_type), msg_type,
err->msg.nlmsg_seq, err->msg.nlmsg_pid);
} else {
- if ((msg_type != RTM_GETNEXTHOP) || !startup)
+ if ((msg_type != RTM_GETNEXTHOP && msg_type != RTM_GETVLAN) ||
+ !startup)
flog_err(EC_ZEBRA_UNEXPECTED_MESSAGE,
"%s error: %s, type=%s(%u), seq=%u, pid=%u",
nl->name, safe_strerror(-errnum),
@@ -1761,7 +1775,7 @@ void kernel_init(struct zebra_ns *zns)
{
uint32_t groups, dplane_groups, ext_groups;
#if defined SOL_NETLINK
- int one, ret;
+ int one, ret, grp;
#endif
/*
@@ -1772,6 +1786,11 @@ void kernel_init(struct zebra_ns *zns)
* keeping track of all the different values would
* lead to confusion, so we need to convert the
* RTNLGRP_XXX to a bit position for ourself
+ *
+ *
+ * NOTE: If the bit is >= 32, you must use setsockopt(). Those
+ * groups are added further below after SOL_NETLINK is verified to
+ * exist.
*/
groups = RTMGRP_LINK |
RTMGRP_IPV4_ROUTE |
@@ -1851,6 +1870,18 @@ void kernel_init(struct zebra_ns *zns)
* sure that we want to pull into our build system.
*/
#if defined SOL_NETLINK
+
+ /*
+ * setsockopt multicast group subscriptions that don't fit in nl_groups
+ */
+ grp = RTNLGRP_BRVLAN;
+ ret = setsockopt(zns->netlink.sock, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP,
+ &grp, sizeof(grp));
+
+ if (ret < 0)
+ zlog_notice(
+ "Registration for RTNLGRP_BRVLAN Membership failed : %d %s",
+ errno, safe_strerror(errno));
/*
* Let's tell the kernel that we want to receive extended
* ACKS over our command socket(s)
diff --git a/zebra/kernel_netlink.h b/zebra/kernel_netlink.h
index 08cd706a9f..7d5453d544 100644
--- a/zebra/kernel_netlink.h
+++ b/zebra/kernel_netlink.h
@@ -31,7 +31,7 @@ extern "C" {
((struct rtattr *)(((char *)(h)) + NLMSG_ALIGN(sizeof(struct nhmsg))))
-#define NL_RCV_PKT_BUF_SIZE 32768
+#define NL_RCV_PKT_BUF_SIZE (34 * 1024)
#define NL_PKT_BUF_SIZE 8192
/*
@@ -48,6 +48,8 @@ extern bool nl_attr_put16(struct nlmsghdr *n, unsigned int maxlen, int type,
uint16_t data);
extern bool nl_attr_put32(struct nlmsghdr *n, unsigned int maxlen, int type,
uint32_t data);
+extern bool nl_attr_put64(struct nlmsghdr *n, unsigned int maxlen, int type,
+ uint64_t data);
/*
* nl_attr_nest - start an attribute nest.
diff --git a/zebra/redistribute.c b/zebra/redistribute.c
index 4a8fe938ed..32d28f8002 100644
--- a/zebra/redistribute.c
+++ b/zebra/redistribute.c
@@ -118,13 +118,15 @@ static void zebra_redistribute(struct zserv *client, int type,
RNODE_FOREACH_RE (rn, newre) {
if (IS_ZEBRA_DEBUG_RIB)
zlog_debug(
- "%s: client %s %pRN(%u:%u) checking: selected=%d, type=%d, distance=%d, metric=%d zebra_check_addr=%d",
+ "%s: client %s %pRN(%u:%u) checking: selected=%d, type=%s, instance=%u, distance=%d, metric=%d zebra_check_addr=%d",
__func__,
zebra_route_string(client->proto), rn,
vrf_id, newre->instance,
!!CHECK_FLAG(newre->flags,
ZEBRA_FLAG_SELECTED),
- newre->type, newre->distance,
+ zebra_route_string(newre->type),
+ newre->instance,
+ newre->distance,
newre->metric,
zebra_check_addr(&rn->p));
diff --git a/zebra/rib.h b/zebra/rib.h
index 166500fa5c..8a3b3e657f 100644
--- a/zebra/rib.h
+++ b/zebra/rib.h
@@ -625,6 +625,9 @@ extern pid_t pid;
extern bool v6_rr_semantics;
+/* Name of hook calls */
+#define ZEBRA_ON_RIB_PROCESS_HOOK_CALL "on_rib_process_dplane_results"
+
#ifdef __cplusplus
}
#endif
diff --git a/zebra/rt.h b/zebra/rt.h
index 6f4dd48a54..4ebf479754 100644
--- a/zebra/rt.h
+++ b/zebra/rt.h
@@ -103,7 +103,9 @@ extern void kernel_init(struct zebra_ns *zns);
extern void kernel_terminate(struct zebra_ns *zns, bool complete);
extern void macfdb_read(struct zebra_ns *zns);
extern void macfdb_read_for_bridge(struct zebra_ns *zns, struct interface *ifp,
- struct interface *br_if);
+ struct interface *br_if, vlanid_t vid);
+extern void macfdb_read_mcast_entry_for_vni(struct zebra_ns *zns,
+ struct interface *ifp, vni_t vni);
extern void macfdb_read_specific_mac(struct zebra_ns *zns,
struct interface *br_if,
const struct ethaddr *mac, vlanid_t vid);
@@ -127,6 +129,7 @@ extern void kernel_update_multi(struct dplane_ctx_list_head *ctx_list);
* Called by the dplane pthread to read incoming OS messages and dispatch them.
*/
int kernel_dplane_read(struct zebra_dplane_info *info);
+extern void vlan_read(struct zebra_ns *zns);
#ifdef __cplusplus
}
diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c
index 216b719ff8..8bf59e02c7 100644
--- a/zebra/rt_netlink.c
+++ b/zebra/rt_netlink.c
@@ -153,6 +153,22 @@ static bool is_proto_nhg(uint32_t id, int type)
return false;
}
+/* Is vni mcast group */
+static bool is_mac_vni_mcast_group(struct ethaddr *mac, vni_t vni,
+ struct in_addr grp_addr)
+{
+ if (!vni)
+ return false;
+
+ if (!is_zero_mac(mac))
+ return false;
+
+ if (!IN_MULTICAST(ntohl(grp_addr.s_addr)))
+ return false;
+
+ return true;
+}
+
/*
* The ipv4_ll data structure is used for all 5549
* additions to the kernel. Let's figure out the
@@ -1309,6 +1325,7 @@ static bool _netlink_route_add_gateway_info(uint8_t route_family,
}
static int build_label_stack(struct mpls_label_stack *nh_label,
+ enum lsp_types_t nh_label_type,
mpls_lse_t *out_lse, char *label_buf,
size_t label_buf_size)
{
@@ -1316,7 +1333,8 @@ static int build_label_stack(struct mpls_label_stack *nh_label,
int num_labels = 0;
for (int i = 0; nh_label && i < nh_label->num_labels; i++) {
- if (nh_label->label[i] == MPLS_LABEL_IMPLICIT_NULL)
+ if (nh_label_type != ZEBRA_LSP_EVPN &&
+ nh_label->label[i] == MPLS_LABEL_IMPLICIT_NULL)
continue;
if (IS_ZEBRA_DEBUG_KERNEL) {
@@ -1330,15 +1348,58 @@ static int build_label_stack(struct mpls_label_stack *nh_label,
}
}
- out_lse[num_labels] =
- mpls_lse_encode(nh_label->label[i], 0, 0, 0);
+ if (nh_label_type == ZEBRA_LSP_EVPN)
+ out_lse[num_labels] = label2vni(&nh_label->label[i]);
+ else
+ out_lse[num_labels] =
+ mpls_lse_encode(nh_label->label[i], 0, 0, 0);
num_labels++;
}
return num_labels;
}
-static bool _netlink_route_encode_label_info(struct mpls_label_stack *nh_label,
+static bool _netlink_nexthop_encode_dvni_label(const struct nexthop *nexthop,
+ struct nlmsghdr *nlmsg,
+ mpls_lse_t *out_lse,
+ size_t buflen, char *label_buf)
+{
+ struct in_addr ipv4;
+
+ if (!nl_attr_put64(nlmsg, buflen, LWTUNNEL_IP_ID,
+ htonll((uint64_t)out_lse[0])))
+ return false;
+
+ if (nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX) {
+ if (!nl_attr_put(nlmsg, buflen, LWTUNNEL_IP_DST,
+ &nexthop->gate.ipv4, 4))
+ return false;
+
+ } else if (nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX) {
+ if (IS_MAPPED_IPV6(&nexthop->gate.ipv6)) {
+ ipv4_mapped_ipv6_to_ipv4(&nexthop->gate.ipv6, &ipv4);
+ if (!nl_attr_put(nlmsg, buflen, LWTUNNEL_IP_DST, &ipv4,
+ 4))
+ return false;
+
+ } else {
+ if (!nl_attr_put(nlmsg, buflen, LWTUNNEL_IP_DST,
+ &nexthop->gate.ipv6, 16))
+ return false;
+ }
+ } else {
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ zlog_debug(
+ "%s: nexthop %pNHv %s must NEXTHOP_TYPE_IPV*_IFINDEX to be vxlan encapped",
+ __func__, nexthop, label_buf);
+
+ return false;
+ }
+
+ return true;
+}
+
+static bool _netlink_route_encode_label_info(const struct nexthop *nexthop,
struct nlmsghdr *nlmsg,
size_t buflen, struct rtmsg *rtmsg,
char *label_buf,
@@ -1346,6 +1407,12 @@ static bool _netlink_route_encode_label_info(struct mpls_label_stack *nh_label,
{
mpls_lse_t out_lse[MPLS_MAX_LABELS];
int num_labels;
+ struct rtattr *nest;
+ struct mpls_label_stack *nh_label;
+ enum lsp_types_t nh_label_type;
+
+ nh_label = nexthop->nh_label;
+ nh_label_type = nexthop->nh_label_type;
/*
* label_buf is *only* currently used within debugging.
@@ -1355,10 +1422,26 @@ static bool _netlink_route_encode_label_info(struct mpls_label_stack *nh_label,
*/
label_buf[0] = '\0';
- num_labels =
- build_label_stack(nh_label, out_lse, label_buf, label_buf_size);
+ num_labels = build_label_stack(nh_label, nh_label_type, out_lse,
+ label_buf, label_buf_size);
+
+ if (num_labels && nh_label_type == ZEBRA_LSP_EVPN) {
+ if (!nl_attr_put16(nlmsg, buflen, RTA_ENCAP_TYPE,
+ LWTUNNEL_ENCAP_IP))
+ return false;
+
+ nest = nl_attr_nest(nlmsg, buflen, RTA_ENCAP);
+ if (!nest)
+ return false;
+
+ if (_netlink_nexthop_encode_dvni_label(nexthop, nlmsg, out_lse,
+ buflen,
+ label_buf) == false)
+ return false;
- if (num_labels) {
+ nl_attr_nest_end(nlmsg, nest);
+
+ } else if (num_labels) {
/* Set the BoS bit */
out_lse[num_labels - 1] |= htonl(1 << MPLS_LS_S_SHIFT);
@@ -1367,8 +1450,6 @@ static bool _netlink_route_encode_label_info(struct mpls_label_stack *nh_label,
num_labels * sizeof(mpls_lse_t)))
return false;
} else {
- struct rtattr *nest;
-
if (!nl_attr_put16(nlmsg, buflen, RTA_ENCAP_TYPE,
LWTUNNEL_ENCAP_MPLS))
return false;
@@ -1482,9 +1563,8 @@ static bool _netlink_route_build_singlepath(const struct prefix *p,
vrf = vrf_lookup_by_id(nexthop->vrf_id);
- if (!_netlink_route_encode_label_info(nexthop->nh_label, nlmsg,
- req_size, rtmsg, label_buf,
- sizeof(label_buf)))
+ if (!_netlink_route_encode_label_info(nexthop, nlmsg, req_size, rtmsg,
+ label_buf, sizeof(label_buf)))
return false;
if (nexthop->nh_srv6) {
@@ -1765,9 +1845,8 @@ static bool _netlink_route_build_multipath(
vrf = vrf_lookup_by_id(nexthop->vrf_id);
- if (!_netlink_route_encode_label_info(nexthop->nh_label, nlmsg,
- req_size, rtmsg, label_buf,
- sizeof(label_buf)))
+ if (!_netlink_route_encode_label_info(nexthop, nlmsg, req_size, rtmsg,
+ label_buf, sizeof(label_buf)))
return false;
if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK))
@@ -2649,11 +2728,28 @@ ssize_t netlink_nexthop_msg_encode(uint16_t cmd,
if (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_ONLINK))
req->nhm.nh_flags |= RTNH_F_ONLINK;
- num_labels =
- build_label_stack(nh->nh_label, out_lse,
- label_buf, sizeof(label_buf));
+ num_labels = build_label_stack(
+ nh->nh_label, nh->nh_label_type, out_lse,
+ label_buf, sizeof(label_buf));
- if (num_labels) {
+ if (num_labels && nh->nh_label_type == ZEBRA_LSP_EVPN) {
+ if (!nl_attr_put16(&req->n, buflen,
+ NHA_ENCAP_TYPE,
+ LWTUNNEL_ENCAP_IP))
+ return 0;
+
+ nest = nl_attr_nest(&req->n, buflen, NHA_ENCAP);
+ if (!nest)
+ return 0;
+
+ if (_netlink_nexthop_encode_dvni_label(
+ nh, &req->n, out_lse, buflen,
+ label_buf) == false)
+ return 0;
+
+ nl_attr_nest_end(&req->n, nest);
+
+ } else if (num_labels) {
/* Set the BoS bit */
out_lse[num_labels - 1] |=
htonl(1 << MPLS_LS_S_SHIFT);
@@ -3400,17 +3496,32 @@ static ssize_t netlink_neigh_update_msg_encode(
if (op == DPLANE_OP_MAC_INSTALL || op == DPLANE_OP_MAC_DELETE) {
vlanid_t vid = dplane_ctx_mac_get_vlan(ctx);
+ vni_t vni = dplane_ctx_mac_get_vni(ctx);
if (vid > 0) {
if (!nl_attr_put16(&req->n, datalen, NDA_VLAN, vid))
return 0;
}
+ if (vni > 0) {
+ if (!nl_attr_put32(&req->n, datalen, NDA_SRC_VNI, vni))
+ return 0;
+ }
+
if (!nl_attr_put32(&req->n, datalen, NDA_MASTER,
dplane_ctx_mac_get_br_ifindex(ctx)))
return 0;
}
+ if (op == DPLANE_OP_VTEP_ADD || op == DPLANE_OP_VTEP_DELETE) {
+ vni_t vni = dplane_ctx_neigh_get_vni(ctx);
+
+ if (vni > 0) {
+ if (!nl_attr_put32(&req->n, datalen, NDA_SRC_VNI, vni))
+ return 0;
+ }
+ }
+
return NLMSG_ALIGN(req->n.nlmsg_len);
}
@@ -3457,7 +3568,9 @@ static int netlink_macfdb_change(struct nlmsghdr *h, int len, ns_id_t ns_id)
bool sticky;
bool local_inactive = false;
bool dp_static = false;
+ vni_t vni = 0;
uint32_t nhg_id = 0;
+ bool vni_mcast_grp = false;
ndm = NLMSG_DATA(h);
@@ -3503,7 +3616,8 @@ static int netlink_macfdb_change(struct nlmsghdr *h, int len, ns_id_t ns_id)
IPV4_MAX_BYTELEN);
snprintfrr(dst_buf, sizeof(dst_buf), " dst %pI4",
&vtep_ip);
- }
+ } else
+ memset(&vtep_ip, 0, sizeof(vtep_ip));
if (tb[NDA_NH_ID])
nhg_id = *(uint32_t *)RTA_DATA(tb[NDA_NH_ID]);
@@ -3528,12 +3642,16 @@ static int netlink_macfdb_change(struct nlmsghdr *h, int len, ns_id_t ns_id)
}
}
+ if (tb[NDA_SRC_VNI])
+ vni = *(vni_t *)RTA_DATA(tb[NDA_SRC_VNI]);
+
if (IS_ZEBRA_DEBUG_KERNEL)
- zlog_debug("Rx %s AF_BRIDGE IF %u%s st 0x%x fl 0x%x MAC %pEA%s nhg %d",
- nl_msg_type_to_str(h->nlmsg_type),
- ndm->ndm_ifindex, vid_present ? vid_buf : "",
- ndm->ndm_state, ndm->ndm_flags, &mac,
- dst_present ? dst_buf : "", nhg_id);
+ zlog_debug(
+ "Rx %s AF_BRIDGE IF %u%s st 0x%x fl 0x%x MAC %pEA%s nhg %d vni %d",
+ nl_msg_type_to_str(h->nlmsg_type), ndm->ndm_ifindex,
+ vid_present ? vid_buf : "", ndm->ndm_state,
+ ndm->ndm_flags, &mac, dst_present ? dst_buf : "",
+ nhg_id, vni);
/* The interface should exist. */
ifp = if_lookup_by_index_per_ns(zebra_ns_lookup(ns_id),
@@ -3556,6 +3674,14 @@ static int netlink_macfdb_change(struct nlmsghdr *h, int len, ns_id_t ns_id)
return 0;
}
+ /* For per vni device, vni comes from device itself */
+ if (IS_ZEBRA_IF_VXLAN(ifp) && IS_ZEBRA_VXLAN_IF_VNI(zif)) {
+ struct zebra_vxlan_vni *vnip;
+
+ vnip = zebra_vxlan_if_vni_find(zif, 0);
+ vni = vnip->vni;
+ }
+
sticky = !!(ndm->ndm_flags & NTF_STICKY);
if (filter_vlan && vid != filter_vlan) {
@@ -3565,6 +3691,11 @@ static int netlink_macfdb_change(struct nlmsghdr *h, int len, ns_id_t ns_id)
return 0;
}
+ /*
+ * Check if this is a mcast group update (svd case)
+ */
+ vni_mcast_grp = is_mac_vni_mcast_group(&mac, vni, vtep_ip);
+
/* If add or update, do accordingly if learnt on a "local" interface; if
* the notification is over VxLAN, this has to be related to
* multi-homing,
@@ -3572,17 +3703,25 @@ static int netlink_macfdb_change(struct nlmsghdr *h, int len, ns_id_t ns_id)
*/
if (h->nlmsg_type == RTM_NEWNEIGH) {
/* Drop "permanent" entries. */
- if (ndm->ndm_state & NUD_PERMANENT) {
+ if (!vni_mcast_grp && (ndm->ndm_state & NUD_PERMANENT)) {
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug(
" Dropping entry because of NUD_PERMANENT");
return 0;
}
- if (IS_ZEBRA_IF_VXLAN(ifp))
+ if (IS_ZEBRA_IF_VXLAN(ifp)) {
+ if (!dst_present)
+ return 0;
+
+ if (vni_mcast_grp)
+ return zebra_vxlan_if_vni_mcast_group_add_update(
+ ifp, vni, &vtep_ip);
+
return zebra_vxlan_dp_network_mac_add(
- ifp, br_if, &mac, vid, nhg_id, sticky,
+ ifp, br_if, &mac, vid, vni, nhg_id, sticky,
!!(ndm->ndm_flags & NTF_EXT_LEARNED));
+ }
return zebra_vxlan_local_mac_add_update(ifp, br_if, &mac, vid,
sticky, local_inactive, dp_static);
@@ -3602,15 +3741,18 @@ static int netlink_macfdb_change(struct nlmsghdr *h, int len, ns_id_t ns_id)
return 0;
if (dst_present) {
- u_char zero_mac[6] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
+ if (vni_mcast_grp)
+ return zebra_vxlan_if_vni_mcast_group_del(ifp, vni,
+ &vtep_ip);
+
+ if (is_zero_mac(&mac) && vni)
+ return zebra_vxlan_check_readd_vtep(ifp, vni, vtep_ip);
- if (!memcmp(zero_mac, mac.octet, ETH_ALEN))
- return zebra_vxlan_check_readd_vtep(ifp, vtep_ip);
return 0;
}
if (IS_ZEBRA_IF_VXLAN(ifp))
- return zebra_vxlan_dp_network_mac_del(ifp, br_if, &mac, vid);
+ return 0;
return zebra_vxlan_local_mac_del(ifp, br_if, &mac, vid);
}
@@ -3687,11 +3829,9 @@ int netlink_macfdb_read(struct zebra_ns *zns)
* specific bridge and matching specific access VLAN (if VLAN-aware bridge).
*/
int netlink_macfdb_read_for_bridge(struct zebra_ns *zns, struct interface *ifp,
- struct interface *br_if)
+ struct interface *br_if, vlanid_t vid)
{
struct zebra_if *br_zif;
- struct zebra_if *zif;
- struct zebra_l2info_vxlan *vxl;
struct zebra_dplane_info dp_info;
int ret = 0;
@@ -3699,10 +3839,8 @@ int netlink_macfdb_read_for_bridge(struct zebra_ns *zns, struct interface *ifp,
/* Save VLAN we're filtering on, if needed. */
br_zif = (struct zebra_if *)br_if->info;
- zif = (struct zebra_if *)ifp->info;
- vxl = &zif->l2info.vxl;
if (IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(br_zif))
- filter_vlan = vxl->access_vlan;
+ filter_vlan = vid;
/* Get bridge FDB table for specific bridge - we do the VLAN filtering.
*/
@@ -3720,40 +3858,45 @@ int netlink_macfdb_read_for_bridge(struct zebra_ns *zns, struct interface *ifp,
/* Request for MAC FDB for a specific MAC address in VLAN from the kernel */
-static int netlink_request_specific_mac_in_bridge(struct zebra_ns *zns,
- int family, int type,
- struct interface *br_if,
- const struct ethaddr *mac,
- vlanid_t vid)
+static int netlink_request_specific_mac(struct zebra_ns *zns, int family,
+ int type, struct interface *ifp,
+ const struct ethaddr *mac, vlanid_t vid,
+ vni_t vni, uint8_t flags)
{
struct {
struct nlmsghdr n;
struct ndmsg ndm;
char buf[256];
} req;
- struct zebra_if *br_zif;
+ struct zebra_if *zif;
memset(&req, 0, sizeof(req));
req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg));
req.n.nlmsg_type = type; /* RTM_GETNEIGH */
req.n.nlmsg_flags = NLM_F_REQUEST;
req.ndm.ndm_family = family; /* AF_BRIDGE */
+ req.ndm.ndm_flags = flags;
/* req.ndm.ndm_state = NUD_REACHABLE; */
nl_attr_put(&req.n, sizeof(req), NDA_LLADDR, mac, 6);
- br_zif = (struct zebra_if *)br_if->info;
- if (IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(br_zif) && vid > 0)
- nl_attr_put16(&req.n, sizeof(req), NDA_VLAN, vid);
-
- nl_attr_put32(&req.n, sizeof(req), NDA_MASTER, br_if->ifindex);
+ zif = (struct zebra_if *)ifp->info;
+ /* Is this a read on a VXLAN interface? */
+ if (IS_ZEBRA_IF_VXLAN(ifp)) {
+ nl_attr_put32(&req.n, sizeof(req), NDA_VNI, vni);
+ /* TBD: Why is ifindex not filled in the non-vxlan case? */
+ req.ndm.ndm_ifindex = ifp->ifindex;
+ } else {
+ if (IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(zif) && vid > 0)
+ nl_attr_put16(&req.n, sizeof(req), NDA_VLAN, vid);
+ nl_attr_put32(&req.n, sizeof(req), NDA_MASTER, ifp->ifindex);
+ }
if (IS_ZEBRA_DEBUG_KERNEL)
- zlog_debug(
- "%s: Tx family %s IF %s(%u) vrf %s(%u) MAC %pEA vid %u",
- __func__, nl_family_to_str(req.ndm.ndm_family),
- br_if->name, br_if->ifindex, br_if->vrf->name,
- br_if->vrf->vrf_id, mac, vid);
+ zlog_debug("Tx %s %s IF %s(%u) MAC %pEA vid %u vni %u",
+ nl_msg_type_to_str(type),
+ nl_family_to_str(req.ndm.ndm_family), ifp->name,
+ ifp->ifindex, mac, vid, vni);
return netlink_request(&zns->netlink_cmd, &req);
}
@@ -3769,9 +3912,34 @@ int netlink_macfdb_read_specific_mac(struct zebra_ns *zns,
/* Get bridge FDB table for specific bridge - we do the VLAN filtering.
*/
- ret = netlink_request_specific_mac_in_bridge(zns, AF_BRIDGE,
- RTM_GETNEIGH,
- br_if, mac, vid);
+ ret = netlink_request_specific_mac(zns, AF_BRIDGE, RTM_GETNEIGH, br_if,
+ mac, vid, 0, 0);
+ if (ret < 0)
+ return ret;
+
+ ret = netlink_parse_info(netlink_macfdb_table, &zns->netlink_cmd,
+ &dp_info, 1, 0);
+
+ return ret;
+}
+
+int netlink_macfdb_read_mcast_for_vni(struct zebra_ns *zns,
+ struct interface *ifp, vni_t vni)
+{
+ struct zebra_if *zif;
+ struct ethaddr mac = {.octet = {0}};
+ struct zebra_dplane_info dp_info;
+ int ret = 0;
+
+ zif = ifp->info;
+ if (IS_ZEBRA_VXLAN_IF_VNI(zif))
+ return 0;
+
+ zebra_dplane_info_from_zns(&dp_info, zns, true /*is_cmd*/);
+
+ /* Get specific FDB entry for BUM handling, if any */
+ ret = netlink_request_specific_mac(zns, AF_BRIDGE, RTM_GETNEIGH, ifp,
+ &mac, 0, vni, NTF_SELF);
if (ret < 0)
return ret;
diff --git a/zebra/rt_netlink.h b/zebra/rt_netlink.h
index 8506367ae4..b550cc06b7 100644
--- a/zebra/rt_netlink.h
+++ b/zebra/rt_netlink.h
@@ -92,7 +92,10 @@ extern int netlink_neigh_change(struct nlmsghdr *h, ns_id_t ns_id);
extern int netlink_macfdb_read(struct zebra_ns *zns);
extern int netlink_macfdb_read_for_bridge(struct zebra_ns *zns,
struct interface *ifp,
- struct interface *br_if);
+ struct interface *br_if,
+ vlanid_t vid);
+extern int netlink_macfdb_read_mcast_for_vni(struct zebra_ns *zns,
+ struct interface *ifp, vni_t vni);
extern int netlink_neigh_read(struct zebra_ns *zns);
extern int netlink_neigh_read_for_vlan(struct zebra_ns *zns,
struct interface *vlan_if);
diff --git a/zebra/rtread_netlink.c b/zebra/rtread_netlink.c
index 8990f66ef8..f9d4605562 100644
--- a/zebra/rtread_netlink.c
+++ b/zebra/rtread_netlink.c
@@ -28,6 +28,7 @@
#include "zebra/zebra_pbr.h"
#include "zebra/zebra_tc.h"
#include "zebra/rt_netlink.h"
+#include "zebra/if_netlink.h"
#include "zebra/rule_netlink.h"
#include "zebra/tc_netlink.h"
@@ -42,9 +43,15 @@ void macfdb_read(struct zebra_ns *zns)
}
void macfdb_read_for_bridge(struct zebra_ns *zns, struct interface *ifp,
- struct interface *br_if)
+ struct interface *br_if, vlanid_t vid)
{
- netlink_macfdb_read_for_bridge(zns, ifp, br_if);
+ netlink_macfdb_read_for_bridge(zns, ifp, br_if, vid);
+}
+
+void macfdb_read_mcast_entry_for_vni(struct zebra_ns *zns,
+ struct interface *ifp, vni_t vni)
+{
+ netlink_macfdb_read_mcast_for_vni(zns, ifp, vni);
}
void macfdb_read_specific_mac(struct zebra_ns *zns, struct interface *br_if,
@@ -78,4 +85,9 @@ void kernel_read_tc_qdisc(struct zebra_ns *zns)
netlink_qdisc_read(zns);
}
+void vlan_read(struct zebra_ns *zns)
+{
+ netlink_vlan_read(zns);
+}
+
#endif /* GNU_LINUX */
diff --git a/zebra/rtread_sysctl.c b/zebra/rtread_sysctl.c
index 35dde0e686..f5b918c022 100644
--- a/zebra/rtread_sysctl.c
+++ b/zebra/rtread_sysctl.c
@@ -84,7 +84,12 @@ void macfdb_read(struct zebra_ns *zns)
}
void macfdb_read_for_bridge(struct zebra_ns *zns, struct interface *ifp,
- struct interface *br_if)
+ struct interface *br_if, vlanid_t vid)
+{
+}
+
+void macfdb_read_mcast_entry_for_vni(struct zebra_ns *zns,
+ struct interface *ifp, vni_t vni)
{
}
@@ -113,4 +118,8 @@ void kernel_read_tc_qdisc(struct zebra_ns *zns)
{
}
+void vlan_read(struct zebra_ns *zns)
+{
+}
+
#endif /* !defined(GNU_LINUX) */
diff --git a/zebra/subdir.am b/zebra/subdir.am
index 00f7d52994..1060e38785 100644
--- a/zebra/subdir.am
+++ b/zebra/subdir.am
@@ -67,6 +67,7 @@ zebra_zebra_SOURCES = \
zebra/zebra_errors.c \
zebra/zebra_gr.c \
zebra/zebra_l2.c \
+ zebra/zebra_l2_bridge_if.c \
zebra/zebra_evpn.c \
zebra/zebra_evpn_mac.c \
zebra/zebra_evpn_neigh.c \
@@ -106,6 +107,7 @@ zebra_zebra_SOURCES = \
zebra/zebra_vrf.c \
zebra/zebra_vty.c \
zebra/zebra_vxlan.c \
+ zebra/zebra_vxlan_if.c \
zebra/zebra_evpn_mh.c \
zebra/zebra_neigh.c \
zebra/zserv.c \
@@ -185,6 +187,8 @@ noinst_HEADERS += \
zebra/zebra_vxlan_private.h \
zebra/zebra_evpn_mh.h \
zebra/zebra_neigh.h \
+ zebra/zebra_l2_bridge_if.h \
+ zebra/zebra_vxlan_if.h \
zebra/zserv.h \
zebra/dpdk/zebra_dplane_dpdk.h \
zebra/dpdk/zebra_dplane_dpdk_private.h \
diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c
index fdea766a1b..15b5790923 100644
--- a/zebra/zapi_msg.c
+++ b/zebra/zapi_msg.c
@@ -1779,13 +1779,19 @@ static bool zapi_read_nexthops(struct zserv *client, struct prefix *p,
nexthop->srte_color = api_nh->srte_color;
}
- /* MPLS labels for BGP-LU or Segment Routing */
+ /* Labels for MPLS BGP-LU or Segment Routing or EVPN */
if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_LABEL)
&& api_nh->type != NEXTHOP_TYPE_IFINDEX
&& api_nh->type != NEXTHOP_TYPE_BLACKHOLE
&& api_nh->label_num > 0) {
- label_type = lsp_type_from_re_type(client->proto);
+ /* If label type was passed, use it */
+ if (api_nh->label_type)
+ label_type = api_nh->label_type;
+ else
+ label_type =
+ lsp_type_from_re_type(client->proto);
+
nexthop_add_labels(nexthop, label_type,
api_nh->label_num,
&api_nh->labels[0]);
@@ -1823,7 +1829,7 @@ static bool zapi_read_nexthops(struct zserv *client, struct prefix *p,
mpls_label2str(nexthop->nh_label->num_labels,
nexthop->nh_label->label,
labelbuf, sizeof(labelbuf),
- false);
+ nexthop->nh_label_type, false);
}
zlog_debug("%s: nh=%s, vrf_id=%d %s",
diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c
index ef4cef65ca..dea5af44f8 100644
--- a/zebra/zebra_dplane.c
+++ b/zebra/zebra_dplane.c
@@ -222,6 +222,7 @@ struct dplane_mac_info {
vlanid_t vid;
ifindex_t br_ifindex;
struct ethaddr mac;
+ vni_t vni;
struct in_addr vtep_ip;
bool is_sticky;
uint32_t nhg_id;
@@ -237,6 +238,7 @@ struct dplane_neigh_info {
struct ethaddr mac;
struct ipaddr ip_addr;
} link;
+ vni_t vni;
uint32_t flags;
uint16_t state;
uint32_t update_flags;
@@ -628,17 +630,16 @@ static enum zebra_dplane_result pw_update_internal(struct zebra_pw *pw,
static enum zebra_dplane_result intf_addr_update_internal(
const struct interface *ifp, const struct connected *ifc,
enum dplane_op_e op);
-static enum zebra_dplane_result mac_update_common(
- enum dplane_op_e op, const struct interface *ifp,
- const struct interface *br_ifp,
- vlanid_t vid, const struct ethaddr *mac,
- struct in_addr vtep_ip, bool sticky, uint32_t nhg_id,
- uint32_t update_flags);
+static enum zebra_dplane_result
+mac_update_common(enum dplane_op_e op, const struct interface *ifp,
+ const struct interface *br_ifp, vlanid_t vid,
+ const struct ethaddr *mac, vni_t vni, struct in_addr vtep_ip,
+ bool sticky, uint32_t nhg_id, uint32_t update_flags);
static enum zebra_dplane_result
neigh_update_internal(enum dplane_op_e op, const struct interface *ifp,
const void *link, int link_family,
- const struct ipaddr *ip, uint32_t flags, uint16_t state,
- uint32_t update_flags, int protocol);
+ const struct ipaddr *ip, vni_t vni, uint32_t flags,
+ uint16_t state, uint32_t update_flags, int protocol);
/*
* Public APIs
@@ -2229,6 +2230,12 @@ const struct ethaddr *dplane_ctx_mac_get_addr(
return &(ctx->u.macinfo.mac);
}
+vni_t dplane_ctx_mac_get_vni(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+ return ctx->u.macinfo.vni;
+}
+
const struct in_addr *dplane_ctx_mac_get_vtep_ip(
const struct zebra_dplane_ctx *ctx)
{
@@ -2264,6 +2271,12 @@ const struct ethaddr *dplane_ctx_neigh_get_mac(
return &(ctx->u.neigh.link.mac);
}
+vni_t dplane_ctx_neigh_get_vni(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+ return ctx->u.neigh.vni;
+}
+
uint32_t dplane_ctx_neigh_get_flags(const struct zebra_dplane_ctx *ctx)
{
DPLANE_CTX_VALID(ctx);
@@ -4649,14 +4662,11 @@ enum zebra_dplane_result dplane_intf_delete(const struct interface *ifp)
/*
* Enqueue vxlan/evpn mac add (or update).
*/
-enum zebra_dplane_result dplane_rem_mac_add(const struct interface *ifp,
- const struct interface *bridge_ifp,
- vlanid_t vid,
- const struct ethaddr *mac,
- struct in_addr vtep_ip,
- bool sticky,
- uint32_t nhg_id,
- bool was_static)
+enum zebra_dplane_result
+dplane_rem_mac_add(const struct interface *ifp,
+ const struct interface *bridge_ifp, vlanid_t vid,
+ const struct ethaddr *mac, vni_t vni, struct in_addr vtep_ip,
+ bool sticky, uint32_t nhg_id, bool was_static)
{
enum zebra_dplane_result result;
uint32_t update_flags = 0;
@@ -4666,8 +4676,9 @@ enum zebra_dplane_result dplane_rem_mac_add(const struct interface *ifp,
update_flags |= DPLANE_MAC_WAS_STATIC;
/* Use common helper api */
- result = mac_update_common(DPLANE_OP_MAC_INSTALL, ifp, bridge_ifp,
- vid, mac, vtep_ip, sticky, nhg_id, update_flags);
+ result = mac_update_common(DPLANE_OP_MAC_INSTALL, ifp, bridge_ifp, vid,
+ mac, vni, vtep_ip, sticky, nhg_id,
+ update_flags);
return result;
}
@@ -4675,10 +4686,10 @@ enum zebra_dplane_result dplane_rem_mac_add(const struct interface *ifp,
* Enqueue vxlan/evpn mac delete.
*/
enum zebra_dplane_result dplane_rem_mac_del(const struct interface *ifp,
- const struct interface *bridge_ifp,
- vlanid_t vid,
- const struct ethaddr *mac,
- struct in_addr vtep_ip)
+ const struct interface *bridge_ifp,
+ vlanid_t vid,
+ const struct ethaddr *mac,
+ vni_t vni, struct in_addr vtep_ip)
{
enum zebra_dplane_result result;
uint32_t update_flags = 0;
@@ -4686,8 +4697,8 @@ enum zebra_dplane_result dplane_rem_mac_del(const struct interface *ifp,
update_flags |= DPLANE_MAC_REMOTE;
/* Use common helper api */
- result = mac_update_common(DPLANE_OP_MAC_DELETE, ifp, bridge_ifp,
- vid, mac, vtep_ip, false, 0, update_flags);
+ result = mac_update_common(DPLANE_OP_MAC_DELETE, ifp, bridge_ifp, vid,
+ mac, vni, vtep_ip, false, 0, update_flags);
return result;
}
@@ -4716,7 +4727,7 @@ enum zebra_dplane_result dplane_neigh_ip_update(enum dplane_op_e op,
update_flags = DPLANE_NEIGH_NO_EXTENSION;
result = neigh_update_internal(op, ifp, (const void *)link_ip,
- ipaddr_family(link_ip), ip, 0, state,
+ ipaddr_family(link_ip), ip, 0, 0, state,
update_flags, protocol);
return result;
@@ -4746,9 +4757,8 @@ enum zebra_dplane_result dplane_local_mac_add(const struct interface *ifp,
vtep_ip.s_addr = 0;
/* Use common helper api */
- result = mac_update_common(DPLANE_OP_MAC_INSTALL, ifp, bridge_ifp,
- vid, mac, vtep_ip, sticky, 0,
- update_flags);
+ result = mac_update_common(DPLANE_OP_MAC_INSTALL, ifp, bridge_ifp, vid,
+ mac, 0, vtep_ip, sticky, 0, update_flags);
return result;
}
@@ -4767,21 +4777,17 @@ dplane_local_mac_del(const struct interface *ifp,
/* Use common helper api */
result = mac_update_common(DPLANE_OP_MAC_DELETE, ifp, bridge_ifp, vid,
- mac, vtep_ip, false, 0, 0);
+ mac, 0, vtep_ip, false, 0, 0);
return result;
}
/*
* Public api to init an empty context - either newly-allocated or
* reset/cleared - for a MAC update.
*/
-void dplane_mac_init(struct zebra_dplane_ctx *ctx,
- const struct interface *ifp,
- const struct interface *br_ifp,
- vlanid_t vid,
- const struct ethaddr *mac,
- struct in_addr vtep_ip,
- bool sticky,
- uint32_t nhg_id,
+void dplane_mac_init(struct zebra_dplane_ctx *ctx, const struct interface *ifp,
+ const struct interface *br_ifp, vlanid_t vid,
+ const struct ethaddr *mac, vni_t vni,
+ struct in_addr vtep_ip, bool sticky, uint32_t nhg_id,
uint32_t update_flags)
{
struct zebra_ns *zns;
@@ -4801,6 +4807,7 @@ void dplane_mac_init(struct zebra_dplane_ctx *ctx,
ctx->u.macinfo.br_ifindex = br_ifp->ifindex;
ctx->u.macinfo.vtep_ip = vtep_ip;
ctx->u.macinfo.mac = *mac;
+ ctx->u.macinfo.vni = vni;
ctx->u.macinfo.vid = vid;
ctx->u.macinfo.is_sticky = sticky;
ctx->u.macinfo.nhg_id = nhg_id;
@@ -4811,15 +4818,10 @@ void dplane_mac_init(struct zebra_dplane_ctx *ctx,
* Common helper api for MAC address/vxlan updates
*/
static enum zebra_dplane_result
-mac_update_common(enum dplane_op_e op,
- const struct interface *ifp,
- const struct interface *br_ifp,
- vlanid_t vid,
- const struct ethaddr *mac,
- struct in_addr vtep_ip,
- bool sticky,
- uint32_t nhg_id,
- uint32_t update_flags)
+mac_update_common(enum dplane_op_e op, const struct interface *ifp,
+ const struct interface *br_ifp, vlanid_t vid,
+ const struct ethaddr *mac, vni_t vni, struct in_addr vtep_ip,
+ bool sticky, uint32_t nhg_id, uint32_t update_flags)
{
enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
int ret;
@@ -4833,7 +4835,7 @@ mac_update_common(enum dplane_op_e op,
ctx->zd_op = op;
/* Common init for the ctx */
- dplane_mac_init(ctx, ifp, br_ifp, vid, mac, vtep_ip, sticky,
+ dplane_mac_init(ctx, ifp, br_ifp, vid, mac, vni, vtep_ip, sticky,
nhg_id, update_flags);
/* Enqueue for processing on the dplane pthread */
@@ -4873,7 +4875,7 @@ enum zebra_dplane_result dplane_rem_neigh_add(const struct interface *ifp,
result = neigh_update_internal(
DPLANE_OP_NEIGH_INSTALL, ifp, (const void *)mac, AF_ETHERNET,
- ip, flags, DPLANE_NUD_NOARP, update_flags, 0);
+ ip, 0, flags, DPLANE_NUD_NOARP, update_flags, 0);
return result;
}
@@ -4906,8 +4908,8 @@ enum zebra_dplane_result dplane_local_neigh_add(const struct interface *ifp,
ntf |= DPLANE_NTF_ROUTER;
result = neigh_update_internal(DPLANE_OP_NEIGH_INSTALL, ifp,
- (const void *)mac, AF_ETHERNET, ip, ntf,
- state, update_flags, 0);
+ (const void *)mac, AF_ETHERNET, ip, 0,
+ ntf, state, update_flags, 0);
return result;
}
@@ -4924,7 +4926,8 @@ enum zebra_dplane_result dplane_rem_neigh_delete(const struct interface *ifp,
update_flags |= DPLANE_NEIGH_REMOTE;
result = neigh_update_internal(DPLANE_OP_NEIGH_DELETE, ifp, NULL,
- AF_ETHERNET, ip, 0, 0, update_flags, 0);
+ AF_ETHERNET, ip, 0, 0, 0, update_flags,
+ 0);
return result;
}
@@ -4948,7 +4951,7 @@ enum zebra_dplane_result dplane_vtep_add(const struct interface *ifp,
addr.ipaddr_v4 = *ip;
result = neigh_update_internal(DPLANE_OP_VTEP_ADD, ifp, &mac,
- AF_ETHERNET, &addr, 0, 0, 0, 0);
+ AF_ETHERNET, &addr, vni, 0, 0, 0, 0);
return result;
}
@@ -4974,7 +4977,7 @@ enum zebra_dplane_result dplane_vtep_delete(const struct interface *ifp,
result = neigh_update_internal(DPLANE_OP_VTEP_DELETE, ifp,
(const void *)&mac, AF_ETHERNET, &addr,
- 0, 0, 0, 0);
+ vni, 0, 0, 0, 0);
return result;
}
@@ -4985,7 +4988,7 @@ enum zebra_dplane_result dplane_neigh_discover(const struct interface *ifp,
enum zebra_dplane_result result;
result = neigh_update_internal(DPLANE_OP_NEIGH_DISCOVER, ifp, NULL,
- AF_ETHERNET, ip, DPLANE_NTF_USE,
+ AF_ETHERNET, ip, 0, DPLANE_NTF_USE,
DPLANE_NUD_INCOMPLETE, 0, 0);
return result;
@@ -5053,8 +5056,8 @@ enum zebra_dplane_result dplane_neigh_table_update(const struct interface *ifp,
static enum zebra_dplane_result
neigh_update_internal(enum dplane_op_e op, const struct interface *ifp,
const void *link, const int link_family,
- const struct ipaddr *ip, uint32_t flags, uint16_t state,
- uint32_t update_flags, int protocol)
+ const struct ipaddr *ip, vni_t vni, uint32_t flags,
+ uint16_t state, uint32_t update_flags, int protocol)
{
enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
int ret;
@@ -5105,6 +5108,7 @@ neigh_update_internal(enum dplane_op_e op, const struct interface *ifp,
ctx->u.neigh.link.ip_addr = *link_ip;
ctx->u.neigh.flags = flags;
+ ctx->u.neigh.vni = vni;
ctx->u.neigh.state = state;
ctx->u.neigh.update_flags = update_flags;
diff --git a/zebra/zebra_dplane.h b/zebra/zebra_dplane.h
index ae13243a16..0c84992051 100644
--- a/zebra/zebra_dplane.h
+++ b/zebra/zebra_dplane.h
@@ -568,6 +568,7 @@ uint32_t dplane_ctx_mac_get_update_flags(const struct zebra_dplane_ctx *ctx);
uint32_t dplane_ctx_mac_get_nhg_id(const struct zebra_dplane_ctx *ctx);
const struct ethaddr *dplane_ctx_mac_get_addr(
const struct zebra_dplane_ctx *ctx);
+vni_t dplane_ctx_mac_get_vni(const struct zebra_dplane_ctx *ctx);
const struct in_addr *dplane_ctx_mac_get_vtep_ip(
const struct zebra_dplane_ctx *ctx);
ifindex_t dplane_ctx_mac_get_br_ifindex(const struct zebra_dplane_ctx *ctx);
@@ -577,6 +578,7 @@ const struct ipaddr *dplane_ctx_neigh_get_ipaddr(
const struct zebra_dplane_ctx *ctx);
const struct ethaddr *dplane_ctx_neigh_get_mac(
const struct zebra_dplane_ctx *ctx);
+vni_t dplane_ctx_neigh_get_vni(const struct zebra_dplane_ctx *ctx);
const struct ipaddr *
dplane_ctx_neigh_get_link_ip(const struct zebra_dplane_ctx *ctx);
uint32_t dplane_ctx_neigh_get_flags(const struct zebra_dplane_ctx *ctx);
@@ -792,14 +794,11 @@ enum zebra_dplane_result dplane_neigh_ip_update(enum dplane_op_e op,
/*
* Enqueue evpn mac operations for the dataplane.
*/
-enum zebra_dplane_result dplane_rem_mac_add(const struct interface *ifp,
- const struct interface *bridge_ifp,
- vlanid_t vid,
- const struct ethaddr *mac,
- struct in_addr vtep_ip,
- bool sticky,
- uint32_t nhg_id,
- bool was_static);
+enum zebra_dplane_result
+dplane_rem_mac_add(const struct interface *ifp,
+ const struct interface *bridge_ifp, vlanid_t vid,
+ const struct ethaddr *mac, vni_t vni, struct in_addr vtep_ip,
+ bool sticky, uint32_t nhg_id, bool was_static);
enum zebra_dplane_result dplane_local_mac_add(const struct interface *ifp,
const struct interface *bridge_ifp,
@@ -815,20 +814,17 @@ dplane_local_mac_del(const struct interface *ifp,
const struct ethaddr *mac);
enum zebra_dplane_result dplane_rem_mac_del(const struct interface *ifp,
- const struct interface *bridge_ifp,
- vlanid_t vid,
- const struct ethaddr *mac,
- struct in_addr vtep_ip);
+ const struct interface *bridge_ifp,
+ vlanid_t vid,
+ const struct ethaddr *mac,
+ vni_t vni, struct in_addr vtep_ip);
/* Helper api to init an empty or new context for a MAC update */
-void dplane_mac_init(struct zebra_dplane_ctx *ctx,
- const struct interface *ifp,
- const struct interface *br_ifp,
- vlanid_t vid,
- const struct ethaddr *mac,
- struct in_addr vtep_ip,
- bool sticky,
- uint32_t nhg_id, uint32_t update_flags);
+void dplane_mac_init(struct zebra_dplane_ctx *ctx, const struct interface *ifp,
+ const struct interface *br_ifp, vlanid_t vid,
+ const struct ethaddr *mac, vni_t vni,
+ struct in_addr vtep_ip, bool sticky, uint32_t nhg_id,
+ uint32_t update_flags);
/*
* Enqueue evpn neighbor updates for the dataplane.
diff --git a/zebra/zebra_evpn.c b/zebra/zebra_evpn.c
index ff9ca1ac25..bbe53adb2f 100644
--- a/zebra/zebra_evpn.c
+++ b/zebra/zebra_evpn.c
@@ -44,13 +44,14 @@
#include "zebra/rt_netlink.h"
#include "zebra/zebra_errors.h"
#include "zebra/zebra_l2.h"
+#include "zebra/zebra_l2_bridge_if.h"
#include "zebra/zebra_ns.h"
#include "zebra/zebra_vrf.h"
#include "zebra/zebra_vxlan.h"
+#include "zebra/zebra_vxlan_private.h"
#include "zebra/zebra_evpn.h"
#include "zebra/zebra_evpn_mac.h"
#include "zebra/zebra_evpn_neigh.h"
-#include "zebra/zebra_vxlan_private.h"
#include "zebra/zebra_evpn_mh.h"
#include "zebra/zebra_evpn_vxlan.h"
#include "zebra/zebra_router.h"
@@ -117,6 +118,9 @@ void zebra_evpn_print(struct zebra_evpn *zevpn, void **ctxt)
if (json == NULL) {
vty_out(vty, "VNI: %u\n", zevpn->vni);
vty_out(vty, " Type: %s\n", "L2");
+ vty_out(vty, " Vlan: %u\n", zevpn->vid);
+ vty_out(vty, " Bridge: %s\n",
+ zevpn->bridge_if ? zevpn->bridge_if->name : "-");
vty_out(vty, " Tenant VRF: %s\n", vrf_id_to_name(zevpn->vrf_id));
} else {
json_object_int_add(json, "vni", zevpn->vni);
@@ -455,16 +459,16 @@ int zebra_evpn_gw_macip_add(struct interface *ifp, struct zebra_evpn *zevpn,
{
struct zebra_mac *mac = NULL;
struct zebra_if *zif = NULL;
- struct zebra_l2info_vxlan *vxl = NULL;
+ struct zebra_vxlan_vni *vni;
zif = zevpn->vxlan_if->info;
if (!zif)
return -1;
- vxl = &zif->l2info.vxl;
+ vni = zebra_vxlan_if_vni_find(zif, zevpn->vni);
zebra_evpn_mac_gw_macip_add(ifp, zevpn, ip, &mac, macaddr,
- vxl->access_vlan, true);
+ vni->access_vlan, true);
return zebra_evpn_neigh_gw_macip_add(ifp, zevpn, ip, mac);
}
@@ -523,7 +527,7 @@ void zebra_evpn_gw_macip_del_for_evpn_hash(struct hash_bucket *bucket,
{
struct zebra_evpn *zevpn = NULL;
struct zebra_if *zif = NULL;
- struct zebra_l2info_vxlan zl2_info;
+ struct zebra_vxlan_vni *vni = NULL;
struct interface *vlan_if = NULL;
struct interface *vrr_if = NULL;
struct interface *ifp;
@@ -550,10 +554,11 @@ void zebra_evpn_gw_macip_del_for_evpn_hash(struct hash_bucket *bucket,
if (!if_is_operative(ifp) || !zif->brslave_info.br_if)
return;
- zl2_info = zif->l2info.vxl;
+ vni = zebra_vxlan_if_vni_find(zif, zevpn->vni);
+ if (!vni)
+ return;
- vlan_if =
- zvni_map_to_svi(zl2_info.access_vlan, zif->brslave_info.br_if);
+ vlan_if = zvni_map_to_svi(vni->access_vlan, zif->brslave_info.br_if);
if (!vlan_if)
return;
@@ -573,10 +578,10 @@ void zebra_evpn_gw_macip_add_for_evpn_hash(struct hash_bucket *bucket,
{
struct zebra_evpn *zevpn = NULL;
struct zebra_if *zif = NULL;
- struct zebra_l2info_vxlan zl2_info;
struct interface *vlan_if = NULL;
struct interface *vrr_if = NULL;
struct interface *ifp = NULL;
+ struct zebra_vxlan_vni *vni = NULL;
zevpn = (struct zebra_evpn *)bucket->data;
@@ -588,10 +593,11 @@ void zebra_evpn_gw_macip_add_for_evpn_hash(struct hash_bucket *bucket,
/* If down or not mapped to a bridge, we're done. */
if (!if_is_operative(ifp) || !zif->brslave_info.br_if)
return;
- zl2_info = zif->l2info.vxl;
+ vni = zebra_vxlan_if_vni_find(zif, zevpn->vni);
+ if (!vni)
+ return;
- vlan_if =
- zvni_map_to_svi(zl2_info.access_vlan, zif->brslave_info.br_if);
+ vlan_if = zvni_map_to_svi(vni->access_vlan, zif->brslave_info.br_if);
if (!vlan_if)
return;
@@ -615,8 +621,8 @@ void zebra_evpn_svi_macip_del_for_evpn_hash(struct hash_bucket *bucket,
{
struct zebra_evpn *zevpn = NULL;
struct zebra_if *zif = NULL;
- struct zebra_l2info_vxlan zl2_info;
struct interface *vlan_if = NULL;
+ struct zebra_vxlan_vni *vni = NULL;
struct interface *ifp;
/* Add primary SVI MAC*/
@@ -643,10 +649,11 @@ void zebra_evpn_svi_macip_del_for_evpn_hash(struct hash_bucket *bucket,
if (!if_is_operative(ifp) || !zif->brslave_info.br_if)
return;
- zl2_info = zif->l2info.vxl;
+ vni = zebra_vxlan_if_vni_find(zif, zevpn->vni);
+ if (!vni)
+ return;
- vlan_if =
- zvni_map_to_svi(zl2_info.access_vlan, zif->brslave_info.br_if);
+ vlan_if = zvni_map_to_svi(vni->access_vlan, zif->brslave_info.br_if);
if (!vlan_if)
return;
@@ -660,6 +667,7 @@ static int zebra_evpn_map_vlan_ns(struct ns *ns,
void *_in_param,
void **_p_zevpn)
{
+ int found = 0;
struct zebra_ns *zns = ns->info;
struct route_node *rn;
struct interface *br_if;
@@ -667,42 +675,59 @@ static int zebra_evpn_map_vlan_ns(struct ns *ns,
struct zebra_evpn *zevpn;
struct interface *tmp_if = NULL;
struct zebra_if *zif;
- struct zebra_l2info_vxlan *vxl = NULL;
struct zebra_from_svi_param *in_param =
(struct zebra_from_svi_param *)_in_param;
+ vlanid_t vid;
+ vni_t vni_id = 0;
+ uint8_t bridge_vlan_aware;
assert(p_zevpn && in_param);
br_if = in_param->br_if;
+ assert(br_if);
zif = in_param->zif;
assert(zif);
- assert(br_if);
-
- /* See if this interface (or interface plus VLAN Id) maps to a VxLAN */
- /* TODO: Optimize with a hash. */
- for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) {
- tmp_if = (struct interface *)rn->info;
- if (!tmp_if)
- continue;
- zif = tmp_if->info;
- if (!zif || zif->zif_type != ZEBRA_IF_VXLAN)
- continue;
- if (!if_is_operative(tmp_if))
- continue;
- vxl = &zif->l2info.vxl;
-
- if (zif->brslave_info.br_if != br_if)
- continue;
+ vid = in_param->vid;
+ bridge_vlan_aware = in_param->bridge_vlan_aware;
- if (!in_param->bridge_vlan_aware
- || vxl->access_vlan == in_param->vid) {
- zevpn = zebra_evpn_lookup(vxl->vni);
- *p_zevpn = zevpn;
- return NS_WALK_STOP;
+ if (bridge_vlan_aware) {
+ vni_id = zebra_l2_bridge_if_vni_find(zif, vid);
+ if (vni_id)
+ found = 1;
+ } else {
+ /*
+ * See if this interface (or interface plus VLAN Id) maps to a
+ * VxLAN
+ */
+ /* TODO: Optimize with a hash. */
+ for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) {
+ tmp_if = (struct interface *)rn->info;
+ if (!tmp_if)
+ continue;
+ zif = tmp_if->info;
+ if (!zif || zif->zif_type != ZEBRA_IF_VXLAN)
+ continue;
+ if (!if_is_operative(tmp_if))
+ continue;
+
+ if (zif->brslave_info.br_if != br_if)
+ continue;
+
+ vni_id =
+ zebra_vxlan_if_access_vlan_vni_find(zif, br_if);
+ if (vni_id) {
+ found = 1;
+ break;
+ }
}
}
- return NS_WALK_CONTINUE;
+ if (!found)
+ return NS_WALK_CONTINUE;
+
+ zevpn = zebra_evpn_lookup(vni_id);
+ *p_zevpn = zevpn;
+ return NS_WALK_STOP;
}
/*
@@ -713,7 +738,6 @@ struct zebra_evpn *zebra_evpn_map_vlan(struct interface *ifp,
struct interface *br_if, vlanid_t vid)
{
struct zebra_if *zif;
- struct zebra_l2info_bridge *br;
struct zebra_evpn **p_zevpn;
struct zebra_evpn *zevpn = NULL;
struct zebra_from_svi_param in_param;
@@ -721,8 +745,7 @@ struct zebra_evpn *zebra_evpn_map_vlan(struct interface *ifp,
/* Determine if bridge is VLAN-aware or not */
zif = br_if->info;
assert(zif);
- br = &zif->l2info.br;
- in_param.bridge_vlan_aware = br->vlan_aware;
+ in_param.bridge_vlan_aware = IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(zif);
in_param.vid = vid;
in_param.br_if = br_if;
in_param.zif = zif;
@@ -745,43 +768,60 @@ static int zebra_evpn_from_svi_ns(struct ns *ns,
struct zebra_evpn *zevpn;
struct interface *tmp_if = NULL;
struct zebra_if *zif;
- struct zebra_l2info_vxlan *vxl = NULL;
+ struct zebra_if *br_zif;
+ struct zebra_l2_bridge_vlan *bvlan;
struct zebra_from_svi_param *in_param =
(struct zebra_from_svi_param *)_in_param;
int found = 0;
+ vni_t vni_id = 0;
+ vlanid_t vid = 0;
+ uint8_t bridge_vlan_aware;
if (!in_param)
return NS_WALK_STOP;
+
br_if = in_param->br_if;
zif = in_param->zif;
assert(zif);
-
- /* TODO: Optimize with a hash. */
- for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) {
- tmp_if = (struct interface *)rn->info;
- if (!tmp_if)
- continue;
- zif = tmp_if->info;
- if (!zif || zif->zif_type != ZEBRA_IF_VXLAN)
- continue;
- if (!if_is_operative(tmp_if))
- continue;
- vxl = &zif->l2info.vxl;
-
- if (zif->brslave_info.br_if != br_if)
- continue;
-
- if (!in_param->bridge_vlan_aware
- || vxl->access_vlan == in_param->vid) {
+ bridge_vlan_aware = in_param->bridge_vlan_aware;
+ vid = in_param->vid;
+ br_zif = br_if->info;
+ assert(br_zif);
+
+ if (bridge_vlan_aware) {
+ bvlan = zebra_l2_bridge_if_vlan_find(br_zif, vid);
+ if (bvlan && bvlan->access_bd && bvlan->access_bd->vni) {
found = 1;
- break;
+ vni_id = bvlan->access_bd->vni;
+ }
+ } else {
+ /* TODO: Optimize with a hash. */
+ for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) {
+ tmp_if = (struct interface *)rn->info;
+ if (!tmp_if)
+ continue;
+ zif = tmp_if->info;
+ if (!zif || zif->zif_type != ZEBRA_IF_VXLAN)
+ continue;
+ if (!if_is_operative(tmp_if))
+ continue;
+
+ if (zif->brslave_info.br_if != br_if)
+ continue;
+
+ vni_id =
+ zebra_vxlan_if_access_vlan_vni_find(zif, br_if);
+ if (vni_id) {
+ found = 1;
+ break;
+ }
}
}
if (!found)
return NS_WALK_CONTINUE;
- zevpn = zebra_evpn_lookup(vxl->vni);
+ zevpn = zebra_evpn_lookup(vni_id);
if (p_zevpn)
*p_zevpn = zevpn;
return NS_WALK_STOP;
@@ -794,7 +834,6 @@ static int zebra_evpn_from_svi_ns(struct ns *ns,
struct zebra_evpn *zebra_evpn_from_svi(struct interface *ifp,
struct interface *br_if)
{
- struct zebra_l2info_bridge *br;
struct zebra_evpn *zevpn = NULL;
struct zebra_evpn **p_zevpn;
struct zebra_if *zif;
@@ -810,8 +849,7 @@ struct zebra_evpn *zebra_evpn_from_svi(struct interface *ifp,
/* Determine if bridge is VLAN-aware or not */
zif = br_if->info;
assert(zif);
- br = &zif->l2info.br;
- in_param.bridge_vlan_aware = br->vlan_aware;
+ in_param.bridge_vlan_aware = IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(zif);
in_param.vid = 0;
if (in_param.bridge_vlan_aware) {
@@ -906,9 +944,24 @@ struct interface *zebra_evpn_map_to_macvlan(struct interface *br_if,
}
/*
+ * Uninstall MAC hash entry - called upon access VLAN change.
+ */
+static void zebra_evpn_uninstall_mac_hash(struct hash_bucket *bucket,
+ void *ctxt)
+{
+ struct zebra_mac *mac;
+ struct mac_walk_ctx *wctx = ctxt;
+
+ mac = (struct zebra_mac *)bucket->data;
+
+ if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE))
+ zebra_evpn_rem_mac_uninstall(wctx->zevpn, mac, false);
+}
+
+/*
* Install MAC hash entry - called upon access VLAN change.
*/
-void zebra_evpn_install_mac_hash(struct hash_bucket *bucket, void *ctxt)
+static void zebra_evpn_install_mac_hash(struct hash_bucket *bucket, void *ctxt)
{
struct zebra_mac *mac;
struct mac_walk_ctx *wctx = ctxt;
@@ -920,6 +973,44 @@ void zebra_evpn_install_mac_hash(struct hash_bucket *bucket, void *ctxt)
}
/*
+ * Uninstall remote MAC entries for this EVPN.
+ */
+void zebra_evpn_rem_mac_uninstall_all(struct zebra_evpn *zevpn)
+{
+ struct mac_walk_ctx wctx;
+
+ if (!zevpn->mac_table)
+ return;
+
+ memset(&wctx, 0, sizeof(struct mac_walk_ctx));
+ wctx.zevpn = zevpn;
+ wctx.uninstall = 1;
+ wctx.upd_client = 0;
+ wctx.flags = ZEBRA_MAC_REMOTE;
+
+ hash_iterate(zevpn->mac_table, zebra_evpn_uninstall_mac_hash, &wctx);
+}
+
+/*
+ * Install remote MAC entries for this EVPN.
+ */
+void zebra_evpn_rem_mac_install_all(struct zebra_evpn *zevpn)
+{
+ struct mac_walk_ctx wctx;
+
+ if (!zevpn->mac_table)
+ return;
+
+ memset(&wctx, 0, sizeof(struct mac_walk_ctx));
+ wctx.zevpn = zevpn;
+ wctx.uninstall = 0;
+ wctx.upd_client = 0;
+ wctx.flags = ZEBRA_MAC_REMOTE;
+
+ hash_iterate(zevpn->mac_table, zebra_evpn_install_mac_hash, &wctx);
+}
+
+/*
* Read and populate local MACs and neighbors corresponding to this EVPN.
*/
void zebra_evpn_read_mac_neigh(struct zebra_evpn *zevpn, struct interface *ifp)
@@ -928,11 +1019,11 @@ void zebra_evpn_read_mac_neigh(struct zebra_evpn *zevpn, struct interface *ifp)
struct zebra_vrf *zvrf;
struct zebra_if *zif;
struct interface *vlan_if;
- struct zebra_l2info_vxlan *vxl;
+ struct zebra_vxlan_vni *vni;
struct interface *vrr_if;
zif = ifp->info;
- vxl = &zif->l2info.vxl;
+ vni = zebra_vxlan_if_vni_find(zif, zevpn->vni);
zvrf = zebra_vrf_lookup_by_id(zevpn->vrf_id);
if (!zvrf || !zvrf->zns)
return;
@@ -944,8 +1035,13 @@ void zebra_evpn_read_mac_neigh(struct zebra_evpn *zevpn, struct interface *ifp)
ifp->name, ifp->ifindex, zevpn->vni,
zif->brslave_info.bridge_ifindex);
- macfdb_read_for_bridge(zns, ifp, zif->brslave_info.br_if);
- vlan_if = zvni_map_to_svi(vxl->access_vlan, zif->brslave_info.br_if);
+ macfdb_read_for_bridge(zns, ifp, zif->brslave_info.br_if,
+ vni->access_vlan);
+ /* We need to specifically read and retrieve the entry for BUM handling
+ * via multicast, if any.
+ */
+ macfdb_read_mcast_entry_for_vni(zns, ifp, zevpn->vni);
+ vlan_if = zvni_map_to_svi(vni->access_vlan, zif->brslave_info.br_if);
if (vlan_if) {
/* Add SVI MAC */
zebra_evpn_acc_bd_svi_mac_add(vlan_if);
@@ -1518,7 +1614,7 @@ void zebra_evpn_rem_macip_del(vni_t vni, const struct ethaddr *macaddr,
struct interface *ifp = NULL;
struct zebra_if *zif = NULL;
struct zebra_ns *zns;
- struct zebra_l2info_vxlan *vxl;
+ struct zebra_vxlan_vni *vnip;
struct zebra_vrf *zvrf;
char buf1[INET6_ADDRSTRLEN];
@@ -1541,7 +1637,14 @@ void zebra_evpn_rem_macip_del(vni_t vni, const struct ethaddr *macaddr,
return;
}
zns = zebra_ns_lookup(NS_DEFAULT);
- vxl = &zif->l2info.vxl;
+ vnip = zebra_vxlan_if_vni_find(zif, vni);
+ if (!vnip) {
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug(
+ "VNI %u not in interface upon remote MACIP DEL",
+ vni);
+ return;
+ }
mac = zebra_evpn_mac_lookup(zevpn, macaddr);
if (ipa_len)
@@ -1596,7 +1699,7 @@ void zebra_evpn_rem_macip_del(vni_t vni, const struct ethaddr *macaddr,
"%s: MAC %pEA (flags 0x%x) is remote and duplicate, read kernel for local entry",
__func__, macaddr, mac->flags);
macfdb_read_specific_mac(zns, zif->brslave_info.br_if,
- macaddr, vxl->access_vlan);
+ macaddr, vnip->access_vlan);
}
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) {
diff --git a/zebra/zebra_evpn.h b/zebra/zebra_evpn.h
index 2c84d23045..8218b77213 100644
--- a/zebra/zebra_evpn.h
+++ b/zebra/zebra_evpn.h
@@ -33,6 +33,7 @@
#include "zebra/zebra_l2.h"
#include "zebra/interface.h"
+#include "zebra/zebra_vxlan.h"
#ifdef __cplusplus
extern "C" {
@@ -83,6 +84,10 @@ struct zebra_evpn {
uint32_t flags;
#define ZEVPN_READY_FOR_BGP (1 << 0) /* ready to be sent to BGP */
+ /* Corresponding Bridge information */
+ vlanid_t vid;
+ struct interface *bridge_if;
+
/* Flag for advertising gw macip */
uint8_t advertise_gw_macip;
@@ -138,7 +143,7 @@ static inline struct interface *zevpn_map_to_svi(struct zebra_evpn *zevpn)
{
struct interface *ifp;
struct zebra_if *zif = NULL;
- struct zebra_l2info_vxlan zl2_info;
+ struct zebra_vxlan_vni *vni;
ifp = zevpn->vxlan_if;
if (!ifp)
@@ -146,12 +151,15 @@ static inline struct interface *zevpn_map_to_svi(struct zebra_evpn *zevpn)
zif = ifp->info;
if (!zif)
return NULL;
+ vni = zebra_vxlan_if_vni_find(zif, zevpn->vni);
+ if (!vni)
+ return NULL;
/* If down or not mapped to a bridge, we're done. */
if (!if_is_operative(ifp) || !zif->brslave_info.br_if)
return NULL;
- zl2_info = zif->l2info.vxl;
- return zvni_map_to_svi(zl2_info.access_vlan, zif->brslave_info.br_if);
+
+ return zvni_map_to_svi(vni->access_vlan, zif->brslave_info.br_if);
}
int advertise_gw_macip_enabled(struct zebra_evpn *zevpn);
@@ -181,7 +189,8 @@ struct zebra_evpn *zebra_evpn_from_svi(struct interface *ifp,
struct interface *br_if);
struct interface *zebra_evpn_map_to_macvlan(struct interface *br_if,
struct interface *svi_if);
-void zebra_evpn_install_mac_hash(struct hash_bucket *bucket, void *ctxt);
+void zebra_evpn_rem_mac_install_all(struct zebra_evpn *zevpn);
+void zebra_evpn_rem_mac_uninstall_all(struct zebra_evpn *zevpn);
void zebra_evpn_read_mac_neigh(struct zebra_evpn *zevpn, struct interface *ifp);
unsigned int zebra_evpn_hash_keymake(const void *p);
bool zebra_evpn_hash_cmp(const void *p1, const void *p2);
diff --git a/zebra/zebra_evpn_mac.c b/zebra/zebra_evpn_mac.c
index 2c953eef15..801403c11c 100644
--- a/zebra/zebra_evpn_mac.c
+++ b/zebra/zebra_evpn_mac.c
@@ -36,6 +36,8 @@
#include "zebra/zebra_router.h"
#include "zebra/zebra_errors.h"
#include "zebra/zebra_vrf.h"
+#include "zebra/zebra_vxlan.h"
+#include "zebra/zebra_vxlan_if.h"
#include "zebra/zebra_evpn.h"
#include "zebra/zebra_evpn_mh.h"
#include "zebra/zebra_evpn_mac.h"
@@ -198,7 +200,7 @@ int zebra_evpn_rem_mac_install(struct zebra_evpn *zevpn, struct zebra_mac *mac,
bool was_static)
{
const struct zebra_if *zif, *br_zif;
- const struct zebra_l2info_vxlan *vxl;
+ const struct zebra_vxlan_vni *vni;
bool sticky;
enum zebra_dplane_result res;
const struct interface *br_ifp;
@@ -214,7 +216,9 @@ int zebra_evpn_rem_mac_install(struct zebra_evpn *zevpn, struct zebra_mac *mac,
if (br_ifp == NULL)
return -1;
- vxl = &zif->l2info.vxl;
+ vni = zebra_vxlan_if_vni_find(zif, zevpn->vni);
+ if (!vni)
+ return -1;
sticky = !!CHECK_FLAG(mac->flags,
(ZEBRA_MAC_STICKY | ZEBRA_MAC_REMOTE_DEF_GW));
@@ -235,12 +239,12 @@ int zebra_evpn_rem_mac_install(struct zebra_evpn *zevpn, struct zebra_mac *mac,
br_zif = (const struct zebra_if *)(br_ifp->info);
if (IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(br_zif))
- vid = vxl->access_vlan;
+ vid = vni->access_vlan;
else
vid = 0;
res = dplane_rem_mac_add(zevpn->vxlan_if, br_ifp, vid, &mac->macaddr,
- vtep_ip, sticky, nhg_id, was_static);
+ vni->vni, vtep_ip, sticky, nhg_id, was_static);
if (res != ZEBRA_DPLANE_REQUEST_FAILURE)
return 0;
else
@@ -254,7 +258,7 @@ int zebra_evpn_rem_mac_uninstall(struct zebra_evpn *zevpn,
struct zebra_mac *mac, bool force)
{
const struct zebra_if *zif, *br_zif;
- const struct zebra_l2info_vxlan *vxl;
+ struct zebra_vxlan_vni *vni;
struct in_addr vtep_ip;
const struct interface *ifp, *br_ifp;
vlanid_t vid;
@@ -280,19 +284,22 @@ int zebra_evpn_rem_mac_uninstall(struct zebra_evpn *zevpn,
if (br_ifp == NULL)
return -1;
- vxl = &zif->l2info.vxl;
+ vni = zebra_vxlan_if_vni_find(zif, zevpn->vni);
+ if (!vni)
+ return -1;
br_zif = (const struct zebra_if *)br_ifp->info;
if (IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(br_zif))
- vid = vxl->access_vlan;
+ vid = vni->access_vlan;
else
vid = 0;
ifp = zevpn->vxlan_if;
vtep_ip = mac->fwd_info.r_vtep_ip;
- res = dplane_rem_mac_del(ifp, br_ifp, vid, &mac->macaddr, vtep_ip);
+ res = dplane_rem_mac_del(ifp, br_ifp, vid, &mac->macaddr, vni->vni,
+ vtep_ip);
if (res != ZEBRA_DPLANE_REQUEST_FAILURE)
return 0;
else
@@ -327,6 +334,8 @@ static void zebra_evpn_mac_get_access_info(struct zebra_mac *mac,
struct interface **p_ifp,
vlanid_t *vid)
{
+ struct zebra_vxlan_vni *vni;
+
/* if the mac is associated with an ES we must get the access
* info from the ES
*/
@@ -338,7 +347,8 @@ static void zebra_evpn_mac_get_access_info(struct zebra_mac *mac,
/* get the vlan from the EVPN */
if (mac->zevpn->vxlan_if) {
zif = mac->zevpn->vxlan_if->info;
- *vid = zif->l2info.vxl.access_vlan;
+ vni = zebra_vxlan_if_vni_find(zif, mac->zevpn->vni);
+ *vid = vni->access_vlan;
} else {
*vid = 0;
}
diff --git a/zebra/zebra_evpn_mh.c b/zebra/zebra_evpn_mh.c
index 01ea9c5b9c..15def89e97 100644
--- a/zebra/zebra_evpn_mh.c
+++ b/zebra/zebra_evpn_mh.c
@@ -41,12 +41,13 @@
#include "zebra/if_netlink.h"
#include "zebra/zebra_errors.h"
#include "zebra/zebra_l2.h"
+#include "zebra/zebra_l2_bridge_if.h"
#include "zebra/zebra_ns.h"
#include "zebra/zebra_vrf.h"
#include "zebra/zebra_vxlan.h"
+#include "zebra/zebra_vxlan_private.h"
#include "zebra/zebra_evpn.h"
#include "zebra/zebra_evpn_mac.h"
-#include "zebra/zebra_vxlan_private.h"
#include "zebra/zebra_router.h"
#include "zebra/zebra_evpn_mh.h"
#include "zebra/zebra_nhg.h"
@@ -481,6 +482,7 @@ void zebra_evpn_update_all_es(struct zebra_evpn *zevpn)
struct interface *vlan_if;
struct interface *vxlan_if;
struct zebra_if *vxlan_zif;
+ struct zebra_vxlan_vni *vni;
/* the EVPN is now elgible as a base for EVPN-MH */
if (zebra_evpn_send_to_client_ok(zevpn))
@@ -497,11 +499,15 @@ void zebra_evpn_update_all_es(struct zebra_evpn *zevpn)
vxlan_zif = vxlan_if->info;
if (if_is_operative(vxlan_if)
&& vxlan_zif->brslave_info.br_if) {
- vlan_if = zvni_map_to_svi(
- vxlan_zif->l2info.vxl.access_vlan,
- vxlan_zif->brslave_info.br_if);
- if (vlan_if)
- zebra_evpn_acc_bd_svi_mac_add(vlan_if);
+ vni = zebra_vxlan_if_vni_find(vxlan_zif, zevpn->vni);
+ /* VLAN-VNI mappings may not exist */
+ if (vni) {
+ vlan_if = zvni_map_to_svi(
+ vni->access_vlan,
+ vxlan_zif->brslave_info.br_if);
+ if (vlan_if)
+ zebra_evpn_acc_bd_svi_mac_add(vlan_if);
+ }
}
}
}
@@ -520,7 +526,7 @@ static unsigned int zebra_evpn_acc_vl_hash_keymake(const void *p)
{
const struct zebra_evpn_access_bd *acc_bd = p;
- return jhash_1word(acc_bd->vid, 0);
+ return jhash_2words(acc_bd->vid, acc_bd->bridge_ifindex, 0);
}
/* Compare two VLAN based broadcast domains */
@@ -535,16 +541,19 @@ static bool zebra_evpn_acc_vl_cmp(const void *p1, const void *p2)
if (acc_bd1 == NULL || acc_bd2 == NULL)
return false;
- return (acc_bd1->vid == acc_bd2->vid);
+ return ((acc_bd1->vid == acc_bd2->vid) &&
+ (acc_bd1->bridge_ifindex == acc_bd2->bridge_ifindex));
}
/* Lookup VLAN based broadcast domain */
-static struct zebra_evpn_access_bd *zebra_evpn_acc_vl_find(vlanid_t vid)
+struct zebra_evpn_access_bd *zebra_evpn_acc_vl_find(vlanid_t vid,
+ struct interface *br_if)
{
struct zebra_evpn_access_bd *acc_bd;
struct zebra_evpn_access_bd tmp;
tmp.vid = vid;
+ tmp.bridge_ifindex = br_if->ifindex;
acc_bd = hash_lookup(zmh_info->evpn_vlan_table, &tmp);
return acc_bd;
@@ -560,11 +569,13 @@ zebra_evpn_acc_vl_new(vlanid_t vid, struct interface *br_if)
struct interface *vlan_if;
if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
- zlog_debug("access vlan %d add", vid);
+ zlog_debug("access vlan %d bridge %s add", vid, br_if->name);
acc_bd = XCALLOC(MTYPE_ZACC_BD, sizeof(struct zebra_evpn_access_bd));
acc_bd->vid = vid;
+ acc_bd->bridge_ifindex = br_if->ifindex;
+ acc_bd->bridge_zif = (struct zebra_if *)br_if->info;
/* Initialize the mbr list */
acc_bd->mbr_zifs = list_new();
@@ -573,14 +584,12 @@ zebra_evpn_acc_vl_new(vlanid_t vid, struct interface *br_if)
(void)hash_get(zmh_info->evpn_vlan_table, acc_bd, hash_alloc_intern);
/* check if an svi exists for the vlan */
- if (br_if) {
- vlan_if = zvni_map_to_svi(vid, br_if);
- if (vlan_if) {
- if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
- zlog_debug("vlan %d SVI %s set", vid,
- vlan_if->name);
- acc_bd->vlan_zif = vlan_if->info;
- }
+ vlan_if = zvni_map_to_svi(vid, br_if);
+ if (vlan_if) {
+ if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
+ zlog_debug("vlan %d bridge %s SVI %s set", vid,
+ br_if->name, vlan_if->name);
+ acc_bd->vlan_zif = vlan_if->info;
}
return acc_bd;
}
@@ -621,16 +630,32 @@ static void zebra_evpn_acc_bd_free_on_deref(struct zebra_evpn_access_bd *acc_bd)
if (!list_isempty(acc_bd->mbr_zifs) || acc_bd->vxlan_zif)
return;
+ /* Remove this access_bd from bridge hash table */
+ zebra_l2_bridge_if_vlan_access_bd_deref(acc_bd);
+
/* if there are no references free the EVI */
zebra_evpn_acc_vl_free(acc_bd);
}
+static struct zebra_evpn_access_bd *
+zebra_evpn_acc_bd_alloc_on_ref(vlanid_t vid, struct interface *br_if)
+{
+ struct zebra_evpn_access_bd *acc_bd = NULL;
+
+ assert(br_if && br_if->info);
+ acc_bd = zebra_evpn_acc_vl_new(vid, br_if);
+ if (acc_bd)
+ /* Add this access_bd to bridge hash table */
+ zebra_l2_bridge_if_vlan_access_bd_ref(acc_bd);
+
+ return acc_bd;
+}
+
/* called when a SVI is goes up/down */
void zebra_evpn_acc_bd_svi_set(struct zebra_if *vlan_zif,
struct zebra_if *br_zif, bool is_up)
{
struct zebra_evpn_access_bd *acc_bd;
- struct zebra_l2info_bridge *br;
uint16_t vid;
struct zebra_if *tmp_br_zif = br_zif;
@@ -641,20 +666,19 @@ void zebra_evpn_acc_bd_svi_set(struct zebra_if *vlan_zif,
tmp_br_zif = vlan_zif->link->info;
}
- br = &tmp_br_zif->l2info.br;
/* ignore vlan unaware bridges */
- if (!br->vlan_aware)
+ if (!IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(tmp_br_zif))
return;
vid = vlan_zif->l2info.vl.vid;
- acc_bd = zebra_evpn_acc_vl_find(vid);
+ acc_bd = zebra_evpn_acc_vl_find(vid, tmp_br_zif->ifp);
if (!acc_bd)
return;
if (is_up) {
if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
- zlog_debug("vlan %d SVI %s set", vid,
- vlan_zif->ifp->name);
+ zlog_debug("vlan %d bridge %s SVI %s set", vid,
+ tmp_br_zif->ifp->name, vlan_zif->ifp->name);
acc_bd->vlan_zif = vlan_zif;
if (acc_bd->zevpn)
@@ -662,7 +686,8 @@ void zebra_evpn_acc_bd_svi_set(struct zebra_if *vlan_zif,
acc_bd->zevpn);
} else if (acc_bd->vlan_zif) {
if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
- zlog_debug("vlan %d SVI clear", vid);
+ zlog_debug("vlan %d bridge %s SVI clear", vid,
+ tmp_br_zif->ifp->name);
acc_bd->vlan_zif = NULL;
if (acc_bd->zevpn && acc_bd->zevpn->mac_table)
zebra_evpn_mac_svi_del(vlan_zif->ifp, acc_bd->zevpn);
@@ -687,8 +712,9 @@ static void zebra_evpn_acc_bd_evpn_set(struct zebra_evpn_access_bd *acc_bd,
struct listnode *node;
if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
- zlog_debug("access vlan %d l2-vni %u set",
- acc_bd->vid, zevpn ? zevpn->vni : 0);
+ zlog_debug("access vlan %d bridge %s l2-vni %u set",
+ acc_bd->vid, acc_bd->bridge_zif->ifp->name,
+ zevpn ? zevpn->vni : 0);
for (ALL_LIST_ELEMENTS_RO(acc_bd->mbr_zifs, node, zif)) {
if (!zif->es_info.es)
@@ -711,33 +737,44 @@ static void zebra_evpn_acc_bd_evpn_set(struct zebra_evpn_access_bd *acc_bd,
}
/* handle VLAN->VxLAN_IF association */
-void zebra_evpn_vl_vxl_ref(uint16_t vid, struct zebra_if *vxlan_zif)
+void zebra_evpn_vl_vxl_ref(uint16_t vid, vni_t vni_id,
+ struct zebra_if *vxlan_zif)
{
+ vni_t old_vni;
struct zebra_evpn_access_bd *acc_bd;
- struct zebra_if *old_vxlan_zif;
struct zebra_evpn *old_zevpn;
+ struct interface *br_if;
if (!vid)
return;
- acc_bd = zebra_evpn_acc_vl_find(vid);
+ if (!vni_id)
+ return;
+
+ br_if = vxlan_zif->brslave_info.br_if;
+
+ if (!br_if)
+ return;
+
+ acc_bd = zebra_evpn_acc_vl_find(vid, br_if);
if (!acc_bd)
- acc_bd = zebra_evpn_acc_vl_new(vid,
- vxlan_zif->brslave_info.br_if);
+ acc_bd = zebra_evpn_acc_bd_alloc_on_ref(vid, br_if);
- old_vxlan_zif = acc_bd->vxlan_zif;
- acc_bd->vxlan_zif = vxlan_zif;
- if (vxlan_zif == old_vxlan_zif)
+ old_vni = acc_bd->vni;
+
+ if (vni_id == old_vni)
return;
+ acc_bd->vni = vni_id;
+ acc_bd->vxlan_zif = vxlan_zif;
+
old_zevpn = acc_bd->zevpn;
- acc_bd->zevpn = zebra_evpn_lookup(vxlan_zif->l2info.vxl.vni);
+ acc_bd->zevpn = zebra_evpn_lookup(vni_id);
if (acc_bd->zevpn == old_zevpn)
return;
if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
- zlog_debug("access vlan %d vni %u ref",
- acc_bd->vid, vxlan_zif->l2info.vxl.vni);
+ zlog_debug("access vlan %d vni %u ref", acc_bd->vid, vni_id);
if (old_zevpn)
zebra_evpn_acc_bd_evpn_set(acc_bd, NULL, old_zevpn);
@@ -747,30 +784,66 @@ void zebra_evpn_vl_vxl_ref(uint16_t vid, struct zebra_if *vxlan_zif)
}
/* handle VLAN->VxLAN_IF deref */
-void zebra_evpn_vl_vxl_deref(uint16_t vid, struct zebra_if *vxlan_zif)
+void zebra_evpn_vl_vxl_deref(uint16_t vid, vni_t vni_id,
+ struct zebra_if *vxlan_zif)
{
+ struct interface *br_if;
struct zebra_evpn_access_bd *acc_bd;
if (!vid)
return;
- acc_bd = zebra_evpn_acc_vl_find(vid);
+ if (!vni_id)
+ return;
+
+ br_if = vxlan_zif->brslave_info.br_if;
+ if (!br_if)
+ return;
+
+ acc_bd = zebra_evpn_acc_vl_find(vid, br_if);
if (!acc_bd)
return;
/* clear vxlan_if only if it matches */
- if (acc_bd->vxlan_zif != vxlan_zif)
+ if (acc_bd->vni != vni_id)
return;
if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
- zlog_debug("access vlan %d vni %u deref",
- acc_bd->vid, vxlan_zif->l2info.vxl.vni);
+ zlog_debug("access vlan %d bridge %s vni %u deref", acc_bd->vid,
+ br_if->name, vni_id);
if (acc_bd->zevpn)
zebra_evpn_acc_bd_evpn_set(acc_bd, NULL, acc_bd->zevpn);
acc_bd->zevpn = NULL;
acc_bd->vxlan_zif = NULL;
+ acc_bd->vni = 0;
+
+ /* if there are no other references the access_bd can be freed */
+ zebra_evpn_acc_bd_free_on_deref(acc_bd);
+}
+
+/* handle BridgeIf<->AccessBD cleanup */
+void zebra_evpn_access_bd_bridge_cleanup(vlanid_t vid, struct interface *br_if,
+ struct zebra_evpn_access_bd *acc_bd)
+{
+ struct zebra_evpn *zevpn;
+
+ if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
+ zlog_debug("access bd vlan %d bridge %s cleanup", acc_bd->vid,
+ br_if->name);
+
+ zevpn = acc_bd->zevpn;
+ if (zevpn)
+ zebra_evpn_acc_bd_evpn_set(acc_bd, NULL, zevpn);
+
+ /* cleanup resources maintained against the ES */
+ list_delete_all_node(acc_bd->mbr_zifs);
+
+ acc_bd->zevpn = NULL;
+ acc_bd->vxlan_zif = NULL;
+ acc_bd->vni = 0;
+ acc_bd->bridge_zif = NULL;
/* if there are no other references the access_bd can be freed */
zebra_evpn_acc_bd_free_on_deref(acc_bd);
@@ -780,15 +853,23 @@ void zebra_evpn_vl_vxl_deref(uint16_t vid, struct zebra_if *vxlan_zif)
void zebra_evpn_vxl_evpn_set(struct zebra_if *zif, struct zebra_evpn *zevpn,
bool set)
{
- struct zebra_l2info_vxlan *vxl;
+ struct interface *br_if;
+ struct zebra_vxlan_vni *vni;
struct zebra_evpn_access_bd *acc_bd;
if (!zif)
return;
/* locate access_bd associated with the vxlan device */
- vxl = &zif->l2info.vxl;
- acc_bd = zebra_evpn_acc_vl_find(vxl->access_vlan);
+ vni = zebra_vxlan_if_vni_find(zif, zevpn->vni);
+ if (!vni)
+ return;
+
+ br_if = zif->brslave_info.br_if;
+ if (!br_if)
+ return;
+
+ acc_bd = zebra_evpn_acc_vl_find(vni->access_vlan, br_if);
if (!acc_bd)
return;
@@ -810,21 +891,26 @@ void zebra_evpn_vxl_evpn_set(struct zebra_if *zif, struct zebra_evpn *zevpn,
/* handle addition of new VLAN members */
void zebra_evpn_vl_mbr_ref(uint16_t vid, struct zebra_if *zif)
{
+ struct interface *br_if;
struct zebra_evpn_access_bd *acc_bd;
if (!vid)
return;
- acc_bd = zebra_evpn_acc_vl_find(vid);
+ br_if = zif->brslave_info.br_if;
+ if (!br_if)
+ return;
+
+ acc_bd = zebra_evpn_acc_vl_find(vid, br_if);
if (!acc_bd)
- acc_bd = zebra_evpn_acc_vl_new(vid, zif->brslave_info.br_if);
+ acc_bd = zebra_evpn_acc_bd_alloc_on_ref(vid, br_if);
if (listnode_lookup(acc_bd->mbr_zifs, zif))
return;
if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
- zlog_debug("access vlan %d mbr %s ref",
- vid, zif->ifp->name);
+ zlog_debug("access vlan %d bridge %s mbr %s ref", vid,
+ br_if->name, zif->ifp->name);
listnode_add(acc_bd->mbr_zifs, zif);
if (acc_bd->zevpn && zif->es_info.es)
@@ -834,13 +920,18 @@ void zebra_evpn_vl_mbr_ref(uint16_t vid, struct zebra_if *zif)
/* handle deletion of VLAN members */
void zebra_evpn_vl_mbr_deref(uint16_t vid, struct zebra_if *zif)
{
+ struct interface *br_if;
struct zebra_evpn_access_bd *acc_bd;
struct listnode *node;
if (!vid)
return;
- acc_bd = zebra_evpn_acc_vl_find(vid);
+ br_if = zif->brslave_info.br_if;
+ if (!br_if)
+ return;
+
+ acc_bd = zebra_evpn_acc_vl_find(vid, br_if);
if (!acc_bd)
return;
@@ -849,8 +940,8 @@ void zebra_evpn_vl_mbr_deref(uint16_t vid, struct zebra_if *zif)
return;
if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
- zlog_debug("access vlan %d mbr %s deref",
- vid, zif->ifp->name);
+ zlog_debug("access vlan %d bridge %s mbr %s deref", vid,
+ br_if->name, zif->ifp->name);
list_delete_node(acc_bd->mbr_zifs, node);
@@ -917,14 +1008,19 @@ static void zebra_evpn_acc_vl_show_entry_detail(struct vty *vty,
if (json) {
zebra_evpn_acc_vl_json_fill(acc_bd, json, true);
} else {
- vty_out(vty, "VLAN: %u\n", acc_bd->vid);
+ vty_out(vty, "VLAN: %s.%u\n", acc_bd->bridge_zif->ifp->name,
+ acc_bd->vid);
vty_out(vty, " VxLAN Interface: %s\n",
acc_bd->vxlan_zif ?
acc_bd->vxlan_zif->ifp->name : "-");
vty_out(vty, " SVI: %s\n",
acc_bd->vlan_zif ? acc_bd->vlan_zif->ifp->name : "-");
- vty_out(vty, " L2-VNI: %d\n",
- acc_bd->zevpn ? acc_bd->zevpn->vni : 0);
+ if (acc_bd->zevpn)
+ vty_out(vty, " L2-VNI: %d\n", acc_bd->zevpn->vni);
+ else {
+ vty_out(vty, " L2-VNI: 0\n");
+ vty_out(vty, " L3-VNI: %d\n", acc_bd->vni);
+ }
vty_out(vty, " Member Count: %d\n",
listcount(acc_bd->mbr_zifs));
vty_out(vty, " Members: \n");
@@ -940,7 +1036,8 @@ static void zebra_evpn_acc_vl_show_entry(struct vty *vty,
if (json) {
zebra_evpn_acc_vl_json_fill(acc_bd, json, false);
} else {
- vty_out(vty, "%-5u %-15s %-8d %-15s %u\n", acc_bd->vid,
+ vty_out(vty, "%-5s.%-5u %-15s %-8d %-15s %u\n",
+ acc_bd->bridge_zif->ifp->name, acc_bd->vid,
acc_bd->vlan_zif ? acc_bd->vlan_zif->ifp->name : "-",
acc_bd->zevpn ? acc_bd->zevpn->vni : 0,
acc_bd->vxlan_zif ? acc_bd->vxlan_zif->ifp->name : "-",
@@ -978,7 +1075,7 @@ void zebra_evpn_acc_vl_show(struct vty *vty, bool uj)
wctx.detail = false;
if (!uj)
- vty_out(vty, "%-5s %-15s %-8s %-15s %s\n", "VLAN", "SVI",
+ vty_out(vty, "%-12s %-15s %-8s %-15s %s\n", "VLAN", "SVI",
"L2-VNI", "VXLAN-IF", "# Members");
hash_iterate(zmh_info->evpn_vlan_table, zebra_evpn_acc_vl_show_hash,
@@ -1007,7 +1104,8 @@ void zebra_evpn_acc_vl_show_detail(struct vty *vty, bool uj)
vty_json(vty, json_array);
}
-void zebra_evpn_acc_vl_show_vid(struct vty *vty, bool uj, vlanid_t vid)
+void zebra_evpn_acc_vl_show_vid(struct vty *vty, bool uj, vlanid_t vid,
+ struct interface *br_if)
{
json_object *json = NULL;
struct zebra_evpn_access_bd *acc_bd;
@@ -1015,12 +1113,13 @@ void zebra_evpn_acc_vl_show_vid(struct vty *vty, bool uj, vlanid_t vid)
if (uj)
json = json_object_new_object();
- acc_bd = zebra_evpn_acc_vl_find(vid);
+ acc_bd = zebra_evpn_acc_vl_find(vid, br_if);
if (acc_bd) {
zebra_evpn_acc_vl_show_entry_detail(vty, acc_bd, json);
} else {
if (!json)
- vty_out(vty, "VLAN %u not present\n", vid);
+ vty_out(vty, "VLAN %s.%u not present\n", br_if->name,
+ vid);
}
if (uj)
@@ -1977,7 +2076,7 @@ static void zebra_evpn_es_setup_evis(struct zebra_evpn_es *es)
return;
bf_for_each_set_bit(zif->vlan_bitmap, vid, IF_VLAN_BITMAP_MAX) {
- acc_bd = zebra_evpn_acc_vl_find(vid);
+ acc_bd = zebra_evpn_acc_vl_find(vid, zif->brslave_info.br_if);
if (acc_bd->zevpn)
zebra_evpn_local_es_evi_add(es, acc_bd->zevpn);
}
@@ -1986,9 +2085,10 @@ static void zebra_evpn_es_setup_evis(struct zebra_evpn_es *es)
static void zebra_evpn_flush_local_mac(struct zebra_mac *mac,
struct interface *ifp)
{
+ vlanid_t vid;
struct zebra_if *zif;
struct interface *br_ifp;
- vlanid_t vid;
+ struct zebra_vxlan_vni *vni;
zif = ifp->info;
br_ifp = zif->brslave_info.br_if;
@@ -1997,7 +2097,8 @@ static void zebra_evpn_flush_local_mac(struct zebra_mac *mac,
if (mac->zevpn->vxlan_if) {
zif = mac->zevpn->vxlan_if->info;
- vid = zif->l2info.vxl.access_vlan;
+ vni = zebra_vxlan_if_vni_find(zif, mac->zevpn->vni);
+ vid = vni->access_vlan;
} else {
vid = 0;
}
diff --git a/zebra/zebra_evpn_mh.h b/zebra/zebra_evpn_mh.h
index 037648311c..12a8569504 100644
--- a/zebra/zebra_evpn_mh.h
+++ b/zebra/zebra_evpn_mh.h
@@ -179,6 +179,10 @@ struct zebra_evpn_es_vtep {
struct zebra_evpn_access_bd {
vlanid_t vid;
+ ifindex_t bridge_ifindex;
+ struct zebra_if *bridge_zif; /* associated bridge */
+
+ vni_t vni; /* vni associated with the vxlan device */
struct zebra_if *vxlan_zif; /* vxlan device */
/* list of members associated with the BD i.e. (potential) ESs */
struct list *mbr_zifs;
@@ -319,8 +323,10 @@ extern void zebra_evpn_vxl_evpn_set(struct zebra_if *zif,
struct zebra_evpn *zevpn, bool set);
extern void zebra_evpn_es_set_base_evpn(struct zebra_evpn *zevpn);
extern void zebra_evpn_es_clear_base_evpn(struct zebra_evpn *zevpn);
-extern void zebra_evpn_vl_vxl_ref(uint16_t vid, struct zebra_if *vxlan_zif);
-extern void zebra_evpn_vl_vxl_deref(uint16_t vid, struct zebra_if *vxlan_zif);
+extern void zebra_evpn_vl_vxl_ref(uint16_t vid, vni_t vni_id,
+ struct zebra_if *vxlan_zif);
+extern void zebra_evpn_vl_vxl_deref(uint16_t vid, vni_t vni_id,
+ struct zebra_if *vxlan_zif);
extern void zebra_evpn_vl_mbr_ref(uint16_t vid, struct zebra_if *zif);
extern void zebra_evpn_vl_mbr_deref(uint16_t vid, struct zebra_if *zif);
extern void zebra_evpn_es_send_all_to_client(bool add);
@@ -345,9 +351,12 @@ extern void zebra_evpn_interface_init(void);
extern int zebra_evpn_mh_if_write(struct vty *vty, struct interface *ifp);
extern void zebra_evpn_acc_vl_show(struct vty *vty, bool uj);
extern void zebra_evpn_acc_vl_show_detail(struct vty *vty, bool uj);
-extern void zebra_evpn_acc_vl_show_vid(struct vty *vty, bool uj, vlanid_t vid);
extern void zebra_evpn_if_es_print(struct vty *vty, json_object *json,
struct zebra_if *zif);
+extern struct zebra_evpn_access_bd *
+zebra_evpn_acc_vl_find(vlanid_t vid, struct interface *br_if);
+extern void zebra_evpn_acc_vl_show_vid(struct vty *vty, bool uj, vlanid_t vid,
+ struct interface *br_if);
extern void zebra_evpn_es_cleanup(void);
extern int zebra_evpn_mh_mac_holdtime_update(struct vty *vty,
uint32_t duration, bool set_default);
@@ -373,6 +382,9 @@ extern void zebra_evpn_l2_nh_show(struct vty *vty, bool uj);
extern void zebra_evpn_acc_bd_svi_set(struct zebra_if *vlan_zif,
struct zebra_if *br_zif, bool is_up);
extern void zebra_evpn_acc_bd_svi_mac_add(struct interface *vlan_if);
+extern void
+zebra_evpn_access_bd_bridge_cleanup(vlanid_t vid, struct interface *br_if,
+ struct zebra_evpn_access_bd *acc_bd);
extern void zebra_evpn_es_bypass_update(struct zebra_evpn_es *es,
struct interface *ifp, bool bypass);
extern void zebra_evpn_proc_remote_nh(ZAPI_HANDLER_ARGS);
diff --git a/zebra/zebra_evpn_neigh.c b/zebra/zebra_evpn_neigh.c
index 684720bb4d..4c7f393fa1 100644
--- a/zebra/zebra_evpn_neigh.c
+++ b/zebra/zebra_evpn_neigh.c
@@ -36,6 +36,8 @@
#include "zebra/rt.h"
#include "zebra/zebra_errors.h"
#include "zebra/zebra_vrf.h"
+#include "zebra/zebra_vxlan.h"
+#include "zebra/zebra_vxlan_if.h"
#include "zebra/zebra_evpn.h"
#include "zebra/zebra_evpn_mh.h"
#include "zebra/zebra_evpn_neigh.h"
diff --git a/zebra/zebra_evpn_neigh.h b/zebra/zebra_evpn_neigh.h
index 9271817440..6119cb8e72 100644
--- a/zebra/zebra_evpn_neigh.h
+++ b/zebra/zebra_evpn_neigh.h
@@ -63,6 +63,9 @@ struct zebra_neigh {
struct zebra_evpn *zevpn;
+ /* Refcnt - Only used by SVD neighs currently */
+ uint32_t refcnt;
+
uint32_t flags;
#define ZEBRA_NEIGH_LOCAL 0x01
#define ZEBRA_NEIGH_REMOTE 0x02
diff --git a/zebra/zebra_evpn_vxlan.h b/zebra/zebra_evpn_vxlan.h
index 3884a1e7ea..71df08a7a7 100644
--- a/zebra/zebra_evpn_vxlan.h
+++ b/zebra/zebra_evpn_vxlan.h
@@ -69,3 +69,33 @@ static inline void zevpn_vxlan_if_set(struct zebra_evpn *zevpn,
zebra_evpn_vxl_evpn_set(zif, zevpn, set);
}
+
+/* EVPN<=>Bridge interface association */
+static inline void zevpn_bridge_if_set(struct zebra_evpn *zevpn,
+ struct interface *ifp, bool set)
+{
+ if (set) {
+ if (zevpn->bridge_if == ifp)
+ return;
+ zevpn->bridge_if = ifp;
+ } else {
+ if (!zevpn->bridge_if)
+ return;
+ zevpn->bridge_if = NULL;
+ }
+}
+
+/* EVPN<=>Bridge interface association */
+static inline void zl3vni_bridge_if_set(struct zebra_l3vni *zl3vni,
+ struct interface *ifp, bool set)
+{
+ if (set) {
+ if (zl3vni->bridge_if == ifp)
+ return;
+ zl3vni->bridge_if = ifp;
+ } else {
+ if (!zl3vni->bridge_if)
+ return;
+ zl3vni->bridge_if = NULL;
+ }
+}
diff --git a/zebra/zebra_l2.c b/zebra/zebra_l2.c
index 8a9f3dffe3..c5d4c58852 100644
--- a/zebra/zebra_l2.c
+++ b/zebra/zebra_l2.c
@@ -42,7 +42,9 @@
#include "zebra/rt_netlink.h"
#include "zebra/interface.h"
#include "zebra/zebra_l2.h"
+#include "zebra/zebra_l2_bridge_if.h"
#include "zebra/zebra_vxlan.h"
+#include "zebra/zebra_vxlan_if.h"
#include "zebra/zebra_evpn_mh.h"
/* definitions */
@@ -262,12 +264,14 @@ void zebra_l2_bridge_add_update(struct interface *ifp,
int add)
{
struct zebra_if *zif;
+ struct zebra_l2_bridge_if *br;
zif = ifp->info;
assert(zif);
- /* Copy over the L2 information. */
- memcpy(&zif->l2info.br, bridge_info, sizeof(*bridge_info));
+ br = BRIDGE_FROM_ZEBRA_IF(zif);
+ br->vlan_aware = bridge_info->bridge.vlan_aware;
+ zebra_l2_bridge_if_add(ifp);
/* Link all slaves to this bridge */
map_slaves_to_bridge(ifp, 1, false, ZEBRA_BRIDGE_NO_ACTION);
@@ -278,6 +282,8 @@ void zebra_l2_bridge_add_update(struct interface *ifp,
*/
void zebra_l2_bridge_del(struct interface *ifp)
{
+ zebra_l2_bridge_if_del(ifp);
+
/* Unlink all slaves to this bridge */
map_slaves_to_bridge(ifp, 0, false, ZEBRA_BRIDGE_NO_ACTION);
}
@@ -341,34 +347,40 @@ void zebra_l2_vxlanif_add_update(struct interface *ifp,
struct zebra_l2info_vxlan *vxlan_info, int add)
{
struct zebra_if *zif;
- struct in_addr old_vtep_ip;
uint16_t chgflags = 0;
+ struct zebra_vxlan_if_update_ctx ctx;
zif = ifp->info;
assert(zif);
if (add) {
memcpy(&zif->l2info.vxl, vxlan_info, sizeof(*vxlan_info));
- zebra_evpn_vl_vxl_ref(zif->l2info.vxl.access_vlan, zif);
zebra_vxlan_if_add(ifp);
return;
}
- old_vtep_ip = zif->l2info.vxl.vtep_ip;
+ memset(&ctx, 0, sizeof(ctx));
+ ctx.old_vtep_ip = zif->l2info.vxl.vtep_ip;
- if (!IPV4_ADDR_SAME(&old_vtep_ip, &vxlan_info->vtep_ip)) {
+ if (!IPV4_ADDR_SAME(&ctx.old_vtep_ip, &vxlan_info->vtep_ip)) {
chgflags |= ZEBRA_VXLIF_LOCAL_IP_CHANGE;
zif->l2info.vxl.vtep_ip = vxlan_info->vtep_ip;
}
- if (!IPV4_ADDR_SAME(&zif->l2info.vxl.mcast_grp,
- &vxlan_info->mcast_grp)) {
- chgflags |= ZEBRA_VXLIF_MCAST_GRP_CHANGE;
- zif->l2info.vxl.mcast_grp = vxlan_info->mcast_grp;
+ if (IS_ZEBRA_VXLAN_IF_VNI(zif)) {
+ ctx.old_vni = vxlan_info->vni_info.vni;
+ if (!IPV4_ADDR_SAME(&zif->l2info.vxl.vni_info.vni.mcast_grp,
+ &vxlan_info->vni_info.vni.mcast_grp)) {
+ chgflags |= ZEBRA_VXLIF_MCAST_GRP_CHANGE;
+ zif->l2info.vxl.vni_info.vni.mcast_grp =
+ vxlan_info->vni_info.vni.mcast_grp;
+ }
}
- if (chgflags)
- zebra_vxlan_if_update(ifp, chgflags);
+ if (chgflags) {
+ ctx.chgflags = chgflags;
+ zebra_vxlan_if_update(ifp, &ctx);
+ }
}
/*
@@ -379,19 +391,30 @@ void zebra_l2_vxlanif_update_access_vlan(struct interface *ifp,
{
struct zebra_if *zif;
vlanid_t old_access_vlan;
+ struct zebra_vxlan_vni *vni;
+ struct zebra_vxlan_if_update_ctx ctx;
+
zif = ifp->info;
assert(zif);
- old_access_vlan = zif->l2info.vxl.access_vlan;
+ /* This would be called only in non svd case */
+ assert(IS_ZEBRA_VXLAN_IF_VNI(zif));
+
+ old_access_vlan = zif->l2info.vxl.vni_info.vni.access_vlan;
+ ;
if (old_access_vlan == access_vlan)
return;
- zif->l2info.vxl.access_vlan = access_vlan;
+ memset(&ctx, 0, sizeof(ctx));
+ vni = zebra_vxlan_if_vni_find(zif, 0);
+ ctx.old_vni = *vni;
+ ctx.chgflags = ZEBRA_VXLIF_VLAN_CHANGE;
+ vni->access_vlan = access_vlan;
- zebra_evpn_vl_vxl_deref(old_access_vlan, zif);
- zebra_evpn_vl_vxl_ref(zif->l2info.vxl.access_vlan, zif);
- zebra_vxlan_if_update(ifp, ZEBRA_VXLIF_VLAN_CHANGE);
+ zebra_evpn_vl_vxl_deref(old_access_vlan, vni->vni, zif);
+ zebra_evpn_vl_vxl_ref(access_vlan, vni->vni, zif);
+ zebra_vxlan_if_update(ifp, &ctx);
}
/*
@@ -404,7 +427,6 @@ void zebra_l2_vxlanif_del(struct interface *ifp)
zif = ifp->info;
assert(zif);
- zebra_evpn_vl_vxl_deref(zif->l2info.vxl.access_vlan, zif);
zebra_vxlan_if_del(ifp);
}
@@ -421,6 +443,9 @@ void zebra_l2if_update_bridge_slave(struct interface *ifp,
ifindex_t old_bridge_ifindex;
ns_id_t old_ns_id;
struct zebra_vrf *zvrf;
+ struct zebra_vxlan_if_update_ctx ctx;
+
+ memset(&ctx, 0, sizeof(ctx));
zif = ifp->info;
assert(zif);
@@ -431,11 +456,14 @@ void zebra_l2if_update_bridge_slave(struct interface *ifp,
if (zif->zif_type == ZEBRA_IF_VXLAN
&& chgflags != ZEBRA_BRIDGE_NO_ACTION) {
- if (chgflags & ZEBRA_BRIDGE_MASTER_MAC_CHANGE)
- zebra_vxlan_if_update(ifp,
- ZEBRA_VXLIF_MASTER_MAC_CHANGE);
- if (chgflags & ZEBRA_BRIDGE_MASTER_UP)
- zebra_vxlan_if_update(ifp, ZEBRA_VXLIF_MASTER_CHANGE);
+ if (chgflags & ZEBRA_BRIDGE_MASTER_MAC_CHANGE) {
+ ctx.chgflags = ZEBRA_VXLIF_MASTER_MAC_CHANGE;
+ zebra_vxlan_if_update(ifp, &ctx);
+ }
+ if (chgflags & ZEBRA_BRIDGE_MASTER_UP) {
+ ctx.chgflags = ZEBRA_VXLIF_MASTER_CHANGE;
+ zebra_vxlan_if_update(ifp, &ctx);
+ }
}
old_bridge_ifindex = zif->brslave_info.bridge_ifindex;
old_ns_id = zif->brslave_info.ns_id;
@@ -443,6 +471,9 @@ void zebra_l2if_update_bridge_slave(struct interface *ifp,
old_ns_id == zif->brslave_info.ns_id)
return;
+ ctx.chgflags = ZEBRA_VXLIF_MASTER_CHANGE;
+
+
zif->brslave_info.ns_id = ns_id;
zif->brslave_info.bridge_ifindex = bridge_ifindex;
/* Set up or remove link with master */
@@ -450,7 +481,7 @@ void zebra_l2if_update_bridge_slave(struct interface *ifp,
zebra_l2_map_slave_to_bridge(&zif->brslave_info, zvrf->zns);
/* In the case of VxLAN, invoke the handler for EVPN. */
if (zif->zif_type == ZEBRA_IF_VXLAN)
- zebra_vxlan_if_update(ifp, ZEBRA_VXLIF_MASTER_CHANGE);
+ zebra_vxlan_if_update(ifp, &ctx);
if (zif->es_info.es)
zebra_evpn_es_local_br_port_update(zif);
} else if (old_bridge_ifindex != IFINDEX_INTERNAL) {
@@ -460,7 +491,7 @@ void zebra_l2if_update_bridge_slave(struct interface *ifp,
* to unmapping the interface from the bridge.
*/
if (zif->zif_type == ZEBRA_IF_VXLAN)
- zebra_vxlan_if_update(ifp, ZEBRA_VXLIF_MASTER_CHANGE);
+ zebra_vxlan_if_update(ifp, &ctx);
if (zif->es_info.es)
zebra_evpn_es_local_br_port_update(zif);
zebra_l2_unmap_slave_from_bridge(&zif->brslave_info);
diff --git a/zebra/zebra_l2.h b/zebra/zebra_l2.h
index 1c3e98158d..e1ce13b163 100644
--- a/zebra/zebra_l2.h
+++ b/zebra/zebra_l2.h
@@ -49,9 +49,30 @@ struct zebra_l2info_bond {
struct list *mbr_zifs; /* slaves using this bond as a master */
};
+struct zebra_l2_bridge_vlan {
+ vlanid_t vid;
+ struct zebra_evpn_access_bd *access_bd;
+};
+
+struct zebra_l2_bridge_if_ctx {
+ /* input */
+ struct zebra_if *zif;
+ int (*func)(struct zebra_if *zif, struct zebra_l2_bridge_vlan *vlan,
+ void *arg);
+
+ /* input-output */
+ void *arg;
+};
+
+struct zebra_l2_bridge_if {
+ uint8_t vlan_aware;
+ struct zebra_if *br_zif;
+ struct hash *vlan_table;
+};
+
/* zebra L2 interface information - bridge interface */
struct zebra_l2info_bridge {
- uint8_t vlan_aware; /* VLAN-aware bridge? */
+ struct zebra_l2_bridge_if bridge;
};
/* zebra L2 interface information - VLAN interface */
@@ -71,12 +92,52 @@ struct zebra_l2info_gre {
ns_id_t link_nsid;
};
+struct zebra_vxlan_vni {
+ vni_t vni; /* VNI */
+ vlanid_t access_vlan; /* Access VLAN - for VLAN-aware bridge. */
+ struct in_addr mcast_grp;
+};
+
+enum {
+ ZEBRA_VXLAN_IF_VNI = 0, /* per vni vxlan if */
+ ZEBRA_VXLAN_IF_SVD /* single vxlan device */
+};
+
+struct zebra_vxlan_if_vlan_ctx {
+ vlanid_t vid;
+ struct zebra_vxlan_vni *vni;
+};
+
+struct zebra_vxlan_if_update_ctx {
+ uint16_t chgflags;
+ struct in_addr old_vtep_ip;
+ struct zebra_vxlan_vni old_vni;
+ struct hash *old_vni_table;
+};
+
+struct zebra_vxlan_if_ctx {
+ /* input */
+ struct zebra_if *zif;
+ int (*func)(struct zebra_if *zif, struct zebra_vxlan_vni *vni,
+ void *arg);
+
+ /* input-output */
+ void *arg;
+};
+
+struct zebra_vxlan_vni_info {
+ int iftype;
+ union {
+ struct zebra_vxlan_vni vni; /* per vni vxlan device vni info */
+ struct hash
+ *vni_table; /* table of vni's assocated with this if */
+ };
+};
+
/* zebra L2 interface information - VXLAN interface */
struct zebra_l2info_vxlan {
- vni_t vni; /* VNI */
+ struct zebra_vxlan_vni_info vni_info;
struct in_addr vtep_ip; /* Local tunnel IP */
- vlanid_t access_vlan; /* Access VLAN - for VLAN-aware bridge. */
- struct in_addr mcast_grp;
ifindex_t ifindex_link; /* Interface index of interface
* linked with VXLAN
*/
@@ -99,10 +160,16 @@ union zebra_l2if_info {
* IOW, the macro VNI_FROM_ZEBRA_IF() will assume the interface is
* of type ZEBRA_IF_VXLAN.
*/
-#define VNI_FROM_ZEBRA_IF(zif) (zif)->l2info.vxl.vni
+#define VNI_INFO_FROM_ZEBRA_IF(zif) (&((zif)->l2info.vxl.vni_info))
+#define IS_ZEBRA_VXLAN_IF_SVD(zif) \
+ ((zif)->l2info.vxl.vni_info.iftype == ZEBRA_VXLAN_IF_SVD)
+#define IS_ZEBRA_VXLAN_IF_VNI(zif) \
+ ((zif)->l2info.vxl.vni_info.iftype == ZEBRA_VXLAN_IF_VNI)
#define VLAN_ID_FROM_ZEBRA_IF(zif) (zif)->l2info.vl.vid
-#define IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(zif) ((zif)->l2info.br.vlan_aware == 1)
+#define BRIDGE_FROM_ZEBRA_IF(zif) (&((zif)->l2info.br.bridge))
+#define IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(zif) \
+ ((zif)->l2info.br.bridge.vlan_aware == 1)
extern void zebra_l2_map_slave_to_bridge(struct zebra_l2info_brslave *br_slave,
struct zebra_ns *zns);
diff --git a/zebra/zebra_l2_bridge_if.c b/zebra/zebra_l2_bridge_if.c
new file mode 100644
index 0000000000..6574899927
--- /dev/null
+++ b/zebra/zebra_l2_bridge_if.c
@@ -0,0 +1,383 @@
+/*
+ * Zebra L2 bridge interface handling
+ *
+ * Copyright (C) 2021 Cumulus Networks, Inc.
+ * Sharath Ramamurthy
+ *
+ * This file is part of FRR.
+ *
+ * FRR is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * FRR is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#include <zebra.h>
+
+#include "hash.h"
+#include "if.h"
+#include "jhash.h"
+#include "linklist.h"
+#include "log.h"
+#include "memory.h"
+#include "prefix.h"
+#include "stream.h"
+#include "table.h"
+#include "vlan.h"
+#include "vxlan.h"
+#ifdef GNU_LINUX
+#include <linux/neighbour.h>
+#endif
+
+#include "zebra/zebra_router.h"
+#include "zebra/debug.h"
+#include "zebra/interface.h"
+#include "zebra/rib.h"
+#include "zebra/rt.h"
+#include "zebra/rt_netlink.h"
+#include "zebra/zebra_errors.h"
+#include "zebra/zebra_l2.h"
+#include "zebra/zebra_l2_bridge_if.h"
+#include "zebra/zebra_ns.h"
+#include "zebra/zebra_vrf.h"
+#include "zebra/zebra_vxlan.h"
+#include "zebra/zebra_vxlan_if.h"
+#include "zebra/zebra_evpn.h"
+#include "zebra/zebra_evpn_mac.h"
+#include "zebra/zebra_evpn_neigh.h"
+#include "zebra/zebra_vxlan_private.h"
+#include "zebra/zebra_evpn_mh.h"
+#include "zebra/zebra_evpn_vxlan.h"
+#include "zebra/zebra_router.h"
+
+static unsigned int zebra_l2_bridge_vlan_hash_keymake(const void *p)
+{
+ const struct zebra_l2_bridge_vlan *bvlan;
+
+ bvlan = (const struct zebra_l2_bridge_vlan *)p;
+ return jhash(&bvlan->vid, sizeof(bvlan->vid), 0);
+}
+
+static bool zebra_l2_bridge_vlan_hash_cmp(const void *p1, const void *p2)
+{
+ const struct zebra_l2_bridge_vlan *bv1;
+ const struct zebra_l2_bridge_vlan *bv2;
+
+ bv1 = (const struct zebra_l2_bridge_vlan *)p1;
+ bv2 = (const struct zebra_l2_bridge_vlan *)p2;
+
+ return (bv1->vid == bv2->vid);
+}
+
+static int zebra_l2_bridge_if_vlan_walk_callback(struct hash_bucket *bucket,
+ void *ctxt)
+{
+ int ret;
+ struct zebra_l2_bridge_vlan *bvlan;
+ struct zebra_l2_bridge_if_ctx *ctx;
+
+ bvlan = (struct zebra_l2_bridge_vlan *)bucket->data;
+ ctx = (struct zebra_l2_bridge_if_ctx *)ctxt;
+
+ ret = ctx->func(ctx->zif, bvlan, ctx->arg);
+ return ret;
+}
+
+static void zebra_l2_bridge_if_vlan_iterate_callback(struct hash_bucket *bucket,
+ void *ctxt)
+{
+ struct zebra_l2_bridge_vlan *bvlan;
+ struct zebra_l2_bridge_if_ctx *ctx;
+
+ bvlan = (struct zebra_l2_bridge_vlan *)bucket->data;
+ ctx = (struct zebra_l2_bridge_if_ctx *)ctxt;
+
+ ctx->func(ctx->zif, bvlan, ctx->arg);
+}
+
+static int zebra_l2_bridge_if_vlan_clean(struct zebra_if *zif,
+ struct zebra_l2_bridge_vlan *bvlan,
+ void *ctxt)
+{
+ struct zebra_evpn_access_bd *acc_bd;
+
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug("access vlan %d bridge %s cleanup", bvlan->vid,
+ zif->ifp->name);
+
+ acc_bd = zebra_evpn_acc_vl_find(bvlan->vid, zif->ifp);
+ if (acc_bd)
+ zebra_evpn_access_bd_bridge_cleanup(bvlan->vid, zif->ifp,
+ acc_bd);
+
+ bvlan->access_bd = NULL;
+ return 0;
+}
+
+static void zebra_l2_bridge_vlan_free(void *arg)
+{
+ struct zebra_l2_bridge_vlan *bvl;
+
+ bvl = (struct zebra_l2_bridge_vlan *)arg;
+ XFREE(MTYPE_TMP, bvl);
+}
+
+static void *zebra_l2_bridge_vlan_alloc(void *p)
+{
+ struct zebra_l2_bridge_vlan *bvlan;
+ const struct zebra_l2_bridge_vlan *bvl;
+
+ bvl = (const struct zebra_l2_bridge_vlan *)p;
+ bvlan = XCALLOC(MTYPE_TMP, sizeof(*bvlan));
+ bvlan->vid = bvl->vid;
+ bvlan->access_bd = bvl->access_bd;
+
+ return (void *)bvlan;
+}
+
+static void zebra_l2_bridge_vlan_table_destroy(struct hash *vlan_table)
+{
+ if (vlan_table) {
+ hash_clean(vlan_table, zebra_l2_bridge_vlan_free);
+ hash_free(vlan_table);
+ }
+}
+
+static struct hash *zebra_l2_bridge_vlan_table_create(void)
+{
+ return hash_create(zebra_l2_bridge_vlan_hash_keymake,
+ zebra_l2_bridge_vlan_hash_cmp,
+ "Zebra L2 Bridge Vlan Table");
+}
+
+static void zebra_l2_bridge_if_vlan_table_destroy(struct zebra_if *zif)
+{
+ struct zebra_l2_bridge_if *br;
+
+ br = BRIDGE_FROM_ZEBRA_IF(zif);
+ zebra_l2_bridge_if_vlan_iterate(zif, zebra_l2_bridge_if_vlan_clean,
+ NULL);
+ zebra_l2_bridge_vlan_table_destroy(br->vlan_table);
+ br->vlan_table = NULL;
+}
+
+static int zebra_l2_bridge_if_vlan_table_create(struct zebra_if *zif)
+{
+ struct zebra_l2_bridge_if *br;
+
+ br = BRIDGE_FROM_ZEBRA_IF(zif);
+ if (!br->vlan_table) {
+ br->vlan_table = zebra_l2_bridge_vlan_table_create();
+ if (!br->vlan_table)
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static int zebra_l2_bridge_if_vlan_del(struct interface *ifp, vlanid_t vid)
+{
+ struct zebra_if *zif;
+ struct zebra_l2_bridge_if *br;
+ struct zebra_l2_bridge_vlan bvl;
+ struct zebra_l2_bridge_vlan *bvlan;
+
+ zif = (struct zebra_if *)ifp->info;
+ memset(&bvl, 0, sizeof(bvl));
+ bvl.vid = vid;
+
+ br = BRIDGE_FROM_ZEBRA_IF(zif);
+ bvlan = hash_release(br->vlan_table, &bvl);
+
+ if (bvlan)
+ zebra_l2_bridge_vlan_free(bvlan);
+
+ return 0;
+}
+
+static int zebra_l2_bridge_if_vlan_update(struct interface *ifp,
+ struct zebra_l2_bridge_vlan *bvl,
+ int chgflags)
+{
+ struct zebra_if *zif;
+ struct zebra_l2_bridge_vlan *bvlan;
+
+ zif = (struct zebra_if *)ifp->info;
+ bvlan = zebra_l2_bridge_if_vlan_find(zif, bvl->vid);
+
+ if (chgflags & ZEBRA_BRIDGEIF_ACCESS_BD_CHANGE)
+ bvlan->access_bd = bvl->access_bd;
+
+ if (!bvlan->access_bd)
+ return zebra_l2_bridge_if_vlan_del(ifp, bvl->vid);
+
+ return 0;
+}
+
+static int zebra_l2_bridge_if_vlan_add(struct interface *ifp,
+ struct zebra_l2_bridge_vlan *bvlan)
+{
+ struct zebra_if *zif;
+ struct zebra_l2_bridge_if *br;
+
+ zif = (struct zebra_if *)ifp->info;
+ br = BRIDGE_FROM_ZEBRA_IF(zif);
+ hash_get(br->vlan_table, (void *)bvlan, zebra_l2_bridge_vlan_alloc);
+
+ return 0;
+}
+
+struct zebra_l2_bridge_vlan *
+zebra_l2_bridge_if_vlan_find(const struct zebra_if *zif, vlanid_t vid)
+{
+ const struct zebra_l2_bridge_if *br;
+ struct zebra_l2_bridge_vlan *bvl;
+ struct zebra_l2_bridge_vlan bvlan;
+
+ br = BRIDGE_FROM_ZEBRA_IF(zif);
+ memset(&bvlan, 0, sizeof(bvlan));
+ bvlan.vid = vid;
+ bvl = (struct zebra_l2_bridge_vlan *)hash_lookup(br->vlan_table,
+ (void *)&bvlan);
+
+ /* TODO: For debugging. Remove later */
+ if (bvl)
+ assert(bvl->vid == vid);
+
+ return bvl;
+}
+
+vni_t zebra_l2_bridge_if_vni_find(const struct zebra_if *zif, vlanid_t vid)
+{
+ vni_t vni_id = 0;
+ struct zebra_l2_bridge_vlan *bvlan;
+
+ bvlan = zebra_l2_bridge_if_vlan_find(zif, vid);
+ if (bvlan && bvlan->access_bd && bvlan->access_bd->vni)
+ vni_id = bvlan->access_bd->vni;
+
+ return vni_id;
+}
+
+void zebra_l2_bridge_if_vlan_iterate(struct zebra_if *zif,
+ int (*func)(struct zebra_if *zif,
+ struct zebra_l2_bridge_vlan *,
+ void *),
+ void *arg)
+{
+ struct zebra_l2_bridge_if *br;
+ struct zebra_l2_bridge_if_ctx ctx;
+
+ br = BRIDGE_FROM_ZEBRA_IF(zif);
+ memset(&ctx, 0, sizeof(ctx));
+ ctx.zif = zif;
+ ctx.func = func;
+ ctx.arg = arg;
+ hash_iterate(br->vlan_table, zebra_l2_bridge_if_vlan_iterate_callback,
+ &ctx);
+}
+
+void zebra_l2_bridge_if_vlan_walk(struct zebra_if *zif,
+ int (*func)(struct zebra_if *zif,
+ struct zebra_l2_bridge_vlan *,
+ void *),
+ void *arg)
+{
+ struct zebra_l2_bridge_if *br;
+ struct zebra_l2_bridge_if_ctx ctx;
+
+ br = BRIDGE_FROM_ZEBRA_IF(zif);
+ memset(&ctx, 0, sizeof(ctx));
+ ctx.zif = zif;
+ ctx.func = func;
+ ctx.arg = arg;
+ hash_walk(br->vlan_table, zebra_l2_bridge_if_vlan_walk_callback, &ctx);
+}
+
+int zebra_l2_bridge_if_vlan_access_bd_deref(struct zebra_evpn_access_bd *bd)
+{
+ int chgflags = 0;
+ struct zebra_if *zif;
+ struct zebra_l2_bridge_vlan bvl;
+ struct zebra_l2_bridge_vlan *bvlan;
+
+ zif = bd->bridge_zif;
+ if (!zif)
+ return -1;
+
+ bvlan = zebra_l2_bridge_if_vlan_find(zif, bd->vid);
+ if (!bvlan)
+ return 0;
+
+ memset(&bvl, 0, sizeof(bvl));
+ bvl.vid = bd->vid;
+ bvl.access_bd = NULL;
+ chgflags = ZEBRA_BRIDGEIF_ACCESS_BD_CHANGE;
+ return zebra_l2_bridge_if_vlan_update(zif->ifp, &bvl, chgflags);
+}
+
+int zebra_l2_bridge_if_vlan_access_bd_ref(struct zebra_evpn_access_bd *bd)
+{
+ int chgflags = 0;
+ struct zebra_if *zif;
+ struct zebra_l2_bridge_vlan bvl;
+ struct zebra_l2_bridge_vlan *bvlan;
+
+ zif = bd->bridge_zif;
+ if (!zif)
+ return -1;
+
+ if (!bd->vid)
+ return -1;
+
+ memset(&bvl, 0, sizeof(bvl));
+ bvl.vid = bd->vid;
+ bvl.access_bd = bd;
+
+ bvlan = zebra_l2_bridge_if_vlan_find(zif, bd->vid);
+ if (!bvlan)
+ return zebra_l2_bridge_if_vlan_add(zif->ifp, &bvl);
+
+ chgflags = ZEBRA_BRIDGEIF_ACCESS_BD_CHANGE;
+ return zebra_l2_bridge_if_vlan_update(zif->ifp, &bvl, chgflags);
+}
+
+int zebra_l2_bridge_if_cleanup(struct interface *ifp)
+{
+ struct zebra_if *zif;
+
+ if (!IS_ZEBRA_IF_BRIDGE(ifp))
+ return 0;
+
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug("bridge %s cleanup", ifp->name);
+
+ zif = (struct zebra_if *)ifp->info;
+ zebra_l2_bridge_if_vlan_table_destroy(zif);
+ return 0;
+}
+
+int zebra_l2_bridge_if_del(struct interface *ifp)
+{
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug("bridge %s delete", ifp->name);
+
+ return zebra_l2_bridge_if_cleanup(ifp);
+}
+
+int zebra_l2_bridge_if_add(struct interface *ifp)
+{
+ struct zebra_if *zif;
+ struct zebra_l2_bridge_if *br;
+
+ zif = (struct zebra_if *)ifp->info;
+ br = BRIDGE_FROM_ZEBRA_IF(zif);
+ br->br_zif = (struct zebra_if *)ifp->info;
+ zebra_l2_bridge_if_vlan_table_create(zif);
+ return 0;
+}
diff --git a/zebra/zebra_l2_bridge_if.h b/zebra/zebra_l2_bridge_if.h
new file mode 100644
index 0000000000..734ecfdcf1
--- /dev/null
+++ b/zebra/zebra_l2_bridge_if.h
@@ -0,0 +1,75 @@
+/*
+ * Zebra L2 bridge interface data structures and definitions
+ * These are public definitions referenced by other files.
+ * Copyright (C) 2021 Cumulus Networks, Inc.
+ * Sharath Ramamurthy
+ *
+ * This file is part of FRR.
+ *
+ * FRR is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * FRR is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with FRR; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef _ZEBRA_L2_BRIDGE_IF_H
+#define _ZEBRA_L2_BRIDGE_IF_H
+
+#include <zebra.h>
+#include <zebra/zebra_router.h>
+
+#include "linklist.h"
+#include "if.h"
+#include "vlan.h"
+#include "vxlan.h"
+
+#include "lib/json.h"
+#include "zebra/zebra_vrf.h"
+#include "zebra/zserv.h"
+
+#include "zebra/zebra_dplane.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Bridge interface change flags of interest. */
+#define ZEBRA_BRIDGEIF_ACCESS_BD_CHANGE (1 << 0)
+
+extern struct zebra_l2_bridge_vlan *
+zebra_l2_bridge_if_vlan_find(const struct zebra_if *zif, vlanid_t vid);
+extern vni_t zebra_l2_bridge_if_vni_find(const struct zebra_if *zif,
+ vlanid_t vid);
+extern void zebra_l2_bridge_if_vlan_iterate(
+ struct zebra_if *zif,
+ int (*func)(struct zebra_if *zif, struct zebra_l2_bridge_vlan *,
+ void *),
+ void *arg);
+extern void
+zebra_l2_bridge_if_vlan_walk(struct zebra_if *zif,
+ int (*func)(struct zebra_if *zif,
+ struct zebra_l2_bridge_vlan *, void *),
+ void *arg);
+extern int
+zebra_l2_bridge_if_vlan_access_bd_deref(struct zebra_evpn_access_bd *bd);
+extern int
+zebra_l2_bridge_if_vlan_access_bd_ref(struct zebra_evpn_access_bd *bd);
+extern int zebra_l2_bridge_if_del(struct interface *ifp);
+extern int zebra_l2_bridge_if_add(struct interface *ifp);
+extern int zebra_l2_bridge_if_cleanup(struct interface *ifp);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _ZEBRA_L2_BRIDGE_IF_H */
diff --git a/zebra/zebra_mpls.c b/zebra/zebra_mpls.c
index 13963d9cc3..aec4961126 100644
--- a/zebra/zebra_mpls.c
+++ b/zebra/zebra_mpls.c
@@ -492,7 +492,7 @@ static void fec_print(struct zebra_fec *fec, struct vty *vty)
rn = fec->rn;
vty_out(vty, "%pRN\n", rn);
- vty_out(vty, " Label: %s", label2str(fec->label, buf, BUFSIZ));
+ vty_out(vty, " Label: %s", label2str(fec->label, 0, buf, BUFSIZ));
if (fec->label_index != MPLS_INVALID_LABEL_INDEX)
vty_out(vty, ", Label Index: %u", fec->label_index);
vty_out(vty, "\n");
@@ -1597,8 +1597,8 @@ static void nhlfe_print(struct zebra_nhlfe *nhlfe, struct vty *vty,
vty_out(vty, " type: %s remote label: %s distance: %d\n",
nhlfe_type2str(nhlfe->type),
mpls_label2str(nexthop->nh_label->num_labels,
- nexthop->nh_label->label,
- buf, sizeof(buf), 0),
+ nexthop->nh_label->label, buf, sizeof(buf),
+ nexthop->nh_label_type, 0),
nhlfe->distance);
if (indent)
@@ -2719,7 +2719,7 @@ int zebra_mpls_write_fec_config(struct vty *vty, struct zebra_vrf *zvrf)
write = 1;
vty_out(vty, "mpls label bind %pFX %s\n", &rn->p,
- label2str(fec->label, lstr, BUFSIZ));
+ label2str(fec->label, 0, lstr, BUFSIZ));
}
}
@@ -3164,10 +3164,10 @@ lsp_add_nhlfe(struct zebra_lsp *lsp, enum lsp_types_t type,
nhlfe2str(nhlfe, buf, sizeof(buf));
mpls_label2str(num_out_labels, out_labels, buf2,
- sizeof(buf2), 0);
+ sizeof(buf2), 0, 0);
mpls_label2str(nh->nh_label->num_labels,
nh->nh_label->label, buf3, sizeof(buf3),
- 0);
+ nh->nh_label_type, 0);
zlog_debug("LSP in-label %u type %d %snexthop %s out-label(s) changed to %s (old %s)",
lsp->ile.in_label, type, backup_str, buf,
@@ -3195,7 +3195,7 @@ lsp_add_nhlfe(struct zebra_lsp *lsp, enum lsp_types_t type,
nhlfe2str(nhlfe, buf, sizeof(buf));
mpls_label2str(num_out_labels, out_labels, buf2,
- sizeof(buf2), 0);
+ sizeof(buf2), 0, 0);
zlog_debug("Add LSP in-label %u type %d %snexthop %s out-label(s) %s",
lsp->ile.in_label, type, backup_str, buf,
@@ -3778,10 +3778,10 @@ void zebra_mpls_print_lsp_table(struct vty *vty, struct zebra_vrf *zvrf,
json = json_object_new_object();
for (ALL_LIST_ELEMENTS_RO(lsp_list, node, lsp))
- json_object_object_add(
- json, label2str(lsp->ile.in_label, buf,
- sizeof(buf)),
- lsp_json(lsp));
+ json_object_object_add(json,
+ label2str(lsp->ile.in_label, 0,
+ buf, sizeof(buf)),
+ lsp_json(lsp));
vty_json(vty, json);
} else {
@@ -3833,7 +3833,8 @@ void zebra_mpls_print_lsp_table(struct vty *vty, struct zebra_vrf *zvrf,
out_label_str = mpls_label2str(
nexthop->nh_label->num_labels,
&nexthop->nh_label->label[0],
- buf, sizeof(buf), 1);
+ buf, sizeof(buf),
+ nexthop->nh_label_type, 1);
else
out_label_str = "-";
diff --git a/zebra/zebra_mpls.h b/zebra/zebra_mpls.h
index cf247861f8..1e63a59576 100644
--- a/zebra/zebra_mpls.h
+++ b/zebra/zebra_mpls.h
@@ -446,6 +446,7 @@ static inline uint8_t lsp_distance(enum lsp_types_t type)
return (route_distance(ZEBRA_ROUTE_BGP));
case ZEBRA_LSP_NONE:
case ZEBRA_LSP_SHARP:
+ case ZEBRA_LSP_EVPN:
case ZEBRA_LSP_OSPF_SR:
case ZEBRA_LSP_ISIS_SR:
case ZEBRA_LSP_SRTE:
@@ -498,6 +499,7 @@ static inline int re_type_from_lsp_type(enum lsp_types_t lsp_type)
case ZEBRA_LSP_LDP:
return ZEBRA_ROUTE_LDP;
case ZEBRA_LSP_BGP:
+ case ZEBRA_LSP_EVPN:
return ZEBRA_ROUTE_BGP;
case ZEBRA_LSP_OSPF_SR:
return ZEBRA_ROUTE_OSPF;
@@ -538,6 +540,8 @@ static inline const char *nhlfe_type2str(enum lsp_types_t lsp_type)
return "SHARP";
case ZEBRA_LSP_SRTE:
return "SR-TE";
+ case ZEBRA_LSP_EVPN:
+ return "EVPN";
case ZEBRA_LSP_NONE:
return "Unknown";
}
diff --git a/zebra/zebra_nb_state.c b/zebra/zebra_nb_state.c
index 0f3d56f214..45b9d440a6 100644
--- a/zebra/zebra_nb_state.c
+++ b/zebra/zebra_nb_state.c
@@ -25,6 +25,8 @@
#include "zebra/zebra_router.h"
#include "zebra/debug.h"
#include "printfrr.h"
+#include "zebra/zebra_vxlan.h"
+#include "zebra/zebra_vxlan_if.h"
/*
* XPath: /frr-interface:lib/interface/frr-zebra:zebra/state/up-count
@@ -101,15 +103,18 @@ lib_interface_zebra_state_vni_id_get_elem(struct nb_cb_get_elem_args *args)
{
const struct interface *ifp = args->list_entry;
struct zebra_if *zebra_if;
- struct zebra_l2info_vxlan *vxlan_info;
+ struct zebra_vxlan_vni *vni;
if (!IS_ZEBRA_IF_VXLAN(ifp))
return NULL;
zebra_if = ifp->info;
- vxlan_info = &zebra_if->l2info.vxl;
- return yang_data_new_uint32(args->xpath, vxlan_info->vni);
+ if (!IS_ZEBRA_VXLAN_IF_VNI(zebra_if))
+ return NULL;
+
+ vni = zebra_vxlan_if_vni_find(zebra_if, 0);
+ return yang_data_new_uint32(args->xpath, vni->vni);
}
/*
@@ -139,15 +144,18 @@ lib_interface_zebra_state_mcast_group_get_elem(struct nb_cb_get_elem_args *args)
{
const struct interface *ifp = args->list_entry;
struct zebra_if *zebra_if;
- struct zebra_l2info_vxlan *vxlan_info;
+ struct zebra_vxlan_vni *vni;
if (!IS_ZEBRA_IF_VXLAN(ifp))
return NULL;
zebra_if = ifp->info;
- vxlan_info = &zebra_if->l2info.vxl;
- return yang_data_new_ipv4(args->xpath, &vxlan_info->mcast_grp);
+ if (!IS_ZEBRA_VXLAN_IF_VNI(zebra_if))
+ return NULL;
+
+ vni = zebra_vxlan_if_vni_find(zebra_if, 0);
+ return yang_data_new_ipv4(args->xpath, &vni->mcast_grp);
}
const void *lib_vrf_zebra_ribs_rib_get_next(struct nb_cb_get_next_args *args)
diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c
index 0bca00ced3..d321ab4949 100644
--- a/zebra/zebra_nhg.c
+++ b/zebra/zebra_nhg.c
@@ -44,6 +44,7 @@
#include "zebra/interface.h"
#include "zebra/zapi_msg.h"
#include "zebra/rib.h"
+#include "zebra/zebra_vxlan.h"
DEFINE_MTYPE_STATIC(ZEBRA, NHG, "Nexthop Group Entry");
DEFINE_MTYPE_STATIC(ZEBRA, NHG_CONNECTED, "Nexthop Group Connected");
@@ -1922,10 +1923,42 @@ static bool nexthop_valid_resolve(const struct nexthop *nexthop,
}
/*
- * When resolving a recursive nexthop, capture backup nexthop(s) also
- * so they can be conveyed through the dataplane to the FIB. We'll look
- * at the backups in the resolving nh 'nexthop' and its nhe, and copy them
- * into the route's resolved nh 'resolved' and its nhe 'nhe'.
+ * Downstream VNI and Single VXlan device check.
+ *
+ * If it has nexthop VNI labels at this point it must be D-VNI allocated
+ * and all the nexthops have to be on an SVD.
+ *
+ * If SVD is not available, mark as inactive.
+ */
+static bool nexthop_set_evpn_dvni_svd(vrf_id_t re_vrf_id,
+ struct nexthop *nexthop)
+{
+ if (!is_vrf_l3vni_svd_backed(re_vrf_id)) {
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL) {
+ struct vrf *vrf = vrf_lookup_by_id(re_vrf_id);
+
+ zlog_debug(
+ "nexthop %pNHv D-VNI but route's vrf %s(%u) doesn't use SVD",
+ nexthop, VRF_LOGNAME(vrf), re_vrf_id);
+ }
+
+ return false;
+ }
+
+ nexthop->ifindex = get_l3vni_vxlan_ifindex(re_vrf_id);
+ nexthop->vrf_id = 0;
+
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("nexthop %pNHv using SVD", nexthop);
+
+ return true;
+}
+
+/*
+ * Given a nexthop we need to properly recursively resolve
+ * the route. As such, do a table lookup to find and match
+ * if at all possible. Set the nexthop->ifindex and resolved_id
+ * as appropriate
*/
static int resolve_backup_nexthops(const struct nexthop *nexthop,
const struct nhg_hash_entry *nhe,
@@ -2195,6 +2228,12 @@ static int nexthop_active(struct nexthop *nexthop, struct nhg_hash_entry *nhe,
* sure the nexthop's interface is known and is operational.
*/
if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK)) {
+ /* DVNI/SVD Checks for EVPN routes */
+ if (nexthop->nh_label &&
+ nexthop->nh_label_type == ZEBRA_LSP_EVPN &&
+ !nexthop_set_evpn_dvni_svd(vrf_id, nexthop))
+ return 0;
+
ifp = if_lookup_by_index(nexthop->ifindex, nexthop->vrf_id);
if (!ifp) {
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
@@ -2706,6 +2745,51 @@ done:
return valid;
}
+/* Checks if the first nexthop is EVPN. If not, early return.
+ *
+ * This is used to determine if there is a mismatch between l3VNI
+ * of the route's vrf and the nexthops in use's VNI labels.
+ *
+ * If there is a mismatch, we keep the labels as these MUST be DVNI nexthops.
+ *
+ * IF there is no mismatch, we remove the labels and handle the routes as
+ * we have traditionally with evpn.
+ */
+static bool nexthop_list_set_evpn_dvni(struct route_entry *re,
+ struct nexthop_group *nhg)
+{
+ struct nexthop *nexthop;
+ vni_t re_vrf_vni;
+ vni_t nh_vni;
+ bool use_dvni = false;
+
+ nexthop = nhg->nexthop;
+
+ if (!nexthop->nh_label || nexthop->nh_label_type != ZEBRA_LSP_EVPN)
+ return false;
+
+ re_vrf_vni = get_l3vni_vni(re->vrf_id);
+
+ for (; nexthop; nexthop = nexthop->next) {
+ if (!nexthop->nh_label ||
+ nexthop->nh_label_type != ZEBRA_LSP_EVPN)
+ continue;
+
+ nh_vni = label2vni(&nexthop->nh_label->label[0]);
+
+ if (nh_vni != re_vrf_vni)
+ use_dvni = true;
+ }
+
+ /* Using traditional way, no VNI encap - remove labels */
+ if (!use_dvni) {
+ for (nexthop = nhg->nexthop; nexthop; nexthop = nexthop->next)
+ nexthop_del_labels(nexthop);
+ }
+
+ return use_dvni;
+}
+
/*
* Process a list of nexthops, given an nhe, determining
* whether each one is ACTIVE/installable at this time.
@@ -2721,12 +2805,16 @@ static uint32_t nexthop_list_active_update(struct route_node *rn,
uint32_t counter = 0;
struct nexthop *nexthop;
struct nexthop_group *nhg = &nhe->nhg;
+ bool vni_removed = false;
nexthop = nhg->nexthop;
/* Init recursive nh mtu */
re->nexthop_mtu = 0;
+ /* Handler for dvni evpn nexthops. Has to be done at nhg level */
+ vni_removed = !nexthop_list_set_evpn_dvni(re, nhg);
+
/* Process nexthops one-by-one */
for ( ; nexthop; nexthop = nexthop->next) {
@@ -2764,16 +2852,17 @@ static uint32_t nexthop_list_active_update(struct route_node *rn,
counter++;
/* Check for changes to the nexthop - set ROUTE_ENTRY_CHANGED */
- if (prev_active != new_active || prev_index != nexthop->ifindex
- || ((nexthop->type >= NEXTHOP_TYPE_IFINDEX
- && nexthop->type < NEXTHOP_TYPE_IPV6)
- && prev_src.ipv4.s_addr
- != nexthop->rmap_src.ipv4.s_addr)
- || ((nexthop->type >= NEXTHOP_TYPE_IPV6
- && nexthop->type < NEXTHOP_TYPE_BLACKHOLE)
- && !(IPV6_ADDR_SAME(&prev_src.ipv6,
- &nexthop->rmap_src.ipv6)))
- || CHECK_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED))
+ if (prev_active != new_active ||
+ prev_index != nexthop->ifindex ||
+ ((nexthop->type >= NEXTHOP_TYPE_IFINDEX &&
+ nexthop->type < NEXTHOP_TYPE_IPV6) &&
+ prev_src.ipv4.s_addr != nexthop->rmap_src.ipv4.s_addr) ||
+ ((nexthop->type >= NEXTHOP_TYPE_IPV6 &&
+ nexthop->type < NEXTHOP_TYPE_BLACKHOLE) &&
+ !(IPV6_ADDR_SAME(&prev_src.ipv6,
+ &nexthop->rmap_src.ipv6))) ||
+ CHECK_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED) ||
+ vni_removed)
SET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
}
diff --git a/zebra/zebra_ns.c b/zebra/zebra_ns.c
index 7b076b8a4a..457a4955b4 100644
--- a/zebra/zebra_ns.c
+++ b/zebra/zebra_ns.c
@@ -127,6 +127,8 @@ int zebra_ns_enable(ns_id_t ns_id, void **info)
zebra_dplane_ns_enable(zns, true);
interface_list(zns);
route_read(zns);
+
+ vlan_read(zns);
kernel_read_pbr_rules(zns);
kernel_read_tc_qdisc(zns);
diff --git a/zebra/zebra_ptm.c b/zebra/zebra_ptm.c
index 4a18eb021e..937dc090a4 100644
--- a/zebra/zebra_ptm.c
+++ b/zebra/zebra_ptm.c
@@ -31,7 +31,6 @@
#include "ptm_lib.h"
#include "rib.h"
#include "stream.h"
-#include "lib/version.h"
#include "vrf.h"
#include "vty.h"
#include "lib_errors.h"
diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c
index ba8073defe..415fc78142 100644
--- a/zebra/zebra_rib.c
+++ b/zebra/zebra_rib.c
@@ -99,42 +99,79 @@ static const struct {
uint8_t distance;
enum meta_queue_indexes meta_q_map;
} route_info[ZEBRA_ROUTE_MAX] = {
- [ZEBRA_ROUTE_NHG] = {ZEBRA_ROUTE_NHG, 255 /* Unneeded for nhg's */,
- META_QUEUE_NHG},
- [ZEBRA_ROUTE_SYSTEM] = {ZEBRA_ROUTE_SYSTEM, 0, META_QUEUE_KERNEL},
- [ZEBRA_ROUTE_KERNEL] = {ZEBRA_ROUTE_KERNEL, 0, META_QUEUE_KERNEL},
- [ZEBRA_ROUTE_CONNECT] = {ZEBRA_ROUTE_CONNECT, 0, META_QUEUE_CONNECTED},
- [ZEBRA_ROUTE_STATIC] = {ZEBRA_ROUTE_STATIC, 1, META_QUEUE_STATIC},
- [ZEBRA_ROUTE_RIP] = {ZEBRA_ROUTE_RIP, 120, META_QUEUE_NOTBGP},
- [ZEBRA_ROUTE_RIPNG] = {ZEBRA_ROUTE_RIPNG, 120, META_QUEUE_NOTBGP},
- [ZEBRA_ROUTE_OSPF] = {ZEBRA_ROUTE_OSPF, 110, META_QUEUE_NOTBGP},
- [ZEBRA_ROUTE_OSPF6] = {ZEBRA_ROUTE_OSPF6, 110, META_QUEUE_NOTBGP},
- [ZEBRA_ROUTE_ISIS] = {ZEBRA_ROUTE_ISIS, 115, META_QUEUE_NOTBGP},
- [ZEBRA_ROUTE_BGP] = {ZEBRA_ROUTE_BGP, 20 /* IBGP is 200. */,
+ [ZEBRA_ROUTE_NHG] =
+ {ZEBRA_ROUTE_NHG,
+ ZEBRA_MAX_DISTANCE_DEFAULT /* Unneeded for nhg's */,
+ META_QUEUE_NHG},
+ [ZEBRA_ROUTE_SYSTEM] = {ZEBRA_ROUTE_SYSTEM,
+ ZEBRA_KERNEL_DISTANCE_DEFAULT,
+ META_QUEUE_KERNEL},
+ [ZEBRA_ROUTE_KERNEL] = {ZEBRA_ROUTE_KERNEL,
+ ZEBRA_KERNEL_DISTANCE_DEFAULT,
+ META_QUEUE_KERNEL},
+ [ZEBRA_ROUTE_CONNECT] = {ZEBRA_ROUTE_CONNECT,
+ ZEBRA_CONNECT_DISTANCE_DEFAULT,
+ META_QUEUE_CONNECTED},
+ [ZEBRA_ROUTE_STATIC] = {ZEBRA_ROUTE_STATIC,
+ ZEBRA_STATIC_DISTANCE_DEFAULT,
+ META_QUEUE_STATIC},
+ [ZEBRA_ROUTE_RIP] = {ZEBRA_ROUTE_RIP, ZEBRA_RIP_DISTANCE_DEFAULT,
+ META_QUEUE_NOTBGP},
+ [ZEBRA_ROUTE_RIPNG] = {ZEBRA_ROUTE_RIPNG, ZEBRA_RIP_DISTANCE_DEFAULT,
+ META_QUEUE_NOTBGP},
+ [ZEBRA_ROUTE_OSPF] = {ZEBRA_ROUTE_OSPF, ZEBRA_OSPF_DISTANCE_DEFAULT,
+ META_QUEUE_NOTBGP},
+ [ZEBRA_ROUTE_OSPF6] = {ZEBRA_ROUTE_OSPF6, ZEBRA_OSPF6_DISTANCE_DEFAULT,
+ META_QUEUE_NOTBGP},
+ [ZEBRA_ROUTE_ISIS] = {ZEBRA_ROUTE_ISIS, ZEBRA_ISIS_DISTANCE_DEFAULT,
+ META_QUEUE_NOTBGP},
+ [ZEBRA_ROUTE_BGP] = {ZEBRA_ROUTE_BGP,
+ ZEBRA_EBGP_DISTANCE_DEFAULT /* IBGP is 200. */,
META_QUEUE_BGP},
- [ZEBRA_ROUTE_PIM] = {ZEBRA_ROUTE_PIM, 255, META_QUEUE_OTHER},
- [ZEBRA_ROUTE_EIGRP] = {ZEBRA_ROUTE_EIGRP, 90, META_QUEUE_NOTBGP},
- [ZEBRA_ROUTE_NHRP] = {ZEBRA_ROUTE_NHRP, 10, META_QUEUE_NOTBGP},
- [ZEBRA_ROUTE_HSLS] = {ZEBRA_ROUTE_HSLS, 255, META_QUEUE_OTHER},
- [ZEBRA_ROUTE_OLSR] = {ZEBRA_ROUTE_OLSR, 255, META_QUEUE_OTHER},
- [ZEBRA_ROUTE_TABLE] = {ZEBRA_ROUTE_TABLE, 150, META_QUEUE_STATIC},
- [ZEBRA_ROUTE_LDP] = {ZEBRA_ROUTE_LDP, 150, META_QUEUE_OTHER},
- [ZEBRA_ROUTE_VNC] = {ZEBRA_ROUTE_VNC, 20, META_QUEUE_BGP},
- [ZEBRA_ROUTE_VNC_DIRECT] = {ZEBRA_ROUTE_VNC_DIRECT, 20, META_QUEUE_BGP},
- [ZEBRA_ROUTE_VNC_DIRECT_RH] = {ZEBRA_ROUTE_VNC_DIRECT_RH, 20,
+ [ZEBRA_ROUTE_PIM] = {ZEBRA_ROUTE_PIM, ZEBRA_MAX_DISTANCE_DEFAULT,
+ META_QUEUE_OTHER},
+ [ZEBRA_ROUTE_EIGRP] = {ZEBRA_ROUTE_EIGRP, ZEBRA_EIGRP_DISTANCE_DEFAULT,
+ META_QUEUE_NOTBGP},
+ [ZEBRA_ROUTE_NHRP] = {ZEBRA_ROUTE_NHRP, ZEBRA_NHRP_DISTANCE_DEFAULT,
+ META_QUEUE_NOTBGP},
+ [ZEBRA_ROUTE_HSLS] = {ZEBRA_ROUTE_HSLS, ZEBRA_MAX_DISTANCE_DEFAULT,
+ META_QUEUE_OTHER},
+ [ZEBRA_ROUTE_OLSR] = {ZEBRA_ROUTE_OLSR, ZEBRA_MAX_DISTANCE_DEFAULT,
+ META_QUEUE_OTHER},
+ [ZEBRA_ROUTE_TABLE] = {ZEBRA_ROUTE_TABLE, ZEBRA_TABLE_DISTANCE_DEFAULT, META_QUEUE_STATIC},
+ [ZEBRA_ROUTE_LDP] = {ZEBRA_ROUTE_LDP, ZEBRA_LDP_DISTANCE_DEFAULT,
+ META_QUEUE_OTHER},
+ [ZEBRA_ROUTE_VNC] = {ZEBRA_ROUTE_VNC, ZEBRA_EBGP_DISTANCE_DEFAULT,
+ META_QUEUE_BGP},
+ [ZEBRA_ROUTE_VNC_DIRECT] = {ZEBRA_ROUTE_VNC_DIRECT,
+ ZEBRA_EBGP_DISTANCE_DEFAULT,
+ META_QUEUE_BGP},
+ [ZEBRA_ROUTE_VNC_DIRECT_RH] = {ZEBRA_ROUTE_VNC_DIRECT_RH,
+ ZEBRA_EBGP_DISTANCE_DEFAULT,
META_QUEUE_BGP},
- [ZEBRA_ROUTE_BGP_DIRECT] = {ZEBRA_ROUTE_BGP_DIRECT, 20, META_QUEUE_BGP},
- [ZEBRA_ROUTE_BGP_DIRECT_EXT] = {ZEBRA_ROUTE_BGP_DIRECT_EXT, 20,
+ [ZEBRA_ROUTE_BGP_DIRECT] = {ZEBRA_ROUTE_BGP_DIRECT,
+ ZEBRA_EBGP_DISTANCE_DEFAULT,
+ META_QUEUE_BGP},
+ [ZEBRA_ROUTE_BGP_DIRECT_EXT] = {ZEBRA_ROUTE_BGP_DIRECT_EXT,
+ ZEBRA_EBGP_DISTANCE_DEFAULT,
META_QUEUE_BGP},
- [ZEBRA_ROUTE_BABEL] = {ZEBRA_ROUTE_BABEL, 100, META_QUEUE_NOTBGP},
- [ZEBRA_ROUTE_SHARP] = {ZEBRA_ROUTE_SHARP, 150, META_QUEUE_OTHER},
- [ZEBRA_ROUTE_PBR] = {ZEBRA_ROUTE_PBR, 200, META_QUEUE_OTHER},
- [ZEBRA_ROUTE_BFD] = {ZEBRA_ROUTE_BFD, 255, META_QUEUE_OTHER},
- [ZEBRA_ROUTE_OPENFABRIC] = {ZEBRA_ROUTE_OPENFABRIC, 115,
+ [ZEBRA_ROUTE_BABEL] = {ZEBRA_ROUTE_BABEL, ZEBRA_BABEL_DISTANCE_DEFAULT,
+ META_QUEUE_NOTBGP},
+ [ZEBRA_ROUTE_SHARP] = {ZEBRA_ROUTE_SHARP, ZEBRA_SHARP_DISTANCE_DEFAULT,
+ META_QUEUE_OTHER},
+ [ZEBRA_ROUTE_PBR] = {ZEBRA_ROUTE_PBR, ZEBRA_PBR_DISTANCE_DEFAULT,
+ META_QUEUE_OTHER},
+ [ZEBRA_ROUTE_BFD] = {ZEBRA_ROUTE_BFD, ZEBRA_MAX_DISTANCE_DEFAULT,
+ META_QUEUE_OTHER},
+ [ZEBRA_ROUTE_OPENFABRIC] = {ZEBRA_ROUTE_OPENFABRIC,
+ ZEBRA_OPENFABRIC_DISTANCE_DEFAULT,
META_QUEUE_NOTBGP},
- [ZEBRA_ROUTE_VRRP] = {ZEBRA_ROUTE_VRRP, 255, META_QUEUE_OTHER},
- [ZEBRA_ROUTE_SRTE] = {ZEBRA_ROUTE_SRTE, 255, META_QUEUE_OTHER},
- [ZEBRA_ROUTE_ALL] = {ZEBRA_ROUTE_ALL, 255, META_QUEUE_OTHER},
+ [ZEBRA_ROUTE_VRRP] = {ZEBRA_ROUTE_VRRP, ZEBRA_MAX_DISTANCE_DEFAULT,
+ META_QUEUE_OTHER},
+ [ZEBRA_ROUTE_SRTE] = {ZEBRA_ROUTE_SRTE, ZEBRA_MAX_DISTANCE_DEFAULT,
+ META_QUEUE_OTHER},
+ [ZEBRA_ROUTE_ALL] = {ZEBRA_ROUTE_ALL, ZEBRA_MAX_DISTANCE_DEFAULT,
+ META_QUEUE_OTHER},
/* Any new route type added to zebra, should be mirrored here */
/* no entry/default: 150 */
@@ -4025,7 +4062,8 @@ static void _route_entry_dump_nh(const struct route_entry *re,
if (nexthop->nh_label && nexthop->nh_label->num_labels > 0) {
mpls_label2str(nexthop->nh_label->num_labels,
nexthop->nh_label->label, label_str,
- sizeof(label_str), 0 /*pretty*/);
+ sizeof(label_str), nexthop->nh_label_type,
+ 0 /*pretty*/);
strlcat(label_str, ", ", sizeof(label_str));
}
diff --git a/zebra/zebra_rnh.c b/zebra/zebra_rnh.c
index 342a8d0f96..3bbb1f2325 100644
--- a/zebra/zebra_rnh.c
+++ b/zebra/zebra_rnh.c
@@ -1413,8 +1413,14 @@ void show_nexthop_json_helper(json_object *json_nexthop,
label_index < nexthop->nh_label->num_labels; label_index++)
json_object_array_add(
json_labels,
- json_object_new_int(
- nexthop->nh_label->label[label_index]));
+ json_object_new_int((
+ (nexthop->nh_label_type ==
+ ZEBRA_LSP_EVPN)
+ ? label2vni(
+ &nexthop->nh_label->label
+ [label_index])
+ : nexthop->nh_label->label
+ [label_index])));
json_object_object_add(json_nexthop, "labels", json_labels);
}
@@ -1534,7 +1540,7 @@ void show_route_nexthop_helper(struct vty *vty, const struct route_entry *re,
vty_out(vty, ", label %s",
mpls_label2str(nexthop->nh_label->num_labels,
nexthop->nh_label->label, buf,
- sizeof(buf), 1));
+ sizeof(buf), nexthop->nh_label_type, 1));
}
if (nexthop->nh_srv6) {
diff --git a/zebra/zebra_routemap.c b/zebra/zebra_routemap.c
index 5f307f95e3..8f24404a44 100644
--- a/zebra/zebra_routemap.c
+++ b/zebra/zebra_routemap.c
@@ -1055,8 +1055,13 @@ route_match_ip_next_hop(void *rule, const struct prefix *prefix, void *object)
return RMAP_NOMATCH;
}
alist = access_list_lookup(AFI_IP, (char *)rule);
- if (alist == NULL)
+ if (alist == NULL) {
+ if (CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP_DETAIL))
+ zlog_debug(
+ "%s: Access-List Specified: %s does not exist defaulting to NO_MATCH",
+ __func__, (char *)rule);
return RMAP_NOMATCH;
+ }
return (access_list_apply(alist, &p) == FILTER_DENY ? RMAP_NOMATCH
: RMAP_MATCH);
@@ -1113,8 +1118,13 @@ route_match_ip_next_hop_prefix_list(void *rule, const struct prefix *prefix,
return RMAP_NOMATCH;
}
plist = prefix_list_lookup(AFI_IP, (char *)rule);
- if (plist == NULL)
+ if (plist == NULL) {
+ if (CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP_DETAIL))
+ zlog_debug(
+ "%s: Prefix List %s specified does not exist defaulting to NO_MATCH",
+ __func__, (char *)rule);
return RMAP_NOMATCH;
+ }
return (prefix_list_apply(plist, &p) == PREFIX_DENY ? RMAP_NOMATCH
: RMAP_MATCH);
@@ -1149,8 +1159,13 @@ route_match_address(afi_t afi, void *rule, const struct prefix *prefix,
struct access_list *alist;
alist = access_list_lookup(afi, (char *)rule);
- if (alist == NULL)
+ if (alist == NULL) {
+ if (CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP_DETAIL))
+ zlog_debug(
+ "%s: Access-List Specified: %s does not exist defaulting to NO_MATCH",
+ __func__, (char *)rule);
return RMAP_NOMATCH;
+ }
return (access_list_apply(alist, prefix) == FILTER_DENY ? RMAP_NOMATCH
: RMAP_MATCH);
@@ -1206,8 +1221,13 @@ route_match_address_prefix_list(void *rule, const struct prefix *prefix,
struct prefix_list *plist;
plist = prefix_list_lookup(afi, (char *)rule);
- if (plist == NULL)
+ if (plist == NULL) {
+ if (CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP_DETAIL))
+ zlog_debug(
+ "%s: Prefix List %s specified does not exist defaulting to NO_MATCH",
+ __func__, (char *)rule);
return RMAP_NOMATCH;
+ }
return (prefix_list_apply(plist, prefix) == PREFIX_DENY ? RMAP_NOMATCH
: RMAP_MATCH);
diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c
index b013e59015..3b63821d37 100644
--- a/zebra/zebra_vty.c
+++ b/zebra/zebra_vty.c
@@ -420,7 +420,8 @@ static void show_nexthop_detail_helper(struct vty *vty,
vty_out(vty, ", label %s",
mpls_label2str(nexthop->nh_label->num_labels,
nexthop->nh_label->label, buf,
- sizeof(buf), 1 /*pretty*/));
+ sizeof(buf), nexthop->nh_label_type,
+ 1 /*pretty*/));
}
if (nexthop->weight)
@@ -3018,20 +3019,37 @@ DEFPY(show_evpn_es_evi,
return CMD_SUCCESS;
}
-DEFPY(show_evpn_access_vlan,
- show_evpn_access_vlan_cmd,
- "show evpn access-vlan [(1-4094)$vid | detail$detail] [json$json]",
+DEFPY(show_evpn_access_vlan, show_evpn_access_vlan_cmd,
+ "show evpn access-vlan [IFNAME$if_name (1-4094)$vid | detail$detail] [json$json]",
SHOW_STR
"EVPN\n"
"Access VLANs\n"
+ "Interface Name\n"
"VLAN ID\n"
- "Detailed information\n"
- JSON_STR)
+ "Detailed information\n" JSON_STR)
{
bool uj = !!json;
- if (vid) {
- zebra_evpn_acc_vl_show_vid(vty, uj, vid);
+ if (if_name && vid) {
+ bool found = false;
+ struct vrf *vrf;
+ struct interface *ifp;
+
+ RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
+ if (if_name) {
+ ifp = if_lookup_by_name(if_name, vrf->vrf_id);
+ if (ifp) {
+ zebra_evpn_acc_vl_show_vid(vty, uj, vid,
+ ifp);
+ found = true;
+ break;
+ }
+ }
+ }
+ if (!found) {
+ vty_out(vty, "%% Can't find interface %s\n", if_name);
+ return CMD_WARNING;
+ }
} else {
if (detail)
zebra_evpn_acc_vl_show_detail(vty, uj);
@@ -3181,6 +3199,30 @@ DEFUN (show_evpn_nh_vni_ip,
return CMD_SUCCESS;
}
+DEFUN_HIDDEN (show_evpn_nh_svd_ip,
+ show_evpn_nh_svd_ip_cmd,
+ "show evpn next-hops svd ip WORD [json]",
+ SHOW_STR
+ "EVPN\n"
+ "Remote Vteps\n"
+ "Single Vxlan Device\n"
+ "Ip address\n"
+ "Host address (ipv4 or ipv6)\n"
+ JSON_STR)
+{
+ struct ipaddr ip;
+ bool uj = use_json(argc, argv);
+
+ if (str2ipaddr(argv[5]->arg, &ip) != 0) {
+ if (!uj)
+ vty_out(vty, "%% Malformed Neighbor address\n");
+ return CMD_WARNING;
+ }
+ zebra_vxlan_print_specific_nh_l3vni(vty, 0, &ip, uj);
+
+ return CMD_SUCCESS;
+}
+
DEFUN (show_evpn_nh_vni,
show_evpn_nh_vni_cmd,
"show evpn next-hops vni " CMD_VNI_RANGE "[json]",
@@ -3200,6 +3242,22 @@ DEFUN (show_evpn_nh_vni,
return CMD_SUCCESS;
}
+DEFUN_HIDDEN (show_evpn_nh_svd,
+ show_evpn_nh_svd_cmd,
+ "show evpn next-hops svd [json]",
+ SHOW_STR
+ "EVPN\n"
+ "Remote VTEPs\n"
+ "Single Vxlan Device\n"
+ JSON_STR)
+{
+ bool uj = use_json(argc, argv);
+
+ zebra_vxlan_print_nh_svd(vty, uj);
+
+ return CMD_SUCCESS;
+}
+
DEFUN (show_evpn_nh_vni_all,
show_evpn_nh_vni_all_cmd,
"show evpn next-hops vni all [json]",
@@ -4557,7 +4615,9 @@ void zebra_vty_init(void)
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_svd_ip_cmd);
install_element(VIEW_NODE, &show_evpn_nh_vni_cmd);
+ install_element(VIEW_NODE, &show_evpn_nh_svd_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);
diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c
index 0bbc811324..4baa3d64af 100644
--- a/zebra/zebra_vxlan.c
+++ b/zebra/zebra_vxlan.c
@@ -46,13 +46,14 @@
#include "zebra/rt_netlink.h"
#include "zebra/zebra_errors.h"
#include "zebra/zebra_l2.h"
+#include "zebra/zebra_l2_bridge_if.h"
#include "zebra/zebra_ns.h"
#include "zebra/zebra_vrf.h"
#include "zebra/zebra_vxlan.h"
+#include "zebra/zebra_vxlan_private.h"
#include "zebra/zebra_evpn.h"
#include "zebra/zebra_evpn_mac.h"
#include "zebra/zebra_evpn_neigh.h"
-#include "zebra/zebra_vxlan_private.h"
#include "zebra/zebra_evpn_mh.h"
#include "zebra/zebra_evpn_vxlan.h"
#include "zebra/zebra_router.h"
@@ -72,6 +73,9 @@ DEFINE_HOOK(zebra_rmac_update,
/* config knobs */
static bool accept_bgp_seq = true;
+/* Single VXlan Device Global Neigh Table */
+struct hash *svd_nh_table;
+
/* static function declarations */
static void zevpn_print_neigh_hash_all_evpn(struct hash_bucket *bucket,
void **args);
@@ -92,6 +96,11 @@ static int zl3vni_nh_del(struct zebra_l3vni *zl3vni, struct zebra_neigh *n);
static int zl3vni_nh_install(struct zebra_l3vni *zl3vni, struct zebra_neigh *n);
static int zl3vni_nh_uninstall(struct zebra_l3vni *zl3vni,
struct zebra_neigh *n);
+static struct zebra_neigh *svd_nh_add(const struct ipaddr *vtep_ip,
+ const struct ethaddr *rmac);
+static int svd_nh_del(struct zebra_neigh *n);
+static int svd_nh_install(struct zebra_l3vni *zl3vni, struct zebra_neigh *n);
+static int svd_nh_uninstall(struct zebra_l3vni *zl3vni, struct zebra_neigh *n);
/* l3-vni rmac related APIs */
static void zl3vni_print_rmac_hash(struct hash_bucket *, void *);
@@ -110,8 +119,6 @@ static int zl3vni_rmac_uninstall(struct zebra_l3vni *zl3vni,
static void *zl3vni_alloc(void *p);
static struct zebra_l3vni *zl3vni_add(vni_t vni, vrf_id_t vrf_id);
static int zl3vni_del(struct zebra_l3vni *zl3vni);
-static void zebra_vxlan_process_l3vni_oper_up(struct zebra_l3vni *zl3vni);
-static void zebra_vxlan_process_l3vni_oper_down(struct zebra_l3vni *zl3vni);
static void zevpn_build_hash_table(void);
static unsigned int zebra_vxlan_sg_hash_key_make(const void *p);
@@ -121,10 +128,6 @@ static void zebra_vxlan_sg_do_deref(struct zebra_vrf *zvrf,
static struct zebra_vxlan_sg *zebra_vxlan_sg_do_ref(struct zebra_vrf *vrf,
struct in_addr sip,
struct in_addr mcast_grp);
-static void zebra_vxlan_sg_deref(struct in_addr local_vtep_ip,
- struct in_addr mcast_grp);
-static void zebra_vxlan_sg_ref(struct in_addr local_vtep_ip,
- struct in_addr mcast_grp);
static void zebra_vxlan_cleanup_sg_table(struct zebra_vrf *zvrf);
bool zebra_evpn_do_dup_addr_detect(struct zebra_vrf *zvrf)
@@ -375,11 +378,16 @@ static void zl3vni_print_nh(struct zebra_neigh *n, struct vty *vty,
ipaddr2str(&n->ip, buf2, sizeof(buf2)));
vty_out(vty, " RMAC: %s\n",
prefix_mac2str(&n->emac, buf1, sizeof(buf1)));
- vty_out(vty, " Refcount: %d\n",
- rb_host_count(&n->host_rb));
- vty_out(vty, " Prefixes:\n");
- RB_FOREACH (hle, host_rb_tree_entry, &n->host_rb)
- vty_out(vty, " %pFX\n", &hle->p);
+ if (n->refcnt)
+ /* SVD neigh */
+ vty_out(vty, " Refcount: %u\n", n->refcnt);
+ else {
+ vty_out(vty, " Refcount: %d\n",
+ rb_host_count(&n->host_rb));
+ vty_out(vty, " Prefixes:\n");
+ RB_FOREACH (hle, host_rb_tree_entry, &n->host_rb)
+ vty_out(vty, " %pFX\n", &hle->p);
+ }
} else {
json_hosts = json_object_new_array();
json_object_string_add(
@@ -387,13 +395,19 @@ static void zl3vni_print_nh(struct zebra_neigh *n, struct vty *vty,
json_object_string_add(
json, "routerMac",
prefix_mac2str(&n->emac, buf2, sizeof(buf2)));
- json_object_int_add(json, "refCount",
- rb_host_count(&n->host_rb));
- RB_FOREACH (hle, host_rb_tree_entry, &n->host_rb)
- json_object_array_add(json_hosts,
- json_object_new_string(prefix2str(
- &hle->p, buf2, sizeof(buf2))));
- json_object_object_add(json, "prefixList", json_hosts);
+ if (n->refcnt)
+ /* SVD neigh */
+ json_object_int_add(json, "refCount", n->refcnt);
+ else {
+ json_object_int_add(json, "refCount",
+ rb_host_count(&n->host_rb));
+ RB_FOREACH (hle, host_rb_tree_entry, &n->host_rb)
+ json_object_array_add(
+ json_hosts,
+ json_object_new_string(prefix2str(
+ &hle->p, buf2, sizeof(buf2))));
+ json_object_object_add(json, "prefixList", json_hosts);
+ }
}
}
@@ -597,33 +611,36 @@ static void zl3vni_print_nh_hash(struct hash_bucket *bucket, void *ctx)
}
}
-static void zl3vni_print_nh_hash_all_vni(struct hash_bucket *bucket,
- void **args)
+static void zl3vni_print_nh_all_table(struct hash *nh_table, vni_t vni,
+ struct vty *vty, json_object *json)
{
- struct vty *vty = NULL;
- json_object *json = NULL;
- json_object *json_evpn = NULL;
- struct zebra_l3vni *zl3vni = NULL;
uint32_t num_nh = 0;
struct nh_walk_ctx wctx;
char vni_str[VNI_STR_LEN];
+ json_object *json_evpn = NULL;
+ bool is_svd = false;
+ const char *svd_str = "Global SVD Table";
- vty = (struct vty *)args[0];
- json = (struct json_object *)args[1];
+ if (vni == 0)
+ is_svd = true;
- zl3vni = (struct zebra_l3vni *)bucket->data;
+ num_nh = hashcount(nh_table);
- num_nh = hashcount(zl3vni->nh_table);
if (!num_nh)
return;
if (json) {
json_evpn = json_object_new_object();
- snprintf(vni_str, VNI_STR_LEN, "%u", zl3vni->vni);
+
+ snprintf(vni_str, VNI_STR_LEN, "%u", vni);
}
if (json == NULL) {
- vty_out(vty, "\nVNI %u #Next-Hops %u\n\n", zl3vni->vni, num_nh);
+ if (is_svd)
+ vty_out(vty, "\n%s #Next-Hops %u\n\n", svd_str, num_nh);
+ else
+ vty_out(vty, "\nVNI %u #Next-Hops %u\n\n", vni, num_nh);
+
vty_out(vty, "%-15s %-17s\n", "IP", "RMAC");
} else
json_object_int_add(json_evpn, "numNextHops", num_nh);
@@ -631,11 +648,26 @@ static void zl3vni_print_nh_hash_all_vni(struct hash_bucket *bucket,
memset(&wctx, 0, sizeof(wctx));
wctx.vty = vty;
wctx.json = json_evpn;
- hash_iterate(zl3vni->nh_table, zl3vni_print_nh_hash, &wctx);
+ hash_iterate(nh_table, zl3vni_print_nh_hash, &wctx);
if (json)
json_object_object_add(json, vni_str, json_evpn);
}
+static void zl3vni_print_nh_hash_all_vni(struct hash_bucket *bucket,
+ void **args)
+{
+ struct vty *vty = NULL;
+ json_object *json = NULL;
+ struct zebra_l3vni *zl3vni = NULL;
+
+ vty = (struct vty *)args[0];
+ json = (struct json_object *)args[1];
+
+ zl3vni = (struct zebra_l3vni *)bucket->data;
+
+ zl3vni_print_nh_all_table(zl3vni->nh_table, zl3vni->vni, vty, json);
+}
+
static void zl3vni_print_rmac_hash_all_vni(struct hash_bucket *bucket,
void **args)
{
@@ -728,6 +760,9 @@ static void zl3vni_print(struct zebra_l3vni *zl3vni, void **ctx)
vty_out(vty, "VNI: %u\n", zl3vni->vni);
vty_out(vty, " Type: %s\n", "L3");
vty_out(vty, " Tenant VRF: %s\n", zl3vni_vrf_name(zl3vni));
+ vty_out(vty, " Vlan: %u\n", zl3vni->vid);
+ vty_out(vty, " Bridge: %s\n",
+ zl3vni->bridge_if ? zl3vni->bridge_if->name : "-");
vty_out(vty, " Local Vtep Ip: %pI4\n",
&zl3vni->local_vtep_ip);
vty_out(vty, " Vxlan-Intf: %s\n",
@@ -889,7 +924,6 @@ struct interface *zvni_map_to_svi(vlanid_t vid, struct interface *br_if)
{
struct interface *tmp_if = NULL;
struct zebra_if *zif;
- struct zebra_l2info_bridge *br;
struct zebra_from_svi_param in_param;
struct interface **p_ifp;
/* Defensive check, caller expected to invoke only with valid bridge. */
@@ -899,8 +933,7 @@ struct interface *zvni_map_to_svi(vlanid_t vid, struct interface *br_if)
/* Determine if bridge is VLAN-aware or not */
zif = br_if->info;
assert(zif);
- br = &zif->l2info.br;
- in_param.bridge_vlan_aware = br->vlan_aware;
+ in_param.bridge_vlan_aware = IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(zif);
/* Check oper status of the SVI. */
if (!in_param.bridge_vlan_aware)
return if_is_operative(br_if) ? br_if : NULL;
@@ -915,9 +948,11 @@ struct interface *zvni_map_to_svi(vlanid_t vid, struct interface *br_if)
return tmp_if;
}
-static int zebra_evpn_vxlan_del(struct zebra_evpn *zevpn)
+int zebra_evpn_vxlan_del(struct zebra_evpn *zevpn)
{
+ zevpn->vid = 0;
zevpn_vxlan_if_set(zevpn, zevpn->vxlan_if, false /* set */);
+ zevpn_bridge_if_set(zevpn, zevpn->bridge_if, false /* set */);
/* Remove references to the BUM mcast grp */
zebra_vxlan_sg_deref(zevpn->local_vtep_ip, zevpn->mcast_grp);
@@ -925,6 +960,136 @@ static int zebra_evpn_vxlan_del(struct zebra_evpn *zevpn)
return zebra_evpn_del(zevpn);
}
+static int zevpn_build_vni_hash_table(struct zebra_if *zif,
+ struct zebra_vxlan_vni *vnip, void *arg)
+{
+ vni_t vni;
+ struct zebra_evpn *zevpn;
+ struct zebra_l3vni *zl3vni;
+ struct interface *ifp;
+ struct zebra_l2info_vxlan *vxl;
+ struct interface *br_if;
+
+ ifp = zif->ifp;
+ vxl = &zif->l2info.vxl;
+ vni = vnip->vni;
+
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug("Build vni table for vni %u for Intf %s", vni,
+ ifp->name);
+
+ /* L3-VNI and L2-VNI are handled seperately */
+ zl3vni = zl3vni_lookup(vni);
+ if (zl3vni) {
+
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug(
+ "create L3-VNI hash for Intf %s(%u) L3-VNI %u",
+ ifp->name, ifp->ifindex, vni);
+
+ /* associate with vxlan_if */
+ zl3vni->local_vtep_ip = vxl->vtep_ip;
+ zl3vni->vxlan_if = ifp;
+
+ /*
+ * we need to associate with SVI.
+ * we can associate with svi-if only after association
+ * with vxlan-intf is complete
+ */
+ zl3vni->svi_if = zl3vni_map_to_svi_if(zl3vni);
+
+ /* Associate l3vni to mac-vlan and extract VRR MAC */
+ zl3vni->mac_vlan_if = zl3vni_map_to_mac_vlan_if(zl3vni);
+
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug(
+ "create l3vni %u svi_if %s mac_vlan_if %s", vni,
+ zl3vni->svi_if ? zl3vni->svi_if->name : "NIL",
+ zl3vni->mac_vlan_if ? zl3vni->mac_vlan_if->name
+ : "NIL");
+
+ if (is_l3vni_oper_up(zl3vni))
+ zebra_vxlan_process_l3vni_oper_up(zl3vni);
+
+ } else {
+ struct interface *vlan_if = NULL;
+
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug(
+ "Create L2-VNI hash for intf %s(%u) L2-VNI %u local IP %pI4",
+ ifp->name, ifp->ifindex, vni, &vxl->vtep_ip);
+
+ /*
+ * EVPN hash entry is expected to exist, if the BGP process is
+ * killed
+ */
+ zevpn = zebra_evpn_lookup(vni);
+ if (zevpn) {
+ zlog_debug(
+ "EVPN hash already present for IF %s(%u) L2-VNI %u",
+ ifp->name, ifp->ifindex, vni);
+
+ /*
+ * Inform BGP if intf is up and mapped to
+ * bridge.
+ */
+ if (if_is_operative(ifp) && zif->brslave_info.br_if)
+ zebra_evpn_send_add_to_client(zevpn);
+
+ /* Send Local MAC-entries to client */
+ zebra_evpn_send_mac_list_to_client(zevpn);
+
+ /* Send Loval Neighbor entries to client */
+ zebra_evpn_send_neigh_to_client(zevpn);
+ } else {
+ zevpn = zebra_evpn_add(vni);
+ if (!zevpn) {
+ zlog_debug(
+ "Failed to add EVPN hash, IF %s(%u) L2-VNI %u",
+ ifp->name, ifp->ifindex, vni);
+ return 0;
+ }
+
+ if (zevpn->local_vtep_ip.s_addr !=
+ vxl->vtep_ip.s_addr ||
+ zevpn->mcast_grp.s_addr != vnip->mcast_grp.s_addr) {
+ zebra_vxlan_sg_deref(zevpn->local_vtep_ip,
+ zevpn->mcast_grp);
+ zebra_vxlan_sg_ref(vxl->vtep_ip,
+ vnip->mcast_grp);
+ zevpn->local_vtep_ip = vxl->vtep_ip;
+ zevpn->mcast_grp = vnip->mcast_grp;
+ /* on local vtep-ip check if ES
+ * orig-ip needs to be updated
+ */
+ zebra_evpn_es_set_base_evpn(zevpn);
+ }
+ zevpn_vxlan_if_set(zevpn, ifp, true /* set */);
+ br_if = zif->brslave_info.br_if;
+ zevpn_bridge_if_set(zevpn, br_if, true /* set */);
+ vlan_if = zvni_map_to_svi(vnip->access_vlan, br_if);
+ if (vlan_if) {
+ zevpn->vid = vnip->access_vlan;
+ zevpn->svi_if = vlan_if;
+ zevpn->vrf_id = vlan_if->vrf->vrf_id;
+ zl3vni = zl3vni_from_vrf(vlan_if->vrf->vrf_id);
+ if (zl3vni)
+ listnode_add_sort(zl3vni->l2vnis,
+ zevpn);
+ }
+
+ /*
+ * Inform BGP if intf is up and mapped to
+ * bridge.
+ */
+ if (if_is_operative(ifp) && zif->brslave_info.br_if)
+ zebra_evpn_send_add_to_client(zevpn);
+ }
+ }
+
+ return 0;
+}
+
static int zevpn_build_hash_table_zns(struct ns *ns,
void *param_in __attribute__((unused)),
void **param_out __attribute__((unused)))
@@ -938,9 +1103,6 @@ static int zevpn_build_hash_table_zns(struct ns *ns,
/* Walk VxLAN interfaces and create EVPN hash. */
for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) {
- vni_t vni;
- struct zebra_evpn *zevpn = NULL;
- struct zebra_l3vni *zl3vni = NULL;
struct zebra_if *zif;
struct zebra_l2info_vxlan *vxl;
@@ -952,126 +1114,23 @@ static int zevpn_build_hash_table_zns(struct ns *ns,
continue;
vxl = &zif->l2info.vxl;
- vni = vxl->vni;
/* link of VXLAN interface should be in zebra_evpn_vrf */
if (zvrf->zns->ns_id != vxl->link_nsid) {
if (IS_ZEBRA_DEBUG_VXLAN)
zlog_debug(
- "Intf %s(%u) VNI %u, link not in same "
+ "Intf %s(%u) link not in same "
"namespace than BGP EVPN core instance ",
- ifp->name, ifp->ifindex, vni);
+ ifp->name, ifp->ifindex);
continue;
}
- /* L3-VNI and L2-VNI are handled seperately */
- zl3vni = zl3vni_lookup(vni);
- if (zl3vni) {
-
- if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug(
- "create L3-VNI hash for Intf %s(%u) L3-VNI %u",
- ifp->name, ifp->ifindex, vni);
-
- /* associate with vxlan_if */
- zl3vni->local_vtep_ip = vxl->vtep_ip;
- zl3vni->vxlan_if = ifp;
-
- /*
- * we need to associate with SVI.
- * we can associate with svi-if only after association
- * with vxlan-intf is complete
- */
- zl3vni->svi_if = zl3vni_map_to_svi_if(zl3vni);
-
- /* Associate l3vni to mac-vlan and extract VRR MAC */
- zl3vni->mac_vlan_if = zl3vni_map_to_mac_vlan_if(zl3vni);
-
- if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug("create l3vni %u svi_if %s mac_vlan_if %s",
- vni, zl3vni->svi_if ? zl3vni->svi_if->name
- : "NIL",
- zl3vni->mac_vlan_if ?
- zl3vni->mac_vlan_if->name : "NIL");
-
- if (is_l3vni_oper_up(zl3vni))
- zebra_vxlan_process_l3vni_oper_up(zl3vni);
- } else {
- struct interface *vlan_if = NULL;
-
- if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug(
- "Create L2-VNI hash for intf %s(%u) L2-VNI %u local IP %pI4",
- ifp->name, ifp->ifindex, vni,
- &vxl->vtep_ip);
-
- /* EVPN hash entry is expected to exist, if the BGP process is killed */
- zevpn = zebra_evpn_lookup(vni);
- if (zevpn) {
- zlog_debug(
- "EVPN hash already present for IF %s(%u) L2-VNI %u",
- ifp->name, ifp->ifindex, vni);
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug("Building vni table for %s-if %s",
+ IS_ZEBRA_VXLAN_IF_VNI(zif) ? "vni" : "svd",
+ ifp->name);
- /*
- * Inform BGP if intf is up and mapped to
- * bridge.
- */
- if (if_is_operative(ifp) &&
- zif->brslave_info.br_if)
- zebra_evpn_send_add_to_client(zevpn);
-
- /* Send Local MAC-entries to client */
- zebra_evpn_send_mac_list_to_client(zevpn);
-
- /* Send Loval Neighbor entries to client */
- zebra_evpn_send_neigh_to_client(zevpn);
- } else {
- zevpn = zebra_evpn_add(vni);
- if (!zevpn) {
- zlog_debug(
- "Failed to add EVPN hash, IF %s(%u) L2-VNI %u",
- ifp->name, ifp->ifindex, vni);
- return NS_WALK_CONTINUE;
- }
-
- if (zevpn->local_vtep_ip.s_addr !=
- vxl->vtep_ip.s_addr ||
- zevpn->mcast_grp.s_addr !=
- vxl->mcast_grp.s_addr) {
- zebra_vxlan_sg_deref(
- zevpn->local_vtep_ip,
- zevpn->mcast_grp);
- zebra_vxlan_sg_ref(vxl->vtep_ip,
- vxl->mcast_grp);
- zevpn->local_vtep_ip = vxl->vtep_ip;
- zevpn->mcast_grp = vxl->mcast_grp;
- /* on local vtep-ip check if ES
- * orig-ip needs to be updated
- */
- zebra_evpn_es_set_base_evpn(zevpn);
- }
- zevpn_vxlan_if_set(zevpn, ifp, true /* set */);
- vlan_if = zvni_map_to_svi(
- vxl->access_vlan,
- zif->brslave_info.br_if);
- if (vlan_if) {
- zevpn->svi_if = vlan_if;
- zevpn->vrf_id = vlan_if->vrf->vrf_id;
- zl3vni = zl3vni_from_vrf(
- vlan_if->vrf->vrf_id);
- if (zl3vni)
- listnode_add_sort(
- zl3vni->l2vnis, zevpn);
- }
-
- /*
- * Inform BGP if intf is up and mapped to
- * bridge.
- */
- if (if_is_operative(ifp) &&
- zif->brslave_info.br_if)
- zebra_evpn_send_add_to_client(zevpn);
- }
- }
+ zebra_vxlan_if_vni_iterate(zif, zevpn_build_vni_hash_table,
+ NULL);
}
return NS_WALK_CONTINUE;
}
@@ -1225,7 +1284,7 @@ static int zl3vni_rmac_install(struct zebra_l3vni *zl3vni,
struct zebra_mac *zrmac)
{
const struct zebra_if *zif = NULL, *br_zif = NULL;
- const struct zebra_l2info_vxlan *vxl = NULL;
+ const struct zebra_vxlan_vni *vni;
const struct interface *br_ifp;
enum zebra_dplane_result res;
vlanid_t vid;
@@ -1242,17 +1301,17 @@ static int zl3vni_rmac_install(struct zebra_l3vni *zl3vni,
if (br_ifp == NULL)
return -1;
- vxl = &zif->l2info.vxl;
+ vni = zebra_vxlan_if_vni_find(zif, zl3vni->vni);
br_zif = (const struct zebra_if *)br_ifp->info;
if (IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(br_zif))
- vid = vxl->access_vlan;
+ vid = vni->access_vlan;
else
vid = 0;
- res = dplane_rem_mac_add(zl3vni->vxlan_if, br_ifp, vid,
- &zrmac->macaddr, zrmac->fwd_info.r_vtep_ip, 0, 0,
+ res = dplane_rem_mac_add(zl3vni->vxlan_if, br_ifp, vid, &zrmac->macaddr,
+ vni->vni, zrmac->fwd_info.r_vtep_ip, 0, 0,
false /*was_static*/);
if (res != ZEBRA_DPLANE_REQUEST_FAILURE)
return 0;
@@ -1267,7 +1326,7 @@ static int zl3vni_rmac_uninstall(struct zebra_l3vni *zl3vni,
struct zebra_mac *zrmac)
{
const struct zebra_if *zif = NULL, *br_zif;
- const struct zebra_l2info_vxlan *vxl = NULL;
+ const struct zebra_vxlan_vni *vni;
const struct interface *br_ifp;
vlanid_t vid;
enum zebra_dplane_result res;
@@ -1292,16 +1351,16 @@ static int zl3vni_rmac_uninstall(struct zebra_l3vni *zl3vni,
if (br_ifp == NULL)
return -1;
- vxl = &zif->l2info.vxl;
+ vni = zebra_vxlan_if_vni_find(zif, zl3vni->vni);
br_zif = (const struct zebra_if *)br_ifp->info;
if (IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(br_zif))
- vid = vxl->access_vlan;
+ vid = vni->access_vlan;
else
vid = 0;
- res = dplane_rem_mac_del(zl3vni->vxlan_if, br_ifp, vid,
- &zrmac->macaddr, zrmac->fwd_info.r_vtep_ip);
+ res = dplane_rem_mac_del(zl3vni->vxlan_if, br_ifp, vid, &zrmac->macaddr,
+ vni->vni, zrmac->fwd_info.r_vtep_ip);
if (res != ZEBRA_DPLANE_REQUEST_FAILURE)
return 0;
else
@@ -1424,21 +1483,41 @@ static void zl3vni_remote_rmac_del(struct zebra_l3vni *zl3vni,
}
/*
- * Look up nh hash entry on a l3-vni.
+ * Common code for look up of nh hash entry.
*/
-static struct zebra_neigh *zl3vni_nh_lookup(struct zebra_l3vni *zl3vni,
- const struct ipaddr *ip)
+static struct zebra_neigh *_nh_lookup(struct zebra_l3vni *zl3vni,
+ const struct ipaddr *ip)
{
struct zebra_neigh tmp;
struct zebra_neigh *n;
memset(&tmp, 0, sizeof(tmp));
memcpy(&tmp.ip, ip, sizeof(struct ipaddr));
- n = hash_lookup(zl3vni->nh_table, &tmp);
+
+ if (zl3vni)
+ n = hash_lookup(zl3vni->nh_table, &tmp);
+ else
+ n = hash_lookup(svd_nh_table, &tmp);
return n;
}
+/*
+ * Look up nh hash entry on a l3-vni.
+ */
+static struct zebra_neigh *zl3vni_nh_lookup(struct zebra_l3vni *zl3vni,
+ const struct ipaddr *ip)
+{
+ return _nh_lookup(zl3vni, ip);
+}
+
+/*
+ * Look up nh hash entry on a SVD.
+ */
+static struct zebra_neigh *svd_nh_lookup(const struct ipaddr *ip)
+{
+ return _nh_lookup(NULL, ip);
+}
/*
* Callback to allocate NH hash entry on L3-VNI.
@@ -1455,18 +1534,24 @@ static void *zl3vni_nh_alloc(void *p)
}
/*
- * Add neighbor entry.
+ * Common code for neigh add.
*/
-static struct zebra_neigh *zl3vni_nh_add(struct zebra_l3vni *zl3vni,
- const struct ipaddr *ip,
- const struct ethaddr *mac)
+static struct zebra_neigh *_nh_add(struct zebra_l3vni *zl3vni,
+ const struct ipaddr *ip,
+ const struct ethaddr *mac)
{
struct zebra_neigh tmp_n;
struct zebra_neigh *n = NULL;
memset(&tmp_n, 0, sizeof(tmp_n));
memcpy(&tmp_n.ip, ip, sizeof(struct ipaddr));
- n = hash_get(zl3vni->nh_table, &tmp_n, zl3vni_nh_alloc);
+
+ if (zl3vni)
+ n = hash_get(zl3vni->nh_table, &tmp_n, zl3vni_nh_alloc);
+ else
+ n = hash_get(svd_nh_table, &tmp_n, zl3vni_nh_alloc);
+
+ assert(n);
RB_INIT(host_rb_tree_entry, &n->host_rb);
@@ -1478,6 +1563,16 @@ static struct zebra_neigh *zl3vni_nh_add(struct zebra_l3vni *zl3vni,
}
/*
+ * Add neighbor entry.
+ */
+static struct zebra_neigh *zl3vni_nh_add(struct zebra_l3vni *zl3vni,
+ const struct ipaddr *ip,
+ const struct ethaddr *mac)
+{
+ return _nh_add(zl3vni, ip, mac);
+}
+
+/*
* Delete neighbor entry.
*/
static int zl3vni_nh_del(struct zebra_l3vni *zl3vni, struct zebra_neigh *n)
@@ -1499,14 +1594,38 @@ static int zl3vni_nh_del(struct zebra_l3vni *zl3vni, struct zebra_neigh *n)
}
/*
- * Install remote nh as neigh into the kernel.
+ * Add Single VXlan Device neighbor entry.
*/
-static int zl3vni_nh_install(struct zebra_l3vni *zl3vni, struct zebra_neigh *n)
+static struct zebra_neigh *svd_nh_add(const struct ipaddr *ip,
+ const struct ethaddr *mac)
+{
+ return _nh_add(NULL, ip, mac);
+}
+
+/*
+ * Del Single VXlan Device neighbor entry.
+ */
+static int svd_nh_del(struct zebra_neigh *n)
+{
+ if (n->refcnt > 0)
+ return -1;
+
+ hash_release(svd_nh_table, n);
+ XFREE(MTYPE_L3NEIGH, n);
+
+ return 0;
+}
+
+/*
+ * Common code to install remote nh as neigh into the kernel.
+ */
+static int _nh_install(struct zebra_l3vni *zl3vni, struct interface *ifp,
+ struct zebra_neigh *n)
{
uint8_t flags;
int ret = 0;
- if (!is_l3vni_oper_up(zl3vni))
+ if (zl3vni && !is_l3vni_oper_up(zl3vni))
return -1;
if (!(n->flags & ZEBRA_NEIGH_REMOTE)
@@ -1517,31 +1636,63 @@ static int zl3vni_nh_install(struct zebra_l3vni *zl3vni, struct zebra_neigh *n)
if (n->flags & ZEBRA_NEIGH_ROUTER_FLAG)
flags |= DPLANE_NTF_ROUTER;
- dplane_rem_neigh_add(zl3vni->svi_if, &n->ip, &n->emac, flags,
- false /*was_static*/);
+ dplane_rem_neigh_add(ifp, &n->ip, &n->emac, flags,
+ false /*was_static*/);
return ret;
}
/*
- * Uninstall remote nh from the kernel.
+ * Common code to uninstall remote nh from the kernel.
*/
-static int zl3vni_nh_uninstall(struct zebra_l3vni *zl3vni,
- struct zebra_neigh *n)
+static int _nh_uninstall(struct interface *ifp, struct zebra_neigh *n)
{
if (!(n->flags & ZEBRA_NEIGH_REMOTE)
|| !(n->flags & ZEBRA_NEIGH_REMOTE_NH))
return 0;
- if (!zl3vni->svi_if || !if_is_operative(zl3vni->svi_if))
+ if (!ifp || !if_is_operative(ifp))
return 0;
- dplane_rem_neigh_delete(zl3vni->svi_if, &n->ip);
+ dplane_rem_neigh_delete(ifp, &n->ip);
return 0;
}
-/* add remote vtep as a neigh entry */
+/*
+ * Install remote nh as neigh into the kernel.
+ */
+static int zl3vni_nh_install(struct zebra_l3vni *zl3vni, struct zebra_neigh *n)
+{
+ return _nh_install(zl3vni, zl3vni->svi_if, n);
+}
+
+/*
+ * Uninstall remote nh from the kernel.
+ */
+static int zl3vni_nh_uninstall(struct zebra_l3vni *zl3vni,
+ struct zebra_neigh *n)
+{
+ return _nh_uninstall(zl3vni->svi_if, n);
+}
+
+/*
+ * Install SVD remote nh as neigh into the kernel.
+ */
+static int svd_nh_install(struct zebra_l3vni *zl3vni, struct zebra_neigh *n)
+{
+ return _nh_install(zl3vni, zl3vni->vxlan_if, n);
+}
+
+/*
+ * Uninstall SVD remote nh from the kernel.
+ */
+static int svd_nh_uninstall(struct zebra_l3vni *zl3vni, struct zebra_neigh *n)
+{
+ return _nh_uninstall(zl3vni->vxlan_if, n);
+}
+
+/* Add remote vtep as a neigh entry */
static int zl3vni_remote_nh_add(struct zebra_l3vni *zl3vni,
const struct ipaddr *vtep_ip,
const struct ethaddr *rmac,
@@ -1579,7 +1730,7 @@ static int zl3vni_remote_nh_add(struct zebra_l3vni *zl3vni,
return 0;
}
-/* handle nh neigh delete */
+/* Del remote vtep as a neigh entry */
static void zl3vni_remote_nh_del(struct zebra_l3vni *zl3vni,
struct zebra_neigh *nh,
struct prefix *host_prefix)
@@ -1595,6 +1746,91 @@ static void zl3vni_remote_nh_del(struct zebra_l3vni *zl3vni,
}
}
+/* Add remote vtep as a SVD neigh entry */
+static int svd_remote_nh_add(struct zebra_l3vni *zl3vni,
+ const struct ipaddr *vtep_ip,
+ const struct ethaddr *rmac,
+ const struct prefix *host_prefix)
+{
+ struct zebra_neigh *nh = NULL;
+
+ /* SVD backed VNI check */
+ if (!IS_ZL3VNI_SVD_BACKED(zl3vni))
+ return 0;
+
+ /* Create the SVD next hop entry, or update its mac, if necessary. */
+ nh = svd_nh_lookup(vtep_ip);
+ if (!nh) {
+ nh = svd_nh_add(vtep_ip, rmac);
+ if (!nh) {
+ zlog_debug(
+ "Failed to add NH %pIA as SVD Neigh (RMAC %pEA prefix %pFX)",
+ vtep_ip, rmac, host_prefix);
+ return -1;
+ }
+
+ } else if (memcmp(&nh->emac, rmac, ETH_ALEN) != 0) {
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug(
+ "SVD RMAC change(%pEA --> %pEA) for nexthop %pIA, prefix %pFX",
+ &nh->emac, rmac, vtep_ip, host_prefix);
+
+ memcpy(&nh->emac, rmac, ETH_ALEN);
+ /* install (update) the nh neigh in kernel */
+ svd_nh_install(zl3vni, nh);
+
+ /* Don't increment refcnt change */
+ return 0;
+ }
+
+ nh->refcnt++;
+
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug("SVD NH ADD refcnt (%u) for nexthop %pIA",
+ nh->refcnt, vtep_ip);
+
+ /*
+ * Install the nh neigh in kernel if this is the first time we
+ * have seen it.
+ */
+ if (nh->refcnt == 1)
+ svd_nh_install(zl3vni, nh);
+
+ return 0;
+}
+
+/* Del remote vtep as a SVD neigh entry */
+static int svd_remote_nh_del(struct zebra_l3vni *zl3vni,
+ const struct ipaddr *vtep_ip)
+{
+ struct zebra_neigh *nh;
+
+ /* SVD backed VNI check */
+ if (!IS_ZL3VNI_SVD_BACKED(zl3vni))
+ return 0;
+
+ nh = svd_nh_lookup(vtep_ip);
+ if (!nh) {
+ zlog_debug("Failed to del NH %pIA as SVD Neigh", vtep_ip);
+
+ return -1;
+ }
+
+ nh->refcnt--;
+
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug("SVD NH Del refcnt (%u) for nexthop %pIA",
+ nh->refcnt, vtep_ip);
+
+ /* Last refcnt on NH, remove it completely. */
+ if (nh->refcnt == 0) {
+ svd_nh_uninstall(zl3vni, nh);
+ svd_nh_del(nh);
+ }
+
+ return 0;
+}
+
/* handle neigh update from kernel - the only thing of interest is to
* readd stale entries.
*/
@@ -1756,7 +1992,8 @@ static int zl3vni_map_to_vxlan_if_ns(struct ns *ns,
for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) {
struct zebra_if *zif = NULL;
- struct zebra_l2info_vxlan *vxl = NULL;
+ struct zebra_l2info_vxlan *vxl;
+ struct zebra_vxlan_vni *vni = NULL;
ifp = (struct interface *)rn->info;
if (!ifp)
@@ -1767,7 +2004,8 @@ static int zl3vni_map_to_vxlan_if_ns(struct ns *ns,
continue;
vxl = &zif->l2info.vxl;
- if (vxl->vni != zl3vni->vni)
+ vni = zebra_vxlan_if_vni_find(zif, zl3vni->vni);
+ if (!vni || vni->vni != zl3vni->vni)
continue;
/* link of VXLAN interface should be in zebra_evpn_vrf */
@@ -1776,12 +2014,12 @@ static int zl3vni_map_to_vxlan_if_ns(struct ns *ns,
zlog_debug(
"Intf %s(%u) VNI %u, link not in same "
"namespace than BGP EVPN core instance ",
- ifp->name, ifp->ifindex, vxl->vni);
+ ifp->name, ifp->ifindex, vni->vni);
continue;
}
- zl3vni->local_vtep_ip = vxl->vtep_ip;
+ zl3vni->local_vtep_ip = zif->l2info.vxl.vtep_ip;
*_pifp = (void *)ifp;
return NS_WALK_STOP;
}
@@ -1804,7 +2042,7 @@ struct interface *zl3vni_map_to_vxlan_if(struct zebra_l3vni *zl3vni)
struct interface *zl3vni_map_to_svi_if(struct zebra_l3vni *zl3vni)
{
struct zebra_if *zif = NULL; /* zebra_if for vxlan_if */
- struct zebra_l2info_vxlan *vxl = NULL; /* l2 info for vxlan_if */
+ struct zebra_vxlan_vni *vni = NULL; /* vni info in vxlan_if */
if (!zl3vni)
return NULL;
@@ -1816,9 +2054,11 @@ struct interface *zl3vni_map_to_svi_if(struct zebra_l3vni *zl3vni)
if (!zif)
return NULL;
- vxl = &zif->l2info.vxl;
+ vni = zebra_vxlan_if_vni_find(zif, zl3vni->vni);
+ if (!vni)
+ return NULL;
- return zvni_map_to_svi(vxl->access_vlan, zif->brslave_info.br_if);
+ return zvni_map_to_svi(vni->access_vlan, zif->brslave_info.br_if);
}
struct interface *zl3vni_map_to_mac_vlan_if(struct zebra_l3vni *zl3vni)
@@ -1853,6 +2093,8 @@ struct zebra_l3vni *zl3vni_from_vrf(vrf_id_t vrf_id)
static int zl3vni_from_svi_ns(struct ns *ns, void *_in_param, void **_p_zl3vni)
{
+ int found = 0;
+ vni_t vni_id = 0;
struct zebra_ns *zns = ns->info;
struct zebra_l3vni **p_zl3vni = (struct zebra_l3vni **)_p_zl3vni;
struct zebra_from_svi_param *in_param =
@@ -1860,33 +2102,46 @@ static int zl3vni_from_svi_ns(struct ns *ns, void *_in_param, void **_p_zl3vni)
struct route_node *rn = NULL;
struct interface *tmp_if = NULL;
struct zebra_if *zif = NULL;
- struct zebra_l2info_vxlan *vxl = NULL;
+ struct zebra_if *br_zif = NULL;
assert(in_param && p_zl3vni);
- /* loop through all vxlan-interface */
- for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) {
- tmp_if = (struct interface *)rn->info;
- if (!tmp_if)
- continue;
- zif = tmp_if->info;
- if (!zif || zif->zif_type != ZEBRA_IF_VXLAN)
- continue;
- if (!if_is_operative(tmp_if))
- continue;
- vxl = &zif->l2info.vxl;
+ br_zif = in_param->br_if->info;
+ assert(br_zif);
- if (zif->brslave_info.br_if != in_param->br_if)
- continue;
+ if (in_param->bridge_vlan_aware) {
+ vni_id = zebra_l2_bridge_if_vni_find(br_zif, in_param->vid);
+ if (vni_id)
+ found = 1;
+ } else {
+ /* loop through all vxlan-interface */
+ for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) {
+ tmp_if = (struct interface *)rn->info;
+ if (!tmp_if)
+ continue;
+ zif = tmp_if->info;
+ if (!zif || zif->zif_type != ZEBRA_IF_VXLAN)
+ continue;
+ if (!if_is_operative(tmp_if))
+ continue;
- if (!in_param->bridge_vlan_aware
- || vxl->access_vlan == in_param->vid) {
- *p_zl3vni = zl3vni_lookup(vxl->vni);
- return NS_WALK_STOP;
+ if (zif->brslave_info.br_if != in_param->br_if)
+ continue;
+
+ vni_id = zebra_vxlan_if_access_vlan_vni_find(
+ zif, in_param->br_if);
+ if (vni_id) {
+ found = 1;
+ break;
+ }
}
}
- return NS_WALK_CONTINUE;
+ if (!found)
+ return NS_WALK_CONTINUE;
+
+ *p_zl3vni = zl3vni_lookup(vni_id);
+ return NS_WALK_STOP;
}
/*
@@ -1898,7 +2153,6 @@ static struct zebra_l3vni *zl3vni_from_svi(struct interface *ifp,
{
struct zebra_l3vni *zl3vni = NULL;
struct zebra_if *zif = NULL;
- struct zebra_l2info_bridge *br = NULL;
struct zebra_from_svi_param in_param = {};
struct zebra_l3vni **p_zl3vni;
@@ -1913,8 +2167,7 @@ static struct zebra_l3vni *zl3vni_from_svi(struct interface *ifp,
/* Determine if bridge is VLAN-aware or not */
zif = br_if->info;
assert(zif);
- br = &zif->l2info.br;
- in_param.bridge_vlan_aware = br->vlan_aware;
+ in_param.bridge_vlan_aware = IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(zif);
if (in_param.bridge_vlan_aware) {
struct zebra_l2info_vlan *vl;
@@ -2061,7 +2314,7 @@ static int zl3vni_send_del_to_client(struct zebra_l3vni *zl3vni)
return zserv_send_message(client, s);
}
-static void zebra_vxlan_process_l3vni_oper_up(struct zebra_l3vni *zl3vni)
+void zebra_vxlan_process_l3vni_oper_up(struct zebra_l3vni *zl3vni)
{
if (!zl3vni)
return;
@@ -2070,7 +2323,7 @@ static void zebra_vxlan_process_l3vni_oper_up(struct zebra_l3vni *zl3vni)
zl3vni_send_add_to_client(zl3vni);
}
-static void zebra_vxlan_process_l3vni_oper_down(struct zebra_l3vni *zl3vni)
+void zebra_vxlan_process_l3vni_oper_down(struct zebra_l3vni *zl3vni)
{
if (!zl3vni)
return;
@@ -2142,6 +2395,7 @@ static int zebra_vxlan_handle_vni_transition(struct zebra_vrf *zvrf, vni_t vni,
struct route_node *rn;
struct interface *ifp;
struct zebra_if *zif;
+ struct zebra_vxlan_vni *vnip;
struct zebra_l2info_vxlan *vxl;
struct interface *vlan_if;
bool found = false;
@@ -2161,7 +2415,8 @@ static int zebra_vxlan_handle_vni_transition(struct zebra_vrf *zvrf, vni_t vni,
continue;
vxl = &zif->l2info.vxl;
- if (vxl->vni == vni) {
+ vnip = zebra_vxlan_if_vni_find(zif, vni);
+ if (vnip) {
found = true;
break;
}
@@ -2183,7 +2438,7 @@ static int zebra_vxlan_handle_vni_transition(struct zebra_vrf *zvrf, vni_t vni,
zevpn = zebra_evpn_add(vni);
/* Find bridge interface for the VNI */
- vlan_if = zvni_map_to_svi(vxl->access_vlan,
+ vlan_if = zvni_map_to_svi(vnip->access_vlan,
zif->brslave_info.br_if);
if (vlan_if) {
zevpn->vrf_id = vlan_if->vrf->vrf_id;
@@ -2282,6 +2537,9 @@ void zebra_vxlan_evpn_vrf_route_add(vrf_id_t vrf_id, const struct ethaddr *rmac,
*/
zl3vni_remote_nh_add(zl3vni, vtep_ip, rmac, host_prefix);
+ /* Add SVD next hop neighbor */
+ svd_remote_nh_add(zl3vni, vtep_ip, rmac, host_prefix);
+
/*
* if the remote vtep is a ipv4 mapped ipv6 address convert it to ipv4
* address. Rmac is programmed against the ipv4 vtep because we only
@@ -2325,6 +2583,9 @@ void zebra_vxlan_evpn_vrf_route_del(vrf_id_t vrf_id,
/* delete the next hop entry */
zl3vni_remote_nh_del(zl3vni, nh, host_prefix);
+ /* Delete SVD next hop entry */
+ svd_remote_nh_del(zl3vni, vtep_ip);
+
/* delete the rmac entry */
if (zrmac)
zl3vni_remote_rmac_del(zl3vni, zrmac, vtep_ip);
@@ -2454,22 +2715,29 @@ void zebra_vxlan_print_specific_nh_l3vni(struct vty *vty, vni_t l3vni,
if (use_json)
json = json_object_new_object();
- zl3vni = zl3vni_lookup(l3vni);
- if (!zl3vni) {
- if (use_json)
- vty_out(vty, "{}\n");
- else
- vty_out(vty, "%% L3-VNI %u does not exist\n", l3vni);
- return;
+ /* If vni=0 passed, assume svd lookup */
+ if (!l3vni)
+ n = svd_nh_lookup(ip);
+ else {
+ zl3vni = zl3vni_lookup(l3vni);
+ if (!zl3vni) {
+ if (use_json)
+ vty_out(vty, "{}\n");
+ else
+ vty_out(vty, "%% L3-VNI %u does not exist\n",
+ l3vni);
+ return;
+ }
+
+ n = zl3vni_nh_lookup(zl3vni, ip);
}
- n = zl3vni_nh_lookup(zl3vni, ip);
if (!n) {
if (use_json)
vty_out(vty, "{}\n");
else
vty_out(vty,
- "%% Requested next-hop not present for L3-VNI %u",
+ "%% Requested next-hop not present for L3-VNI %u\n",
l3vni);
return;
}
@@ -2480,26 +2748,14 @@ void zebra_vxlan_print_specific_nh_l3vni(struct vty *vty, vni_t l3vni,
vty_json(vty, json);
}
-void zebra_vxlan_print_nh_l3vni(struct vty *vty, vni_t l3vni, bool use_json)
+static void l3vni_print_nh_table(struct hash *nh_table, struct vty *vty,
+ bool use_json)
{
uint32_t num_nh;
struct nh_walk_ctx wctx;
json_object *json = NULL;
- struct zebra_l3vni *zl3vni = NULL;
-
- if (!is_evpn_enabled())
- return;
-
- zl3vni = zl3vni_lookup(l3vni);
- if (!zl3vni) {
- if (use_json)
- vty_out(vty, "{}\n");
- else
- vty_out(vty, "%% L3-VNI %u does not exist\n", l3vni);
- return;
- }
- num_nh = hashcount(zl3vni->nh_table);
+ num_nh = hashcount(nh_table);
if (!num_nh)
return;
@@ -2515,12 +2771,45 @@ void zebra_vxlan_print_nh_l3vni(struct vty *vty, vni_t l3vni, bool use_json)
} else
json_object_int_add(json, "numNextHops", num_nh);
- hash_iterate(zl3vni->nh_table, zl3vni_print_nh_hash, &wctx);
+ hash_iterate(nh_table, zl3vni_print_nh_hash, &wctx);
if (use_json)
vty_json(vty, json);
}
+void zebra_vxlan_print_nh_l3vni(struct vty *vty, vni_t l3vni, bool use_json)
+{
+ struct zebra_l3vni *zl3vni = NULL;
+
+ if (!is_evpn_enabled()) {
+ if (use_json)
+ vty_out(vty, "{}\n");
+ return;
+ }
+
+ zl3vni = zl3vni_lookup(l3vni);
+ if (!zl3vni) {
+ if (use_json)
+ vty_out(vty, "{}\n");
+ else
+ vty_out(vty, "%% L3-VNI %u does not exist\n", l3vni);
+ return;
+ }
+
+ l3vni_print_nh_table(zl3vni->nh_table, vty, use_json);
+}
+
+void zebra_vxlan_print_nh_svd(struct vty *vty, bool use_json)
+{
+ if (!is_evpn_enabled()) {
+ if (use_json)
+ vty_out(vty, "{}\n");
+ return;
+ }
+
+ l3vni_print_nh_table(svd_nh_table, vty, use_json);
+}
+
void zebra_vxlan_print_nh_all_l3vni(struct vty *vty, bool use_json)
{
json_object *json = NULL;
@@ -3953,20 +4242,17 @@ stream_failure:
/*
* Handle remote vtep delete by kernel; re-add the vtep if we have it
*/
-int zebra_vxlan_check_readd_vtep(struct interface *ifp,
+int zebra_vxlan_check_readd_vtep(struct interface *ifp, vni_t vni,
struct in_addr vtep_ip)
{
struct zebra_if *zif;
struct zebra_vrf *zvrf = NULL;
- struct zebra_l2info_vxlan *vxl;
- vni_t vni;
struct zebra_evpn *zevpn = NULL;
struct zebra_vtep *zvtep = NULL;
+ struct zebra_vxlan_vni *vnip;
zif = ifp->info;
assert(zif);
- vxl = &zif->l2info.vxl;
- vni = vxl->vni;
/* If EVPN is not enabled, nothing to do. */
if (!is_evpn_enabled())
@@ -3977,6 +4263,10 @@ int zebra_vxlan_check_readd_vtep(struct interface *ifp,
if (!zvrf)
return -1;
+ vnip = zebra_vxlan_if_vni_find(zif, vni);
+ if (!vnip)
+ return 0;
+
/* Locate hash entry; it is expected to exist. */
zevpn = zebra_evpn_lookup(vni);
if (!zevpn)
@@ -4004,18 +4294,14 @@ int zebra_vxlan_check_readd_vtep(struct interface *ifp,
static int zebra_vxlan_check_del_local_mac(struct interface *ifp,
struct interface *br_if,
struct ethaddr *macaddr,
- vlanid_t vid)
+ vlanid_t vid, vni_t vni)
{
struct zebra_if *zif;
- struct zebra_l2info_vxlan *vxl;
- vni_t vni;
struct zebra_evpn *zevpn;
struct zebra_mac *mac;
zif = ifp->info;
assert(zif);
- vxl = &zif->l2info.vxl;
- vni = vxl->vni;
/* Check if EVPN is enabled. */
if (!is_evpn_enabled())
@@ -4067,7 +4353,8 @@ static int zebra_vxlan_check_del_local_mac(struct interface *ifp,
int zebra_vxlan_dp_network_mac_add(struct interface *ifp,
struct interface *br_if,
struct ethaddr *macaddr, vlanid_t vid,
- uint32_t nhg_id, bool sticky, bool dp_static)
+ vni_t vni, uint32_t nhg_id, bool sticky,
+ bool dp_static)
{
struct zebra_evpn_es *es;
struct interface *acc_ifp;
@@ -4083,7 +4370,8 @@ int zebra_vxlan_dp_network_mac_add(struct interface *ifp,
}
/* Get vxlan's vid for netlink message has no it. */
- vid = ((struct zebra_if *)ifp->info)->l2info.vxl.access_vlan;
+ vid = ((struct zebra_if *)ifp->info)
+ ->l2info.vxl.vni_info.vni.access_vlan;
/* if remote mac delete the local entry */
if (!nhg_id || !zebra_evpn_nhg_is_local_es(nhg_id, &es)
@@ -4091,8 +4379,8 @@ int zebra_vxlan_dp_network_mac_add(struct interface *ifp,
if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_MAC)
zlog_debug("dpAdd remote MAC %pEA VID %u", macaddr,
vid);
- return zebra_vxlan_check_del_local_mac(ifp, br_if, macaddr,
- vid);
+ return zebra_vxlan_check_del_local_mac(ifp, br_if, macaddr, vid,
+ vni);
}
/* If local MAC on a down local ES translate the network-mac-add
@@ -4113,19 +4401,16 @@ int zebra_vxlan_dp_network_mac_add(struct interface *ifp,
*/
int zebra_vxlan_dp_network_mac_del(struct interface *ifp,
struct interface *br_if,
- struct ethaddr *macaddr, vlanid_t vid)
+ struct ethaddr *macaddr, vlanid_t vid,
+ vni_t vni)
{
struct zebra_if *zif = NULL;
- struct zebra_l2info_vxlan *vxl = NULL;
- vni_t vni;
struct zebra_evpn *zevpn = NULL;
struct zebra_l3vni *zl3vni = NULL;
struct zebra_mac *mac = NULL;
zif = ifp->info;
assert(zif);
- vxl = &zif->l2info.vxl;
- vni = vxl->vni;
/* Check if EVPN is enabled. */
if (!is_evpn_enabled())
@@ -4804,507 +5089,6 @@ void zebra_vxlan_macvlan_up(struct interface *ifp)
}
}
-/*
- * Handle VxLAN interface down
- */
-int zebra_vxlan_if_down(struct interface *ifp)
-{
- vni_t vni;
- struct zebra_if *zif = NULL;
- struct zebra_l2info_vxlan *vxl = NULL;
- struct zebra_l3vni *zl3vni = NULL;
- struct zebra_evpn *zevpn;
-
- /* Check if EVPN is enabled. */
- if (!is_evpn_enabled())
- return 0;
-
- zif = ifp->info;
- assert(zif);
- vxl = &zif->l2info.vxl;
- vni = vxl->vni;
-
- zl3vni = zl3vni_lookup(vni);
- if (zl3vni) {
- /* process-if-down for l3-vni */
- if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug("Intf %s(%u) L3-VNI %u is DOWN", ifp->name,
- ifp->ifindex, vni);
-
- zebra_vxlan_process_l3vni_oper_down(zl3vni);
- } else {
- /* process if-down for l2-vni */
- if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug("Intf %s(%u) L2-VNI %u is DOWN", ifp->name,
- ifp->ifindex, vni);
-
- /* Locate hash entry; it is expected to exist. */
- zevpn = zebra_evpn_lookup(vni);
- if (!zevpn) {
- zlog_debug(
- "Failed to locate VNI hash at DOWN, IF %s(%u) VNI %u",
- ifp->name, ifp->ifindex, vni);
- return -1;
- }
-
- assert(zevpn->vxlan_if == ifp);
-
- /* remove from l3-vni list */
- zl3vni = zl3vni_from_vrf(zevpn->vrf_id);
- if (zl3vni)
- listnode_delete(zl3vni->l2vnis, zevpn);
-
- /* Delete this VNI from BGP. */
- zebra_evpn_send_del_to_client(zevpn);
-
- /* Free up all neighbors and MACs, if any. */
- zebra_evpn_neigh_del_all(zevpn, 1, 0, DEL_ALL_NEIGH);
- zebra_evpn_mac_del_all(zevpn, 1, 0, DEL_ALL_MAC);
-
- /* Free up all remote VTEPs, if any. */
- zebra_evpn_vtep_del_all(zevpn, 1);
- }
- return 0;
-}
-
-/*
- * Handle VxLAN interface up - update BGP if required.
- */
-int zebra_vxlan_if_up(struct interface *ifp)
-{
- vni_t vni;
- struct zebra_if *zif = NULL;
- struct zebra_l2info_vxlan *vxl = NULL;
- struct zebra_evpn *zevpn = NULL;
- struct zebra_l3vni *zl3vni = NULL;
-
- /* Check if EVPN is enabled. */
- if (!is_evpn_enabled())
- return 0;
-
- zif = ifp->info;
- assert(zif);
- vxl = &zif->l2info.vxl;
- vni = vxl->vni;
-
- zl3vni = zl3vni_lookup(vni);
- if (zl3vni) {
- /* we need to associate with SVI, if any, we can associate with
- * svi-if only after association with vxlan-intf is complete
- */
- zl3vni->svi_if = zl3vni_map_to_svi_if(zl3vni);
- zl3vni->mac_vlan_if = zl3vni_map_to_mac_vlan_if(zl3vni);
-
- if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug("Intf %s(%u) L3-VNI %u is UP svi_if %s mac_vlan_if %s"
- , ifp->name, ifp->ifindex, vni,
- zl3vni->svi_if ? zl3vni->svi_if->name : "NIL",
- zl3vni->mac_vlan_if ?
- zl3vni->mac_vlan_if->name : "NIL");
-
- if (is_l3vni_oper_up(zl3vni))
- zebra_vxlan_process_l3vni_oper_up(zl3vni);
- } else {
- /* Handle L2-VNI add */
- struct interface *vlan_if = NULL;
-
- if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug("Intf %s(%u) L2-VNI %u is UP", ifp->name,
- ifp->ifindex, vni);
-
- /* Locate hash entry; it is expected to exist. */
- zevpn = zebra_evpn_lookup(vni);
- if (!zevpn) {
- zlog_debug(
- "Failed to locate EVPN hash at UP, IF %s(%u) VNI %u",
- ifp->name, ifp->ifindex, vni);
- return -1;
- }
-
- assert(zevpn->vxlan_if == ifp);
- vlan_if = zvni_map_to_svi(vxl->access_vlan,
- zif->brslave_info.br_if);
- if (vlan_if) {
- zevpn->svi_if = vlan_if;
- zevpn->vrf_id = vlan_if->vrf->vrf_id;
- zl3vni = zl3vni_from_vrf(vlan_if->vrf->vrf_id);
- if (zl3vni)
- listnode_add_sort_nodup(zl3vni->l2vnis, zevpn);
- }
-
- /* If part of a bridge, inform BGP about this VNI. */
- /* Also, read and populate local MACs and neighbors. */
- if (zif->brslave_info.br_if) {
- zebra_evpn_send_add_to_client(zevpn);
- zebra_evpn_read_mac_neigh(zevpn, ifp);
- }
- }
-
- return 0;
-}
-
-/*
- * Handle VxLAN interface delete. Locate and remove entry in hash table
- * and update BGP, if required.
- */
-int zebra_vxlan_if_del(struct interface *ifp)
-{
- vni_t vni;
- struct zebra_if *zif = NULL;
- struct zebra_l2info_vxlan *vxl = NULL;
- struct zebra_evpn *zevpn = NULL;
- struct zebra_l3vni *zl3vni = NULL;
-
- /* Check if EVPN is enabled. */
- if (!is_evpn_enabled())
- return 0;
-
- zif = ifp->info;
- assert(zif);
- vxl = &zif->l2info.vxl;
- vni = vxl->vni;
-
- zl3vni = zl3vni_lookup(vni);
- if (zl3vni) {
-
- if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug("Del L3-VNI %u intf %s(%u)", vni, ifp->name,
- ifp->ifindex);
-
- /* process oper-down for l3-vni */
- zebra_vxlan_process_l3vni_oper_down(zl3vni);
-
- /* remove the association with vxlan_if */
- memset(&zl3vni->local_vtep_ip, 0, sizeof(struct in_addr));
- zl3vni->vxlan_if = NULL;
- } else {
-
- /* process if-del for l2-vni*/
- if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug("Del L2-VNI %u intf %s(%u)", vni, ifp->name,
- ifp->ifindex);
-
- /* Locate hash entry; it is expected to exist. */
- zevpn = zebra_evpn_lookup(vni);
- if (!zevpn) {
- zlog_debug(
- "Failed to locate VNI hash at del, IF %s(%u) VNI %u",
- ifp->name, ifp->ifindex, vni);
- return 0;
- }
-
- /* remove from l3-vni list */
- zl3vni = zl3vni_from_vrf(zevpn->vrf_id);
- if (zl3vni)
- listnode_delete(zl3vni->l2vnis, zevpn);
- /* Delete VNI from BGP. */
- zebra_evpn_send_del_to_client(zevpn);
-
- /* Free up all neighbors and MAC, if any. */
- zebra_evpn_neigh_del_all(zevpn, 0, 0, DEL_ALL_NEIGH);
- zebra_evpn_mac_del_all(zevpn, 0, 0, DEL_ALL_MAC);
-
- /* Free up all remote VTEPs, if any. */
- zebra_evpn_vtep_del_all(zevpn, 0);
-
- /* Delete the hash entry. */
- if (zebra_evpn_vxlan_del(zevpn)) {
- flog_err(EC_ZEBRA_VNI_DEL_FAILED,
- "Failed to del EVPN hash %p, IF %s(%u) VNI %u",
- zevpn, ifp->name, ifp->ifindex, zevpn->vni);
- return -1;
- }
- }
- return 0;
-}
-
-/*
- * Handle VxLAN interface update - change to tunnel IP, master or VLAN.
- */
-int zebra_vxlan_if_update(struct interface *ifp, uint16_t chgflags)
-{
- vni_t vni;
- struct zebra_if *zif = NULL;
- struct zebra_l2info_vxlan *vxl = NULL;
- struct zebra_evpn *zevpn = NULL;
- struct zebra_l3vni *zl3vni = NULL;
- struct interface *vlan_if = NULL;
-
- /* Check if EVPN is enabled. */
- if (!is_evpn_enabled())
- return 0;
-
- zif = ifp->info;
- assert(zif);
- vxl = &zif->l2info.vxl;
- vni = vxl->vni;
-
- zl3vni = zl3vni_lookup(vni);
- if (zl3vni) {
-
- if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug(
- "Update L3-VNI %u intf %s(%u) VLAN %u local IP %pI4 master %u chg 0x%x",
- vni, ifp->name, ifp->ifindex, vxl->access_vlan,
- &vxl->vtep_ip,
- zif->brslave_info.bridge_ifindex, chgflags);
-
- /* Removed from bridge? Cleanup and return */
- if ((chgflags & ZEBRA_VXLIF_MASTER_CHANGE)
- && (zif->brslave_info.bridge_ifindex == IFINDEX_INTERNAL)) {
- zebra_vxlan_process_l3vni_oper_down(zl3vni);
- return 0;
- }
-
- if ((chgflags & ZEBRA_VXLIF_MASTER_MAC_CHANGE)
- && if_is_operative(ifp) && is_l3vni_oper_up(zl3vni)) {
- zebra_vxlan_process_l3vni_oper_down(zl3vni);
- zebra_vxlan_process_l3vni_oper_up(zl3vni);
- return 0;
- }
-
- /* access-vlan change - process oper down, associate with new
- * svi_if and then process oper up again
- */
- if (chgflags & ZEBRA_VXLIF_VLAN_CHANGE) {
- if (if_is_operative(ifp)) {
- zebra_vxlan_process_l3vni_oper_down(zl3vni);
- zl3vni->svi_if = NULL;
- zl3vni->svi_if = zl3vni_map_to_svi_if(zl3vni);
- zl3vni->mac_vlan_if =
- zl3vni_map_to_mac_vlan_if(zl3vni);
- zl3vni->local_vtep_ip = vxl->vtep_ip;
- if (is_l3vni_oper_up(zl3vni))
- zebra_vxlan_process_l3vni_oper_up(
- zl3vni);
- }
- }
-
- /*
- * local-ip change - process oper down, associate with new
- * local-ip and then process oper up again
- */
- if (chgflags & ZEBRA_VXLIF_LOCAL_IP_CHANGE) {
- if (if_is_operative(ifp)) {
- zebra_vxlan_process_l3vni_oper_down(zl3vni);
- zl3vni->local_vtep_ip = vxl->vtep_ip;
- if (is_l3vni_oper_up(zl3vni))
- zebra_vxlan_process_l3vni_oper_up(
- zl3vni);
- }
- }
-
- /* Update local tunnel IP. */
- zl3vni->local_vtep_ip = vxl->vtep_ip;
-
- /* if we have a valid new master, process l3-vni oper up */
- if (chgflags & ZEBRA_VXLIF_MASTER_CHANGE) {
- if (if_is_operative(ifp) && is_l3vni_oper_up(zl3vni))
- zebra_vxlan_process_l3vni_oper_up(zl3vni);
- }
- } else {
-
- /* Update VNI hash. */
- zevpn = zebra_evpn_lookup(vni);
- if (!zevpn) {
- zlog_debug(
- "Failed to find EVPN hash on update, IF %s(%u) VNI %u",
- ifp->name, ifp->ifindex, vni);
- return -1;
- }
-
- if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug(
- "Update L2-VNI %u intf %s(%u) VLAN %u local IP %pI4 master %u chg 0x%x",
- vni, ifp->name, ifp->ifindex, vxl->access_vlan,
- &vxl->vtep_ip,
- zif->brslave_info.bridge_ifindex, chgflags);
-
- /* Removed from bridge? Cleanup and return */
- if ((chgflags & ZEBRA_VXLIF_MASTER_CHANGE)
- && (zif->brslave_info.bridge_ifindex == IFINDEX_INTERNAL)) {
- /* Delete from client, remove all remote VTEPs */
- /* Also, free up all MACs and neighbors. */
- zevpn->svi_if = NULL;
- zebra_evpn_send_del_to_client(zevpn);
- zebra_evpn_neigh_del_all(zevpn, 1, 0, DEL_ALL_NEIGH);
- zebra_evpn_mac_del_all(zevpn, 1, 0, DEL_ALL_MAC);
- zebra_evpn_vtep_del_all(zevpn, 1);
- return 0;
- }
-
- /* Handle other changes. */
- if (chgflags & ZEBRA_VXLIF_VLAN_CHANGE) {
- /* Remove all existing local neigh and MACs for this VNI
- * (including from BGP)
- */
- zebra_evpn_neigh_del_all(zevpn, 0, 1, DEL_LOCAL_MAC);
- zebra_evpn_mac_del_all(zevpn, 0, 1, DEL_LOCAL_MAC);
- }
-
- if (zevpn->local_vtep_ip.s_addr != vxl->vtep_ip.s_addr ||
- zevpn->mcast_grp.s_addr != vxl->mcast_grp.s_addr) {
- zebra_vxlan_sg_deref(zevpn->local_vtep_ip,
- zevpn->mcast_grp);
- zebra_vxlan_sg_ref(vxl->vtep_ip, vxl->mcast_grp);
- zevpn->local_vtep_ip = vxl->vtep_ip;
- zevpn->mcast_grp = vxl->mcast_grp;
- /* on local vtep-ip check if ES orig-ip
- * needs to be updated
- */
- zebra_evpn_es_set_base_evpn(zevpn);
- }
- zevpn_vxlan_if_set(zevpn, ifp, true /* set */);
- vlan_if = zvni_map_to_svi(vxl->access_vlan,
- zif->brslave_info.br_if);
- if (vlan_if) {
- zevpn->svi_if = vlan_if;
- zevpn->vrf_id = vlan_if->vrf->vrf_id;
- zl3vni = zl3vni_from_vrf(vlan_if->vrf->vrf_id);
- if (zl3vni)
- listnode_add_sort_nodup(zl3vni->l2vnis, zevpn);
- }
-
- /* Take further actions needed.
- * Note that if we are here, there is a change of interest.
- */
- /* If down or not mapped to a bridge, we're done. */
- if (!if_is_operative(ifp) || !zif->brslave_info.br_if)
- return 0;
-
- /* Inform BGP, if there is a change of interest. */
- if (chgflags &
- (ZEBRA_VXLIF_MASTER_CHANGE | ZEBRA_VXLIF_LOCAL_IP_CHANGE |
- ZEBRA_VXLIF_MCAST_GRP_CHANGE | ZEBRA_VXLIF_VLAN_CHANGE))
- zebra_evpn_send_add_to_client(zevpn);
-
- /* If there is a valid new master or a VLAN mapping change,
- * read and populate local MACs and neighbors.
- * Also, reinstall any remote MACs and neighbors
- * for this VNI (based on new VLAN).
- */
- if (chgflags & ZEBRA_VXLIF_MASTER_CHANGE)
- zebra_evpn_read_mac_neigh(zevpn, ifp);
- else if (chgflags & ZEBRA_VXLIF_VLAN_CHANGE) {
- struct mac_walk_ctx m_wctx;
- struct neigh_walk_ctx n_wctx;
-
- zebra_evpn_read_mac_neigh(zevpn, ifp);
-
- memset(&m_wctx, 0, sizeof(m_wctx));
- m_wctx.zevpn = zevpn;
- hash_iterate(zevpn->mac_table,
- zebra_evpn_install_mac_hash, &m_wctx);
-
- memset(&n_wctx, 0, sizeof(n_wctx));
- n_wctx.zevpn = zevpn;
- hash_iterate(zevpn->neigh_table,
- zebra_evpn_install_neigh_hash, &n_wctx);
- }
- }
-
- return 0;
-}
-
-/*
- * Handle VxLAN interface add.
- */
-int zebra_vxlan_if_add(struct interface *ifp)
-{
- vni_t vni;
- struct zebra_if *zif = NULL;
- struct zebra_l2info_vxlan *vxl = NULL;
- struct zebra_evpn *zevpn = NULL;
- struct zebra_l3vni *zl3vni = NULL;
-
- /* Check if EVPN is enabled. */
- if (!is_evpn_enabled())
- return 0;
-
- zif = ifp->info;
- assert(zif);
- vxl = &zif->l2info.vxl;
- vni = vxl->vni;
-
- zl3vni = zl3vni_lookup(vni);
- if (zl3vni) {
-
- /* process if-add for l3-vni*/
- if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug(
- "Add L3-VNI %u intf %s(%u) VLAN %u local IP %pI4 master %u",
- vni, ifp->name, ifp->ifindex, vxl->access_vlan,
- &vxl->vtep_ip,
- zif->brslave_info.bridge_ifindex);
-
- /* associate with vxlan_if */
- zl3vni->local_vtep_ip = vxl->vtep_ip;
- zl3vni->vxlan_if = ifp;
-
- /* Associate with SVI, if any. We can associate with svi-if only
- * after association with vxlan_if is complete */
- zl3vni->svi_if = zl3vni_map_to_svi_if(zl3vni);
-
- zl3vni->mac_vlan_if = zl3vni_map_to_mac_vlan_if(zl3vni);
-
- if (is_l3vni_oper_up(zl3vni))
- zebra_vxlan_process_l3vni_oper_up(zl3vni);
- } else {
-
- /* process if-add for l2-vni */
- struct interface *vlan_if = NULL;
-
- /* Create or update EVPN hash. */
- zevpn = zebra_evpn_lookup(vni);
- if (!zevpn)
- zevpn = zebra_evpn_add(vni);
-
- if (zevpn->local_vtep_ip.s_addr != vxl->vtep_ip.s_addr ||
- zevpn->mcast_grp.s_addr != vxl->mcast_grp.s_addr) {
- zebra_vxlan_sg_deref(zevpn->local_vtep_ip,
- zevpn->mcast_grp);
- zebra_vxlan_sg_ref(vxl->vtep_ip, vxl->mcast_grp);
- zevpn->local_vtep_ip = vxl->vtep_ip;
- zevpn->mcast_grp = vxl->mcast_grp;
- /* on local vtep-ip check if ES orig-ip
- * needs to be updated
- */
- zebra_evpn_es_set_base_evpn(zevpn);
- }
- zevpn_vxlan_if_set(zevpn, ifp, true /* set */);
- vlan_if = zvni_map_to_svi(vxl->access_vlan,
- zif->brslave_info.br_if);
- if (vlan_if) {
- zevpn->svi_if = vlan_if;
- zevpn->vrf_id = vlan_if->vrf->vrf_id;
- zl3vni = zl3vni_from_vrf(vlan_if->vrf->vrf_id);
- if (zl3vni)
- listnode_add_sort_nodup(zl3vni->l2vnis, zevpn);
- }
-
- if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug(
- "Add L2-VNI %u VRF %s intf %s(%u) VLAN %u local IP %pI4 mcast_grp %pI4 master %u",
- vni,
- vlan_if ? vlan_if->vrf->name : VRF_DEFAULT_NAME,
- ifp->name, ifp->ifindex, vxl->access_vlan,
- &vxl->vtep_ip, &vxl->mcast_grp,
- zif->brslave_info.bridge_ifindex);
-
- /* If down or not mapped to a bridge, we're done. */
- if (!if_is_operative(ifp) || !zif->brslave_info.br_if)
- return 0;
-
- /* Inform BGP */
- zebra_evpn_send_add_to_client(zevpn);
-
- /* Read and populate local MACs and neighbors */
- zebra_evpn_read_mac_neigh(zevpn, ifp);
- }
-
- return 0;
-}
-
int zebra_vxlan_process_vrf_vni_cmd(struct zebra_vrf *zvrf, vni_t vni,
char *err, int err_str_sz, int filter,
int add)
@@ -5557,8 +5341,8 @@ void zebra_vxlan_advertise_svi_macip(ZAPI_HANDLER_ARGS)
} else {
struct zebra_if *zif = NULL;
- struct zebra_l2info_vxlan zl2_info;
struct interface *vlan_if = NULL;
+ struct zebra_vxlan_vni *zl2_info_vni;
int old_advertise;
zevpn = zebra_evpn_lookup(vni);
@@ -5592,8 +5376,11 @@ void zebra_vxlan_advertise_svi_macip(ZAPI_HANDLER_ARGS)
if (!if_is_operative(ifp) || !zif->brslave_info.br_if)
return;
- zl2_info = zif->l2info.vxl;
- vlan_if = zvni_map_to_svi(zl2_info.access_vlan,
+ zl2_info_vni = zebra_vxlan_if_vni_find(zif, vni);
+ if (!zl2_info_vni)
+ return;
+
+ vlan_if = zvni_map_to_svi(zl2_info_vni->access_vlan,
zif->brslave_info.br_if);
if (!vlan_if)
return;
@@ -5623,8 +5410,8 @@ void zebra_vxlan_advertise_subnet(ZAPI_HANDLER_ARGS)
struct zebra_evpn *zevpn = NULL;
struct interface *ifp = NULL;
struct zebra_if *zif = NULL;
- struct zebra_l2info_vxlan zl2_info;
struct interface *vlan_if = NULL;
+ struct zebra_vxlan_vni *zl2_info_vni = NULL;
if (!EVPN_ENABLED(zvrf)) {
zlog_debug("EVPN GW-MACIP Adv for non-EVPN VRF %u",
@@ -5661,10 +5448,12 @@ void zebra_vxlan_advertise_subnet(ZAPI_HANDLER_ARGS)
if (!if_is_operative(ifp) || !zif->brslave_info.br_if)
return;
- zl2_info = zif->l2info.vxl;
+ zl2_info_vni = zebra_vxlan_if_vni_find(zif, vni);
+ if (!zl2_info_vni)
+ return;
- vlan_if =
- zvni_map_to_svi(zl2_info.access_vlan, zif->brslave_info.br_if);
+ vlan_if = zvni_map_to_svi(zl2_info_vni->access_vlan,
+ zif->brslave_info.br_if);
if (!vlan_if)
return;
@@ -5723,9 +5512,9 @@ void zebra_vxlan_advertise_gw_macip(ZAPI_HANDLER_ARGS)
} else {
struct zebra_if *zif = NULL;
- struct zebra_l2info_vxlan zl2_info;
struct interface *vlan_if = NULL;
struct interface *vrr_if = NULL;
+ struct zebra_vxlan_vni *zl2_info_vni = NULL;
int old_advertise;
zevpn = zebra_evpn_lookup(vni);
@@ -5755,9 +5544,11 @@ void zebra_vxlan_advertise_gw_macip(ZAPI_HANDLER_ARGS)
if (!if_is_operative(ifp) || !zif->brslave_info.br_if)
return;
- zl2_info = zif->l2info.vxl;
+ zl2_info_vni = zebra_vxlan_if_vni_find(zif, vni);
+ if (!zl2_info_vni)
+ return;
- vlan_if = zvni_map_to_svi(zl2_info.access_vlan,
+ vlan_if = zvni_map_to_svi(zl2_info_vni->access_vlan,
zif->brslave_info.br_if);
if (!vlan_if)
return;
@@ -5934,6 +5725,9 @@ void zebra_vxlan_init(void)
{
zrouter.l3vni_table = hash_create(l3vni_hash_keymake, l3vni_hash_cmp,
"Zebra VRF L3 VNI table");
+
+ svd_nh_table = zebra_neigh_db_create("Zebra SVD next-hop table");
+
zrouter.evpn_vrf = NULL;
zebra_evpn_mh_init();
}
@@ -5957,6 +5751,42 @@ ifindex_t get_l3vni_svi_ifindex(vrf_id_t vrf_id)
return zl3vni->svi_if->ifindex;
}
+/* get the l3vni vxlan ifindex */
+ifindex_t get_l3vni_vxlan_ifindex(vrf_id_t vrf_id)
+{
+ struct zebra_l3vni *zl3vni = NULL;
+
+ zl3vni = zl3vni_from_vrf(vrf_id);
+ if (!zl3vni || !is_l3vni_oper_up(zl3vni))
+ return 0;
+
+ return zl3vni->vxlan_if->ifindex;
+}
+
+/* get the l3vni vni */
+vni_t get_l3vni_vni(vrf_id_t vrf_id)
+{
+ struct zebra_l3vni *zl3vni = NULL;
+
+ zl3vni = zl3vni_from_vrf(vrf_id);
+ if (!zl3vni || !is_l3vni_oper_up(zl3vni))
+ return 0;
+
+ return zl3vni->vni;
+}
+
+/* is the vrf l3vni SVD backed? */
+bool is_vrf_l3vni_svd_backed(vrf_id_t vrf_id)
+{
+ struct zebra_l3vni *zl3vni = NULL;
+
+ zl3vni = zl3vni_from_vrf(vrf_id);
+ if (!zl3vni || !is_l3vni_oper_up(zl3vni))
+ return false;
+
+ return IS_ZL3VNI_SVD_BACKED(zl3vni);
+}
+
/************************** vxlan SG cache management ************************/
/* Inform PIM about the mcast group */
static int zebra_vxlan_sg_send(struct zebra_vrf *zvrf,
@@ -6140,8 +5970,8 @@ static struct zebra_vxlan_sg *zebra_vxlan_sg_do_ref(struct zebra_vrf *zvrf,
return vxlan_sg;
}
-static void zebra_vxlan_sg_deref(struct in_addr local_vtep_ip,
- struct in_addr mcast_grp)
+void zebra_vxlan_sg_deref(struct in_addr local_vtep_ip,
+ struct in_addr mcast_grp)
{
struct zebra_vrf *zvrf;
@@ -6156,8 +5986,7 @@ static void zebra_vxlan_sg_deref(struct in_addr local_vtep_ip,
zebra_vxlan_sg_do_deref(zvrf, local_vtep_ip, mcast_grp);
}
-static void zebra_vxlan_sg_ref(struct in_addr local_vtep_ip,
- struct in_addr mcast_grp)
+void zebra_vxlan_sg_ref(struct in_addr local_vtep_ip, struct in_addr mcast_grp)
{
struct zebra_vrf *zvrf;
diff --git a/zebra/zebra_vxlan.h b/zebra/zebra_vxlan.h
index 16c5bc0a1a..b33c215c73 100644
--- a/zebra/zebra_vxlan.h
+++ b/zebra/zebra_vxlan.h
@@ -36,6 +36,7 @@
#include "zebra/zebra_vrf.h"
#include "zebra/zserv.h"
#include "zebra/zebra_dplane.h"
+#include "zebra/interface.h"
#ifdef __cplusplus
extern "C" {
@@ -62,6 +63,10 @@ is_vxlan_flooding_head_end(void)
#define ZEBRA_VXLIF_MCAST_GRP_CHANGE (1 << 3)
#define ZEBRA_VXLIF_MASTER_MAC_CHANGE (1 << 4)
+#define ZEBRA_VXLIF_VNI_UPDATE(__flags) \
+ ((__flags) & (ZEBRA_VXLIF_VLAN_CHANGE | ZEBRA_VXLIF_MCAST_GRP_CHANGE))
+#define ZEBRA_VXLIF_UPDATE(__flags) \
+ ((__flags) & (ZEBRA_VXLIF_LOCAL_IP_CHANGE | ZEBRA_VXLIF_MASTER_CHANGE))
#define VNI_STR_LEN 32
@@ -84,6 +89,9 @@ extern void zebra_vxlan_sg_replay(ZAPI_HANDLER_ARGS);
extern int is_l3vni_for_prefix_routes_only(vni_t vni);
extern ifindex_t get_l3vni_svi_ifindex(vrf_id_t vrf_id);
+extern ifindex_t get_l3vni_vxlan_ifindex(vrf_id_t vrf_id);
+extern vni_t get_l3vni_vni(vrf_id_t vrf_id);
+extern bool is_vrf_l3vni_svd_backed(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);
@@ -153,6 +161,7 @@ extern void zebra_vxlan_print_rmacs_l3vni(struct vty *vty, vni_t vni,
extern void zebra_vxlan_print_rmacs_all_l3vni(struct vty *vty, bool use_json);
extern void zebra_vxlan_print_nh_l3vni(struct vty *vty, vni_t vni,
bool use_json);
+extern void zebra_vxlan_print_nh_svd(struct vty *vty, bool use_json);
extern void zebra_vxlan_print_nh_all_l3vni(struct vty *vty, bool use_json);
extern void zebra_vxlan_print_l3vni(struct vty *vty, vni_t vni, bool use_json);
extern void zebra_vxlan_print_vrf_vni(struct vty *vty, struct zebra_vrf *zvrf,
@@ -177,12 +186,13 @@ extern int zebra_vxlan_local_mac_add_update(struct interface *ifp,
extern int zebra_vxlan_local_mac_del(struct interface *ifp,
struct interface *br_if,
struct ethaddr *mac, vlanid_t vid);
-extern int zebra_vxlan_check_readd_vtep(struct interface *ifp,
+extern int zebra_vxlan_check_readd_vtep(struct interface *ifp, vni_t vni,
struct in_addr vtep_ip);
extern int zebra_vxlan_if_up(struct interface *ifp);
extern int zebra_vxlan_if_down(struct interface *ifp);
extern int zebra_vxlan_if_add(struct interface *ifp);
-extern int zebra_vxlan_if_update(struct interface *ifp, uint16_t chgflags);
+extern int zebra_vxlan_if_update(struct interface *ifp,
+ struct zebra_vxlan_if_update_ctx *ctx);
extern int zebra_vxlan_if_del(struct interface *ifp);
extern int zebra_vxlan_process_vrf_vni_cmd(struct zebra_vrf *zvrf, vni_t vni,
char *err, int err_str_sz,
@@ -218,12 +228,12 @@ extern int vni_list_cmp(void *p1, void *p2);
extern int zebra_vxlan_dp_network_mac_add(struct interface *ifp,
struct interface *br_if,
struct ethaddr *macaddr, vlanid_t vid,
- uint32_t nhg_id, bool sticky,
- bool dp_static);
+ vni_t vni, uint32_t nhg_id,
+ bool sticky, bool dp_static);
extern int zebra_vxlan_dp_network_mac_del(struct interface *ifp,
struct interface *br_if,
- struct ethaddr *macaddr,
- vlanid_t vid);
+ struct ethaddr *macaddr, vlanid_t vid,
+ vni_t vni);
extern void zebra_vxlan_set_accept_bgp_seq(bool set);
extern bool zebra_vxlan_get_accept_bgp_seq(void);
diff --git a/zebra/zebra_vxlan_if.c b/zebra/zebra_vxlan_if.c
new file mode 100644
index 0000000000..08e07b60a2
--- /dev/null
+++ b/zebra/zebra_vxlan_if.c
@@ -0,0 +1,1162 @@
+/*
+ * Zebra EVPN for VxLAN interface handling
+ *
+ * Copyright (C) 2021 Cumulus Networks, Inc.
+ * Vivek Venkatraman, Stephen Worley, Sharath Ramamurthy
+ *
+ * This file is part of FRR.
+ *
+ * FRR is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * FRR is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#include <zebra.h>
+
+#include "hash.h"
+#include "if.h"
+#include "jhash.h"
+#include "linklist.h"
+#include "log.h"
+#include "memory.h"
+#include "prefix.h"
+#include "stream.h"
+#include "table.h"
+#include "vlan.h"
+#include "vxlan.h"
+#ifdef GNU_LINUX
+#include <linux/neighbour.h>
+#endif
+
+#include "zebra/zebra_router.h"
+#include "zebra/debug.h"
+#include "zebra/interface.h"
+#include "zebra/rib.h"
+#include "zebra/rt.h"
+#include "zebra/rt_netlink.h"
+#include "zebra/zebra_errors.h"
+#include "zebra/zebra_l2.h"
+#include "zebra/zebra_ns.h"
+#include "zebra/zebra_vrf.h"
+#include "zebra/zebra_vxlan.h"
+#include "zebra/zebra_vxlan_if.h"
+#include "zebra/zebra_evpn.h"
+#include "zebra/zebra_evpn_mac.h"
+#include "zebra/zebra_evpn_neigh.h"
+#include "zebra/zebra_vxlan_private.h"
+#include "zebra/zebra_evpn_mh.h"
+#include "zebra/zebra_evpn_vxlan.h"
+#include "zebra/zebra_router.h"
+
+static unsigned int zebra_vxlan_vni_hash_keymake(const void *p)
+{
+ const struct zebra_vxlan_vni *vni;
+
+ vni = (const struct zebra_vxlan_vni *)p;
+ return jhash_1word(vni->vni, 0);
+}
+
+static bool zebra_vxlan_vni_hash_cmp(const void *p1, const void *p2)
+{
+ const struct zebra_vxlan_vni *vni1;
+ const struct zebra_vxlan_vni *vni2;
+
+ vni1 = (const struct zebra_vxlan_vni *)p1;
+ vni2 = (const struct zebra_vxlan_vni *)p2;
+
+ return (vni1->vni == vni2->vni);
+}
+
+static int zebra_vxlan_if_vni_walk_callback(struct hash_bucket *bucket,
+ void *ctxt)
+{
+ int ret;
+ struct zebra_vxlan_vni *vni;
+ struct zebra_vxlan_if_ctx *ctx;
+
+ vni = (struct zebra_vxlan_vni *)bucket->data;
+ ctx = (struct zebra_vxlan_if_ctx *)ctxt;
+
+ ret = ctx->func(ctx->zif, vni, ctx->arg);
+ return ret;
+}
+
+static void zebra_vxlan_if_vni_iterate_callback(struct hash_bucket *bucket,
+ void *ctxt)
+{
+ struct zebra_vxlan_vni *vni;
+ struct zebra_vxlan_if_ctx *ctx;
+
+ vni = (struct zebra_vxlan_vni *)bucket->data;
+ ctx = (struct zebra_vxlan_if_ctx *)ctxt;
+
+ ctx->func(ctx->zif, vni, ctx->arg);
+}
+
+static int zebra_vxlan_if_del_vni(struct interface *ifp,
+ struct zebra_vxlan_vni *vnip)
+{
+ vni_t vni;
+ struct zebra_if *zif;
+ struct zebra_evpn *zevpn;
+ struct zebra_l3vni *zl3vni;
+ struct interface *br_if;
+
+ /* Check if EVPN is enabled. */
+ if (!is_evpn_enabled())
+ return 0;
+
+ zif = ifp->info;
+ assert(zif);
+ vni = vnip->vni;
+
+ zl3vni = zl3vni_lookup(vni);
+ if (zl3vni) {
+
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug("Del L3-VNI %u intf %s(%u)", vni, ifp->name,
+ ifp->ifindex);
+
+ /* process oper-down for l3-vni */
+ zebra_vxlan_process_l3vni_oper_down(zl3vni);
+
+ /* remove the association with vxlan_if */
+ memset(&zl3vni->local_vtep_ip, 0, sizeof(struct in_addr));
+ zl3vni->vxlan_if = NULL;
+ zl3vni->vid = 0;
+ br_if = zif->brslave_info.br_if;
+ zl3vni_bridge_if_set(zl3vni, br_if, false /* unset */);
+ } else {
+
+ /* process if-del for l2-vni*/
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug("Del L2-VNI %u intf %s(%u)", vni, ifp->name,
+ ifp->ifindex);
+
+ /* Locate hash entry; it is expected to exist. */
+ zevpn = zebra_evpn_lookup(vni);
+ if (!zevpn) {
+ zlog_debug(
+ "Failed to locate VNI hash at del, IF %s(%u) VNI %u",
+ ifp->name, ifp->ifindex, vni);
+ return 0;
+ }
+
+ /* remove from l3-vni list */
+ zl3vni = zl3vni_from_vrf(zevpn->vrf_id);
+ if (zl3vni)
+ listnode_delete(zl3vni->l2vnis, zevpn);
+ /* Delete VNI from BGP. */
+ zebra_evpn_send_del_to_client(zevpn);
+
+ /* Free up all neighbors and MAC, if any. */
+ zebra_evpn_neigh_del_all(zevpn, 1, 0, DEL_ALL_NEIGH);
+ zebra_evpn_mac_del_all(zevpn, 1, 0, DEL_ALL_MAC);
+
+ /* Free up all remote VTEPs, if any. */
+ zebra_evpn_vtep_del_all(zevpn, 1);
+
+ /* Delete the hash entry. */
+ if (zebra_evpn_vxlan_del(zevpn)) {
+ flog_err(EC_ZEBRA_VNI_DEL_FAILED,
+ "Failed to del EVPN hash %p, IF %s(%u) VNI %u",
+ zevpn, ifp->name, ifp->ifindex, zevpn->vni);
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static int zebra_vxlan_if_update_vni(struct interface *ifp,
+ struct zebra_vxlan_vni *vnip,
+ struct zebra_vxlan_if_update_ctx *ctx)
+{
+ vni_t vni;
+ uint16_t chgflags;
+ vlanid_t access_vlan;
+ struct zebra_if *zif;
+ struct zebra_l2info_vxlan *vxl;
+ struct zebra_evpn *zevpn;
+ struct zebra_l3vni *zl3vni;
+ struct interface *vlan_if;
+ struct interface *br_if;
+
+ /* Check if EVPN is enabled. */
+ if (!is_evpn_enabled())
+ return 0;
+
+ zif = ifp->info;
+ assert(zif);
+ vxl = &zif->l2info.vxl;
+ vni = vnip->vni;
+ chgflags = ctx->chgflags;
+
+ zl3vni = zl3vni_lookup(vni);
+ if (zl3vni) {
+
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug(
+ "Update L3-VNI %u intf %s(%u) VLAN %u local IP %pI4 master %u chg 0x%x",
+ vni, ifp->name, ifp->ifindex, vnip->access_vlan,
+ &vxl->vtep_ip, zif->brslave_info.bridge_ifindex,
+ chgflags);
+
+ /* Removed from bridge? Cleanup and return */
+ if ((chgflags & ZEBRA_VXLIF_MASTER_CHANGE) &&
+ (zif->brslave_info.bridge_ifindex == IFINDEX_INTERNAL)) {
+ zebra_vxlan_process_l3vni_oper_down(zl3vni);
+ return 0;
+ }
+
+ if ((chgflags & ZEBRA_VXLIF_MASTER_MAC_CHANGE) &&
+ if_is_operative(ifp) && is_l3vni_oper_up(zl3vni)) {
+ zebra_vxlan_process_l3vni_oper_down(zl3vni);
+ zebra_vxlan_process_l3vni_oper_up(zl3vni);
+ return 0;
+ }
+
+ /* access-vlan change - process oper down, associate with new
+ * svi_if and then process oper up again
+ */
+ if (chgflags & ZEBRA_VXLIF_VLAN_CHANGE) {
+ if (if_is_operative(ifp)) {
+ zebra_vxlan_process_l3vni_oper_down(zl3vni);
+ zl3vni->svi_if = NULL;
+ zl3vni->svi_if = zl3vni_map_to_svi_if(zl3vni);
+ zl3vni->mac_vlan_if =
+ zl3vni_map_to_mac_vlan_if(zl3vni);
+ zl3vni->local_vtep_ip = vxl->vtep_ip;
+ if (is_l3vni_oper_up(zl3vni))
+ zebra_vxlan_process_l3vni_oper_up(
+ zl3vni);
+ }
+ }
+
+ /*
+ * local-ip change - process oper down, associate with new
+ * local-ip and then process oper up again
+ */
+ if (chgflags & ZEBRA_VXLIF_LOCAL_IP_CHANGE) {
+ if (if_is_operative(ifp)) {
+ zebra_vxlan_process_l3vni_oper_down(zl3vni);
+ zl3vni->local_vtep_ip = vxl->vtep_ip;
+ if (is_l3vni_oper_up(zl3vni))
+ zebra_vxlan_process_l3vni_oper_up(
+ zl3vni);
+ }
+ }
+
+ /* Update local tunnel IP. */
+ zl3vni->local_vtep_ip = vxl->vtep_ip;
+
+ zl3vni->vid = (zl3vni->vid != vnip->access_vlan)
+ ? vnip->access_vlan
+ : zl3vni->vid;
+ br_if = zif->brslave_info.br_if;
+ zl3vni_bridge_if_set(zl3vni, br_if, true /* set */);
+
+ /* if we have a valid new master, process l3-vni oper up */
+ if (chgflags & ZEBRA_VXLIF_MASTER_CHANGE) {
+ if (if_is_operative(ifp) && is_l3vni_oper_up(zl3vni))
+ zebra_vxlan_process_l3vni_oper_up(zl3vni);
+ }
+ } else {
+
+ /* Update VNI hash. */
+ zevpn = zebra_evpn_lookup(vni);
+ if (!zevpn) {
+ zlog_debug(
+ "Failed to find EVPN hash on update, IF %s(%u) VNI %u",
+ ifp->name, ifp->ifindex, vni);
+ return -1;
+ }
+
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug(
+ "Update L2-VNI %u intf %s(%u) VLAN %u local IP %pI4 master %u chg 0x%x",
+ vni, ifp->name, ifp->ifindex, vnip->access_vlan,
+ &vxl->vtep_ip, zif->brslave_info.bridge_ifindex,
+ chgflags);
+
+ /* Removed from bridge? Cleanup and return */
+ if ((chgflags & ZEBRA_VXLIF_MASTER_CHANGE) &&
+ (zif->brslave_info.bridge_ifindex == IFINDEX_INTERNAL)) {
+ /* Delete from client, remove all remote VTEPs */
+ /* Also, free up all MACs and neighbors. */
+ zevpn->svi_if = NULL;
+ zebra_evpn_send_del_to_client(zevpn);
+ zebra_evpn_neigh_del_all(zevpn, 1, 0, DEL_ALL_NEIGH);
+ zebra_evpn_mac_del_all(zevpn, 1, 0, DEL_ALL_MAC);
+ zebra_evpn_vtep_del_all(zevpn, 1);
+ return 0;
+ }
+
+ /* Handle other changes. */
+ if (chgflags & ZEBRA_VXLIF_VLAN_CHANGE) {
+ /* Remove all existing local neigh and MACs for this VNI
+ * (including from BGP)
+ */
+ access_vlan = vnip->access_vlan;
+ vnip->access_vlan = ctx->old_vni.access_vlan;
+ zebra_evpn_neigh_del_all(zevpn, 0, 1, DEL_LOCAL_MAC);
+ zebra_evpn_mac_del_all(zevpn, 0, 1, DEL_LOCAL_MAC);
+ zebra_evpn_rem_mac_uninstall_all(zevpn);
+ vnip->access_vlan = access_vlan;
+ }
+
+ if (zevpn->local_vtep_ip.s_addr != vxl->vtep_ip.s_addr ||
+ zevpn->mcast_grp.s_addr != vnip->mcast_grp.s_addr) {
+ zebra_vxlan_sg_deref(zevpn->local_vtep_ip,
+ zevpn->mcast_grp);
+ zebra_vxlan_sg_ref(vxl->vtep_ip, vnip->mcast_grp);
+ zevpn->local_vtep_ip = vxl->vtep_ip;
+ zevpn->mcast_grp = vnip->mcast_grp;
+ /* on local vtep-ip check if ES orig-ip
+ * needs to be updated
+ */
+ zebra_evpn_es_set_base_evpn(zevpn);
+ }
+ zevpn_vxlan_if_set(zevpn, ifp, true /* set */);
+ zevpn->vid = (zevpn->vid != vnip->access_vlan)
+ ? vnip->access_vlan
+ : zevpn->vid;
+ br_if = zif->brslave_info.br_if;
+ zevpn_bridge_if_set(zevpn, br_if, true /* set */);
+
+ vlan_if = zvni_map_to_svi(vnip->access_vlan, br_if);
+ if (vlan_if)
+ zevpn->svi_if = vlan_if;
+
+ /* Take further actions needed.
+ * Note that if we are here, there is a change of interest.
+ */
+ /* If down or not mapped to a bridge, we're done. */
+ if (!if_is_operative(ifp) || !zif->brslave_info.br_if)
+ return 0;
+
+ /* Inform BGP, if there is a change of interest. */
+ if (chgflags &
+ (ZEBRA_VXLIF_MASTER_CHANGE | ZEBRA_VXLIF_LOCAL_IP_CHANGE |
+ ZEBRA_VXLIF_MCAST_GRP_CHANGE | ZEBRA_VXLIF_VLAN_CHANGE))
+ zebra_evpn_send_add_to_client(zevpn);
+
+ /* If there is a valid new master or a VLAN mapping change,
+ * read and populate local MACs and neighbors.
+ * Also, reinstall any remote MACs and neighbors
+ * for this VNI (based on new VLAN).
+ */
+ if (chgflags & ZEBRA_VXLIF_MASTER_CHANGE)
+ zebra_evpn_read_mac_neigh(zevpn, ifp);
+ else if (chgflags & ZEBRA_VXLIF_VLAN_CHANGE) {
+ struct neigh_walk_ctx n_wctx;
+
+ zebra_evpn_read_mac_neigh(zevpn, ifp);
+
+ zebra_evpn_rem_mac_install_all(zevpn);
+
+ memset(&n_wctx, 0, sizeof(n_wctx));
+ n_wctx.zevpn = zevpn;
+ hash_iterate(zevpn->neigh_table,
+ zebra_evpn_install_neigh_hash, &n_wctx);
+ }
+ }
+
+ return 0;
+}
+
+static int zebra_vxlan_if_add_vni(struct interface *ifp,
+ struct zebra_vxlan_vni *vnip)
+{
+ vni_t vni;
+ struct zebra_if *zif;
+ struct zebra_l2info_vxlan *vxl;
+ struct zebra_evpn *zevpn;
+ struct zebra_l3vni *zl3vni;
+ struct interface *br_if;
+
+ /* Check if EVPN is enabled. */
+ if (!is_evpn_enabled())
+ return 0;
+
+ zif = ifp->info;
+ assert(zif);
+ vxl = &zif->l2info.vxl;
+ vni = vnip->vni;
+
+ zl3vni = zl3vni_lookup(vni);
+ if (zl3vni) {
+
+ /* process if-add for l3-vni*/
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug(
+ "Add L3-VNI %u intf %s(%u) VLAN %u local IP %pI4 master %u",
+ vni, ifp->name, ifp->ifindex, vnip->access_vlan,
+ &vxl->vtep_ip,
+ zif->brslave_info.bridge_ifindex);
+
+ /* associate with vxlan_if */
+ zl3vni->local_vtep_ip = vxl->vtep_ip;
+ zl3vni->vxlan_if = ifp;
+
+ /*
+ * Associate with SVI, if any. We can associate with svi-if only
+ * after association with vxlan_if is complete
+ */
+ zl3vni->svi_if = zl3vni_map_to_svi_if(zl3vni);
+
+ zl3vni->mac_vlan_if = zl3vni_map_to_mac_vlan_if(zl3vni);
+
+ zl3vni->vid = vnip->access_vlan;
+ br_if = zif->brslave_info.br_if;
+ zl3vni_bridge_if_set(zl3vni, br_if, true /* set */);
+
+ if (is_l3vni_oper_up(zl3vni))
+ zebra_vxlan_process_l3vni_oper_up(zl3vni);
+ } else {
+
+ /* process if-add for l2-vni */
+ struct interface *vlan_if = NULL;
+
+ /* Create or update EVPN hash. */
+ zevpn = zebra_evpn_lookup(vni);
+ if (!zevpn)
+ zevpn = zebra_evpn_add(vni);
+
+ if (zevpn->local_vtep_ip.s_addr != vxl->vtep_ip.s_addr ||
+ zevpn->mcast_grp.s_addr != vnip->mcast_grp.s_addr) {
+ zebra_vxlan_sg_deref(zevpn->local_vtep_ip,
+ zevpn->mcast_grp);
+ zebra_vxlan_sg_ref(vxl->vtep_ip, vnip->mcast_grp);
+ zevpn->local_vtep_ip = vxl->vtep_ip;
+ zevpn->mcast_grp = vnip->mcast_grp;
+ /* on local vtep-ip check if ES orig-ip
+ * needs to be updated
+ */
+ zebra_evpn_es_set_base_evpn(zevpn);
+ }
+ zevpn_vxlan_if_set(zevpn, ifp, true /* set */);
+ br_if = zif->brslave_info.br_if;
+ zevpn_bridge_if_set(zevpn, br_if, true /* set */);
+ vlan_if = zvni_map_to_svi(vnip->access_vlan, br_if);
+ if (vlan_if) {
+ zevpn->vid = vnip->access_vlan;
+ zevpn->svi_if = vlan_if;
+ zevpn->vrf_id = vlan_if->vrf->vrf_id;
+ zl3vni = zl3vni_from_vrf(vlan_if->vrf->vrf_id);
+ if (zl3vni)
+ listnode_add_sort_nodup(zl3vni->l2vnis, zevpn);
+ }
+
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug(
+ "Add L2-VNI %u VRF %s intf %s(%u) VLAN %u local IP %pI4 mcast_grp %pI4 master %u",
+ vni,
+ vlan_if ? vlan_if->vrf->name : VRF_DEFAULT_NAME,
+ ifp->name, ifp->ifindex, vnip->access_vlan,
+ &vxl->vtep_ip, &vnip->mcast_grp,
+ zif->brslave_info.bridge_ifindex);
+
+ /* If down or not mapped to a bridge, we're done. */
+ if (!if_is_operative(ifp) || !zif->brslave_info.br_if)
+ return 0;
+
+ /* Inform BGP */
+ zebra_evpn_send_add_to_client(zevpn);
+
+ /* Read and populate local MACs and neighbors */
+ zebra_evpn_read_mac_neigh(zevpn, ifp);
+ }
+
+ return 0;
+}
+
+static void zebra_vxlan_if_vni_entry_del(struct zebra_if *zif,
+ struct zebra_vxlan_vni *vni)
+{
+ if (vni) {
+ zebra_evpn_vl_vxl_deref(vni->access_vlan, vni->vni, zif);
+ zebra_vxlan_if_del_vni(zif->ifp, vni);
+ }
+}
+
+static int zebra_vxlan_if_vni_entry_add(struct zebra_if *zif,
+ struct zebra_vxlan_vni *vni)
+{
+ zebra_evpn_vl_vxl_ref(vni->access_vlan, vni->vni, zif);
+ return zebra_vxlan_if_add_vni(zif->ifp, vni);
+}
+
+static int zebra_vxlan_if_add_update_vni(struct zebra_if *zif,
+ struct zebra_vxlan_vni *vni,
+ void *ctxt)
+{
+ struct zebra_vxlan_vni vni_tmp;
+ struct zebra_vxlan_if_update_ctx *ctx;
+ struct zebra_vxlan_vni *old_vni = NULL;
+
+ ctx = (struct zebra_vxlan_if_update_ctx *)ctxt;
+ memcpy(&vni_tmp, vni, sizeof(*vni));
+
+ if ((hashcount(ctx->old_vni_table) == 0) ||
+ !(old_vni = hash_release(ctx->old_vni_table, &vni_tmp))) {
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug("vxlan %s adding vni(%d, %d)",
+ zif->ifp->name, vni->vni, vni->access_vlan);
+
+ zebra_vxlan_if_vni_entry_add(zif, &vni_tmp);
+ return 0;
+ }
+
+ ctx->old_vni = *old_vni;
+ ctx->chgflags = ZEBRA_VXLIF_VLAN_CHANGE;
+
+ /* copy mcast group from old_vni as thats not being changed here */
+ vni->mcast_grp = old_vni->mcast_grp;
+
+ if (old_vni->access_vlan != vni->access_vlan) {
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug(
+ "vxlan %s updating vni(%d, %d) -> vni(%d, %d)",
+ zif->ifp->name, old_vni->vni,
+ old_vni->access_vlan, vni->vni,
+ vni->access_vlan);
+
+ zebra_evpn_vl_vxl_deref(old_vni->access_vlan, old_vni->vni,
+ zif);
+ zebra_evpn_vl_vxl_ref(vni->access_vlan, vni->vni, zif);
+ zebra_vxlan_if_update_vni(zif->ifp, vni, ctx);
+ zebra_vxlan_vni_free(old_vni);
+ }
+
+ return 0;
+}
+
+static int zebra_vxlan_if_vni_entry_update_callback(struct zebra_if *zif,
+ struct zebra_vxlan_vni *vni,
+ void *ctxt)
+{
+ struct zebra_vxlan_if_update_ctx *ctx;
+
+ ctx = (struct zebra_vxlan_if_update_ctx *)ctxt;
+ return zebra_vxlan_if_update_vni(zif->ifp, vni, ctx);
+}
+
+static int zebra_vxlan_if_vni_entry_del_callback(struct zebra_if *zif,
+ struct zebra_vxlan_vni *vni,
+ void *ctxt)
+{
+ zebra_vxlan_if_vni_entry_del(zif, vni);
+ return 0;
+}
+
+static int zebra_vxlan_if_vni_entry_down_callback(struct zebra_if *zif,
+ struct zebra_vxlan_vni *vni,
+ void *ctxt)
+{
+ return zebra_vxlan_if_vni_down(zif->ifp, vni);
+}
+
+static int zebra_vxlan_if_vni_entry_up_callback(struct zebra_if *zif,
+ struct zebra_vxlan_vni *vni,
+ void *ctxt)
+{
+ return zebra_vxlan_if_vni_up(zif->ifp, vni);
+}
+
+static void zebra_vxlan_if_vni_clean(struct hash_bucket *bucket, void *arg)
+{
+ struct zebra_if *zif;
+ struct zebra_vxlan_vni *vni;
+
+ zif = (struct zebra_if *)arg;
+ vni = (struct zebra_vxlan_vni *)bucket->data;
+ zebra_vxlan_if_vni_entry_del(zif, vni);
+}
+
+void zebra_vxlan_vni_free(void *arg)
+{
+ struct zebra_vxlan_vni *vni;
+
+ vni = (struct zebra_vxlan_vni *)arg;
+
+ XFREE(MTYPE_TMP, vni);
+}
+
+void *zebra_vxlan_vni_alloc(void *p)
+{
+ struct zebra_vxlan_vni *vni;
+ const struct zebra_vxlan_vni *vnip;
+
+ vnip = (const struct zebra_vxlan_vni *)p;
+ vni = XCALLOC(MTYPE_TMP, sizeof(*vni));
+ vni->vni = vnip->vni;
+ vni->access_vlan = vnip->access_vlan;
+ vni->mcast_grp = vnip->mcast_grp;
+
+ return (void *)vni;
+}
+
+struct hash *zebra_vxlan_vni_table_create(void)
+{
+ return hash_create(zebra_vxlan_vni_hash_keymake,
+ zebra_vxlan_vni_hash_cmp, "Zebra Vxlan VNI Table");
+}
+
+void zebra_vxlan_vni_table_destroy(struct hash *vni_table)
+{
+ if (vni_table) {
+ hash_clean(vni_table, zebra_vxlan_vni_free);
+ hash_free(vni_table);
+ }
+}
+
+int zebra_vxlan_if_vni_table_destroy(struct zebra_if *zif)
+{
+ struct zebra_vxlan_vni_info *vni_info;
+
+ vni_info = VNI_INFO_FROM_ZEBRA_IF(zif);
+ if (vni_info->vni_table) {
+ zebra_vxlan_if_vni_iterate(
+ zif, zebra_vxlan_if_vni_entry_del_callback, NULL);
+ zebra_vxlan_vni_table_destroy(vni_info->vni_table);
+ vni_info->vni_table = NULL;
+ }
+ return 0;
+}
+
+int zebra_vxlan_if_vni_table_create(struct zebra_if *zif)
+{
+ struct zebra_vxlan_vni_info *vni_info;
+
+ if (!IS_ZEBRA_VXLAN_IF_SVD(zif))
+ return 0;
+
+ vni_info = VNI_INFO_FROM_ZEBRA_IF(zif);
+ vni_info->vni_table = zebra_vxlan_vni_table_create();
+ if (!vni_info->vni_table)
+ return -ENOMEM;
+
+ return 0;
+}
+
+struct zebra_vxlan_vni *zebra_vxlan_if_vni_find(const struct zebra_if *zif,
+ vni_t vni)
+{
+ struct zebra_vxlan_vni *vnip = NULL;
+ const struct zebra_vxlan_vni_info *vni_info;
+ struct zebra_vxlan_vni vni_tmp;
+
+ vni_info = VNI_INFO_FROM_ZEBRA_IF(zif);
+ if (IS_ZEBRA_VXLAN_IF_VNI(zif)) {
+ vnip = (struct zebra_vxlan_vni *)&vni_info->vni;
+ assert(vnip);
+ if (vni && (vnip->vni != vni))
+ vnip = NULL;
+
+ return vnip;
+ }
+
+ /* For SVD, the VNI value is a required parameter. */
+ assert(vni);
+
+ memset(&vni_tmp, 0, sizeof(vni_tmp));
+ vni_tmp.vni = vni;
+ vnip = (struct zebra_vxlan_vni *)hash_lookup(vni_info->vni_table,
+ (void *)&vni_tmp);
+
+ /* TODO: For debugging. Remove later */
+ if (vnip)
+ assert(vnip->vni == vni);
+
+ return vnip;
+}
+
+static int zif_vlanid_vni_walker(struct zebra_if *zif,
+ struct zebra_vxlan_vni *vnip, void *arg)
+{
+ struct zebra_vxlan_if_vlan_ctx *ctx;
+
+ ctx = (struct zebra_vxlan_if_vlan_ctx *)arg;
+
+ if (vnip->access_vlan == ctx->vid) {
+ ctx->vni = vnip;
+ return HASHWALK_ABORT;
+ }
+
+ return HASHWALK_CONTINUE;
+}
+
+struct zebra_vxlan_vni *zebra_vxlan_if_vlanid_vni_find(struct zebra_if *zif,
+ vlanid_t vid)
+{
+ struct zebra_vxlan_if_vlan_ctx ctx = {};
+
+ if (!IS_ZEBRA_VXLAN_IF_SVD(zif))
+ return NULL;
+
+ ctx.vid = vid;
+
+ zebra_vxlan_if_vni_walk(zif, zif_vlanid_vni_walker, &ctx);
+
+ return ctx.vni;
+}
+
+void zebra_vxlan_if_vni_iterate(struct zebra_if *zif,
+ int (*func)(struct zebra_if *zif,
+ struct zebra_vxlan_vni *, void *),
+ void *arg)
+{
+ struct zebra_vxlan_vni_info *vni_info;
+ struct zebra_vxlan_vni *vni = NULL;
+ struct zebra_vxlan_if_ctx ctx;
+
+ vni_info = VNI_INFO_FROM_ZEBRA_IF(zif);
+ if (IS_ZEBRA_VXLAN_IF_VNI(zif)) {
+ vni = zebra_vxlan_if_vni_find(zif, 0);
+ func(zif, vni, arg);
+ return;
+ }
+
+ memset(&ctx, 0, sizeof(ctx));
+ ctx.zif = zif;
+ ctx.func = func;
+ ctx.arg = arg;
+ hash_iterate(vni_info->vni_table, zebra_vxlan_if_vni_iterate_callback,
+ &ctx);
+}
+
+void zebra_vxlan_if_vni_walk(struct zebra_if *zif,
+ int (*func)(struct zebra_if *zif,
+ struct zebra_vxlan_vni *, void *),
+ void *arg)
+{
+ struct zebra_vxlan_vni_info *vni_info;
+ struct zebra_vxlan_vni *vni = NULL;
+ struct zebra_vxlan_if_ctx ctx;
+
+ vni_info = VNI_INFO_FROM_ZEBRA_IF(zif);
+ if (IS_ZEBRA_VXLAN_IF_VNI(zif)) {
+ vni = zebra_vxlan_if_vni_find(zif, 0);
+ func(zif, vni, arg);
+ return;
+ }
+
+ memset(&ctx, 0, sizeof(ctx));
+ ctx.zif = zif;
+ ctx.func = func;
+ ctx.arg = arg;
+ hash_walk(vni_info->vni_table, zebra_vxlan_if_vni_walk_callback, &ctx);
+}
+
+vni_t zebra_vxlan_if_access_vlan_vni_find(struct zebra_if *zif,
+ struct interface *br_if)
+{
+ struct zebra_vxlan_vni *vni = NULL;
+
+ /* Expected to be called only for vlan-unware bridges. In this case,
+ * we only support a per-VNI VXLAN interface model.
+ */
+ if (!IS_ZEBRA_VXLAN_IF_VNI(zif))
+ return 0;
+
+ vni = zebra_vxlan_if_vni_find(zif, 0);
+ assert(vni);
+
+ return vni->vni;
+}
+
+int zebra_vxlan_if_vni_table_add_update(struct interface *ifp,
+ struct hash *vni_table)
+{
+ struct zebra_if *zif;
+ struct zebra_vxlan_vni_info *vni_info;
+ struct zebra_vxlan_if_update_ctx ctx;
+
+ zif = (struct zebra_if *)ifp->info;
+
+ vni_info = VNI_INFO_FROM_ZEBRA_IF(zif);
+
+ memset(&ctx, 0, sizeof(ctx));
+ ctx.old_vni_table = vni_info->vni_table;
+ vni_info->vni_table = vni_table;
+
+ zebra_vxlan_if_vni_iterate(zif, zebra_vxlan_if_add_update_vni, &ctx);
+
+ /* release kernel deleted vnis */
+ if (ctx.old_vni_table) {
+ if (hashcount(ctx.old_vni_table)) {
+ /* UGLY HACK: Put back the old table so that delete of
+ * MACs goes through and then flip back.
+ */
+ vni_info->vni_table = ctx.old_vni_table;
+ hash_iterate(ctx.old_vni_table,
+ zebra_vxlan_if_vni_clean, zif);
+ vni_info->vni_table = vni_table;
+ }
+ zebra_vxlan_vni_table_destroy(ctx.old_vni_table);
+ ctx.old_vni_table = NULL;
+ }
+
+ return 0;
+}
+
+int zebra_vxlan_if_vni_mcast_group_add_update(struct interface *ifp,
+ vni_t vni_id,
+ struct in_addr *mcast_group)
+{
+ struct zebra_if *zif;
+ struct zebra_vxlan_vni *vni;
+ struct zebra_vxlan_if_update_ctx ctx;
+
+ zif = (struct zebra_if *)ifp->info;
+
+ if (!IS_ZEBRA_VXLAN_IF_SVD(zif))
+ return 0;
+
+ vni = zebra_vxlan_if_vni_find(zif, vni_id);
+ if (!vni)
+ return 0;
+
+ memset(&ctx, 0, sizeof(ctx));
+ ctx.old_vni.mcast_grp = vni->mcast_grp;
+ ctx.chgflags = ZEBRA_VXLIF_MCAST_GRP_CHANGE;
+
+ vni->mcast_grp = *mcast_group;
+
+ return zebra_vxlan_if_update_vni(ifp, vni, &ctx);
+}
+
+int zebra_vxlan_if_vni_mcast_group_del(struct interface *ifp, vni_t vni_id,
+ struct in_addr *mcast_group)
+{
+ struct zebra_if *zif = NULL;
+ struct zebra_vxlan_vni *vni;
+ struct zebra_vxlan_if_update_ctx ctx;
+
+ zif = (struct zebra_if *)ifp->info;
+
+ if (!IS_ZEBRA_VXLAN_IF_SVD(zif))
+ return 0;
+
+ vni = zebra_vxlan_if_vni_find(zif, vni_id);
+ if (!vni)
+ return 0;
+
+ if (memcmp(mcast_group, &vni->mcast_grp, sizeof(*mcast_group)))
+ return 0;
+
+ memset(&ctx, 0, sizeof(ctx));
+ ctx.old_vni.mcast_grp = vni->mcast_grp;
+ ctx.chgflags = ZEBRA_VXLIF_MCAST_GRP_CHANGE;
+
+ memset(&vni->mcast_grp, 0, sizeof(vni->mcast_grp));
+
+ return zebra_vxlan_if_update_vni(ifp, vni, &ctx);
+}
+
+int zebra_vxlan_if_vni_down(struct interface *ifp, struct zebra_vxlan_vni *vnip)
+{
+ vni_t vni;
+ struct zebra_if *zif;
+ struct zebra_l3vni *zl3vni;
+ struct zebra_evpn *zevpn;
+
+ /* Check if EVPN is enabled. */
+ if (!is_evpn_enabled())
+ return 0;
+
+ zif = ifp->info;
+ assert(zif);
+ vni = vnip->vni;
+
+ zl3vni = zl3vni_lookup(vni);
+ if (zl3vni) {
+ /* process-if-down for l3-vni */
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug("Intf %s(%u) L3-VNI %u is DOWN", ifp->name,
+ ifp->ifindex, vni);
+
+ zebra_vxlan_process_l3vni_oper_down(zl3vni);
+ } else {
+ /* process if-down for l2-vni */
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug("Intf %s(%u) L2-VNI %u is DOWN", ifp->name,
+ ifp->ifindex, vni);
+
+ /* Locate hash entry; it is expected to exist. */
+ zevpn = zebra_evpn_lookup(vni);
+ if (!zevpn) {
+ zlog_debug(
+ "Failed to locate VNI hash at DOWN, IF %s(%u) VNI %u",
+ ifp->name, ifp->ifindex, vni);
+ return -1;
+ }
+
+ assert(zevpn->vxlan_if == ifp);
+
+ /* remove from l3-vni list */
+ zl3vni = zl3vni_from_vrf(zevpn->vrf_id);
+ if (zl3vni)
+ listnode_delete(zl3vni->l2vnis, zevpn);
+
+ zebra_evpn_vl_vxl_deref(vnip->access_vlan, vnip->vni, zif);
+
+ /* Delete this VNI from BGP. */
+ zebra_evpn_send_del_to_client(zevpn);
+
+ /* Free up all neighbors and MACs, if any. */
+ zebra_evpn_neigh_del_all(zevpn, 1, 0, DEL_ALL_NEIGH);
+ zebra_evpn_mac_del_all(zevpn, 1, 0, DEL_ALL_MAC);
+
+ /* Free up all remote VTEPs, if any. */
+ zebra_evpn_vtep_del_all(zevpn, 1);
+ }
+ return 0;
+}
+
+/*
+ * Handle VxLAN interface down
+ */
+int zebra_vxlan_if_down(struct interface *ifp)
+{
+ struct zebra_if *zif;
+ struct zebra_vxlan_vni_info *vni_info;
+
+ /* Check if EVPN is enabled. */
+ if (!is_evpn_enabled())
+ return 0;
+
+ zif = ifp->info;
+ assert(zif);
+
+ if (IS_ZEBRA_VXLAN_IF_VNI(zif)) {
+ vni_info = VNI_INFO_FROM_ZEBRA_IF(zif);
+ return zebra_vxlan_if_vni_down(ifp, &vni_info->vni);
+ }
+
+ zebra_vxlan_if_vni_iterate(zif, zebra_vxlan_if_vni_entry_down_callback,
+ NULL);
+
+ return 0;
+}
+
+int zebra_vxlan_if_vni_up(struct interface *ifp, struct zebra_vxlan_vni *vnip)
+{
+ vni_t vni;
+ struct zebra_if *zif;
+ struct zebra_evpn *zevpn;
+ struct zebra_l3vni *zl3vni;
+
+ /* Check if EVPN is enabled. */
+ if (!is_evpn_enabled())
+ return 0;
+
+ zif = ifp->info;
+ assert(zif);
+ vni = vnip->vni;
+
+ zl3vni = zl3vni_lookup(vni);
+ if (zl3vni) {
+ /* we need to associate with SVI, if any, we can associate with
+ * svi-if only after association with vxlan-intf is complete
+ */
+ zl3vni->svi_if = zl3vni_map_to_svi_if(zl3vni);
+ zl3vni->mac_vlan_if = zl3vni_map_to_mac_vlan_if(zl3vni);
+
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug(
+ "Intf %s(%u) L3-VNI %u is UP svi_if %s mac_vlan_if %s",
+ ifp->name, ifp->ifindex, vni,
+ zl3vni->svi_if ? zl3vni->svi_if->name : "NIL",
+ zl3vni->mac_vlan_if ? zl3vni->mac_vlan_if->name
+ : "NIL");
+
+ if (is_l3vni_oper_up(zl3vni))
+ zebra_vxlan_process_l3vni_oper_up(zl3vni);
+ } else {
+ /* Handle L2-VNI add */
+ struct interface *vlan_if = NULL;
+
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug("Intf %s(%u) L2-VNI %u is UP", ifp->name,
+ ifp->ifindex, vni);
+
+ /* Locate hash entry; it is expected to exist. */
+ zevpn = zebra_evpn_lookup(vni);
+ if (!zevpn) {
+ zlog_debug(
+ "Failed to locate EVPN hash at UP, IF %s(%u) VNI %u",
+ ifp->name, ifp->ifindex, vni);
+ return -1;
+ }
+
+ assert(zevpn->vxlan_if == ifp);
+ zebra_evpn_vl_vxl_ref(vnip->access_vlan, vnip->vni, zif);
+ vlan_if = zvni_map_to_svi(vnip->access_vlan,
+ zif->brslave_info.br_if);
+ if (vlan_if) {
+ zevpn->svi_if = vlan_if;
+ zevpn->vrf_id = vlan_if->vrf->vrf_id;
+ zl3vni = zl3vni_from_vrf(vlan_if->vrf->vrf_id);
+ if (zl3vni)
+ listnode_add_sort_nodup(zl3vni->l2vnis, zevpn);
+ }
+
+ /* If part of a bridge, inform BGP about this VNI. */
+ /* Also, read and populate local MACs and neighbors. */
+ if (zif->brslave_info.br_if) {
+ zebra_evpn_send_add_to_client(zevpn);
+ zebra_evpn_read_mac_neigh(zevpn, ifp);
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Handle VxLAN interface up - update BGP if required.
+ */
+int zebra_vxlan_if_up(struct interface *ifp)
+{
+ struct zebra_if *zif;
+ struct zebra_vxlan_vni_info *vni_info;
+
+ /* Check if EVPN is enabled. */
+ if (!is_evpn_enabled())
+ return 0;
+
+ zif = ifp->info;
+ assert(zif);
+
+ if (IS_ZEBRA_VXLAN_IF_VNI(zif)) {
+ vni_info = VNI_INFO_FROM_ZEBRA_IF(zif);
+ return zebra_vxlan_if_vni_up(ifp, &vni_info->vni);
+ }
+
+ zebra_vxlan_if_vni_iterate(zif, zebra_vxlan_if_vni_entry_up_callback,
+ NULL);
+
+ return 0;
+}
+
+int zebra_vxlan_if_vni_del(struct interface *ifp, vni_t vni)
+{
+ struct zebra_if *zif;
+ struct zebra_vxlan_vni *vnip;
+ struct zebra_vxlan_vni vni_tmp;
+ struct zebra_vxlan_vni_info *vni_info;
+
+ zif = ifp->info;
+ assert(zif);
+
+ /* This should be called in SVD context only */
+ assert(IS_ZEBRA_VXLAN_IF_SVD(zif));
+
+ vni_info = VNI_INFO_FROM_ZEBRA_IF(zif);
+ memset(&vni_tmp, 0, sizeof(vni_tmp));
+ vni_tmp.vni = vni;
+
+ vnip = hash_release(vni_info->vni_table, &vni_tmp);
+ if (vnip) {
+ zebra_vxlan_if_vni_entry_del(zif, vnip);
+ zebra_vxlan_vni_free(vnip);
+ }
+ return 0;
+}
+
+/*
+ * Handle VxLAN interface delete. Locate and remove entry in hash table
+ * and update BGP, if required.
+ */
+int zebra_vxlan_if_del(struct interface *ifp)
+{
+ struct zebra_if *zif;
+ struct zebra_vxlan_vni_info *vni_info;
+
+ zif = ifp->info;
+ assert(zif);
+
+ if (IS_ZEBRA_VXLAN_IF_VNI(zif)) {
+ vni_info = VNI_INFO_FROM_ZEBRA_IF(zif);
+ zebra_evpn_vl_vxl_deref(vni_info->vni.access_vlan,
+ vni_info->vni.vni, zif);
+ return zebra_vxlan_if_del_vni(ifp, &vni_info->vni);
+ }
+
+ zebra_vxlan_if_vni_table_destroy(zif);
+
+ return 0;
+}
+
+/*
+ * Handle VxLAN interface update - change to tunnel IP, master or VLAN.
+ */
+int zebra_vxlan_if_update(struct interface *ifp,
+ struct zebra_vxlan_if_update_ctx *ctx)
+{
+ struct zebra_if *zif;
+ struct zebra_vxlan_vni_info *vni_info;
+
+ zif = ifp->info;
+ assert(zif);
+
+ if (IS_ZEBRA_VXLAN_IF_VNI(zif)) {
+ vni_info = VNI_INFO_FROM_ZEBRA_IF(zif);
+ return zebra_vxlan_if_update_vni(ifp, &vni_info->vni, ctx);
+ }
+
+ zebra_vxlan_if_vni_iterate(
+ zif, zebra_vxlan_if_vni_entry_update_callback, ctx);
+
+ return 0;
+}
+
+int zebra_vxlan_if_vni_add(struct interface *ifp, struct zebra_vxlan_vni *vni)
+{
+ struct zebra_if *zif;
+ struct zebra_vxlan_vni_info *vni_info;
+
+ zif = ifp->info;
+ assert(zif);
+
+ /* This should be called in SVD context only */
+ assert(IS_ZEBRA_VXLAN_IF_SVD(zif));
+
+ /* First insert into the table */
+ vni_info = VNI_INFO_FROM_ZEBRA_IF(zif);
+ hash_get(vni_info->vni_table, (void *)vni, zebra_vxlan_vni_alloc);
+
+ return zebra_vxlan_if_vni_entry_add(zif, vni);
+}
+
+/*
+ * Handle VxLAN interface add.
+ */
+int zebra_vxlan_if_add(struct interface *ifp)
+{
+ int ret;
+ struct zebra_if *zif;
+ struct zebra_vxlan_vni_info *vni_info;
+
+ zif = ifp->info;
+ assert(zif);
+
+ if (IS_ZEBRA_VXLAN_IF_VNI(zif)) {
+ vni_info = VNI_INFO_FROM_ZEBRA_IF(zif);
+ zebra_evpn_vl_vxl_ref(vni_info->vni.access_vlan,
+ vni_info->vni.vni, zif);
+ return zebra_vxlan_if_add_vni(ifp, &vni_info->vni);
+ }
+
+ ret = zebra_vxlan_if_vni_table_create(zif);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
diff --git a/zebra/zebra_vxlan_if.h b/zebra/zebra_vxlan_if.h
new file mode 100644
index 0000000000..8a03acbf1e
--- /dev/null
+++ b/zebra/zebra_vxlan_if.h
@@ -0,0 +1,96 @@
+/*
+ * Zebra VxLAN (EVPN) interface data structures and definitions
+ * These are public definitions referenced by other files.
+ * Copyright (C) 2021 Cumulus Networks, Inc.
+ * Sharath Ramamurthy
+ *
+ * This file is part of FRR.
+ *
+ * FRR is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * FRR is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with FRR; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef _ZEBRA_VXLAN_IF_H
+#define _ZEBRA_VXLAN_IF_H
+
+#include <zebra.h>
+#include <zebra/zebra_router.h>
+
+#include "linklist.h"
+#include "if.h"
+#include "vlan.h"
+#include "vxlan.h"
+
+#include "lib/json.h"
+#include "zebra/zebra_vrf.h"
+#include "zebra/zserv.h"
+#include "zebra/zebra_dplane.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern void *zebra_vxlan_vni_alloc(void *p);
+extern void zebra_vxlan_vni_free(void *arg);
+extern struct hash *zebra_vxlan_vni_table_create(void);
+extern void zebra_vxlan_vni_table_destroy(struct hash *vni_table);
+extern int zebra_vxlan_if_vni_table_create(struct zebra_if *zif);
+extern int zebra_vxlan_if_vni_table_destroy(struct zebra_if *zif);
+extern struct zebra_vxlan_vni *
+zebra_vxlan_if_vni_find(const struct zebra_if *zif, vni_t vni);
+extern struct zebra_vxlan_vni *
+zebra_vxlan_if_vlanid_vni_find(struct zebra_if *zif, vlanid_t vni);
+extern void zebra_vxlan_if_vni_iterate(struct zebra_if *zif,
+ int (*func)(struct zebra_if *zif,
+ struct zebra_vxlan_vni *,
+ void *),
+ void *arg);
+extern void zebra_vxlan_if_vni_walk(struct zebra_if *zif,
+ int (*func)(struct zebra_if *zif,
+ struct zebra_vxlan_vni *,
+ void *),
+ void *arg);
+extern vni_t zebra_vxlan_if_access_vlan_vni_find(struct zebra_if *zif,
+ struct interface *br_if);
+extern int
+zebra_vxlan_if_vni_mcast_group_add_update(struct interface *ifp, vni_t vni_id,
+ struct in_addr *mcast_group);
+extern int zebra_vxlan_if_vni_mcast_group_del(struct interface *ifp,
+ vni_t vni_id,
+ struct in_addr *mcast_group);
+extern int zebra_vxlan_if_vni_down(struct interface *ifp,
+ struct zebra_vxlan_vni *vni);
+extern int zebra_vxlan_if_down(struct interface *ifp);
+extern int zebra_vxlan_if_vni_up(struct interface *ifp,
+ struct zebra_vxlan_vni *vni);
+extern int zebra_vxlan_if_up(struct interface *ifp);
+extern int zebra_vxlan_if_vni_del(struct interface *ifp, vni_t vni);
+extern int zebra_vxlan_if_del(struct interface *ifp);
+extern int zebra_vxlan_if_vni_table_add_update(struct interface *ifp,
+ struct hash *vni_table);
+extern int zebra_vxlan_if_vni_update(struct interface *ifp,
+ struct zebra_vxlan_vni *vni,
+ uint16_t chgflags);
+extern int zebra_vxlan_if_update(struct interface *ifp,
+ struct zebra_vxlan_if_update_ctx *ctx);
+extern int zebra_vxlan_if_vni_add(struct interface *ifp,
+ struct zebra_vxlan_vni *vni);
+extern int zebra_vxlan_if_add(struct interface *ifp);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _ZEBRA_VXLAN_IF_H */
diff --git a/zebra/zebra_vxlan_private.h b/zebra/zebra_vxlan_private.h
index fb17dac23e..7b8cdef409 100644
--- a/zebra/zebra_vxlan_private.h
+++ b/zebra/zebra_vxlan_private.h
@@ -29,6 +29,7 @@
#include "if.h"
#include "linklist.h"
#include "zebra_vxlan.h"
+#include "zebra_vxlan_if.h"
#include "zebra_evpn.h"
#include "zebra_evpn_mac.h"
@@ -50,6 +51,10 @@ struct zebra_l3vni {
uint32_t filter;
#define PREFIX_ROUTES_ONLY (1 << 0) /* l3-vni used for prefix routes only */
+ /* Corresponding Bridge information */
+ vlanid_t vid;
+ struct interface *bridge_if;
+
/* Local IP */
struct in_addr local_vtep_ip;
@@ -71,6 +76,10 @@ struct zebra_l3vni {
struct hash *nh_table;
};
+#define IS_ZL3VNI_SVD_BACKED(zl3vni) \
+ (zl3vni->vxlan_if && zl3vni->vxlan_if->info && \
+ IS_ZEBRA_VXLAN_IF_SVD((struct zebra_if *)zl3vni->vxlan_if->info))
+
/* get the vx-intf name for l3vni */
static inline const char *zl3vni_vxlan_if_name(struct zebra_l3vni *zl3vni)
{
@@ -260,5 +269,12 @@ extern void zebra_vxlan_sync_mac_dp_install(struct zebra_mac *mac,
bool force_clear_static,
const char *caller);
extern bool zebra_evpn_do_dup_addr_detect(struct zebra_vrf *zvrf);
+extern void zebra_vxlan_sg_ref(struct in_addr local_vtep_ip,
+ struct in_addr mcast_grp);
+extern void zebra_vxlan_sg_deref(struct in_addr local_vtep_ip,
+ struct in_addr mcast_grp);
+extern void zebra_vxlan_process_l3vni_oper_up(struct zebra_l3vni *zl3vni);
+extern void zebra_vxlan_process_l3vni_oper_down(struct zebra_l3vni *zl3vni);
+extern int zebra_evpn_vxlan_del(struct zebra_evpn *zevpn);
#endif /* _ZEBRA_VXLAN_PRIVATE_H */