summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bgpd/bgp_conditional_adv.c7
-rw-r--r--bgpd/bgp_damp.c3
-rw-r--r--bgpd/bgp_fsm.c3
-rw-r--r--bgpd/bgp_route.c18
-rw-r--r--bgpd/bgp_vty.c172
-rw-r--r--doc/user/overview.rst6
-rw-r--r--lib/lib_vty.c4
-rw-r--r--pimd/pim_cmd.c2
-rw-r--r--pimd/pim_vty.c7
-rw-r--r--tests/topotests/ospf_basic_functionality/test_ospf_authentication.py5
-rw-r--r--tests/topotests/ospf_basic_functionality/test_ospf_lan.py7
-rw-r--r--tests/topotests/ospf_basic_functionality/test_ospf_single_area.py5
-rw-r--r--vtysh/vtysh.c2
-rw-r--r--vtysh/vtysh.h2
-rw-r--r--vtysh/vtysh_config.c12
-rw-r--r--vtysh/vtysh_main.c10
-rw-r--r--zebra/if_netlink.c2
-rw-r--r--zebra/interface.c17
-rw-r--r--zebra/interface.h4
-rw-r--r--zebra/zebra_evpn_mh.c287
-rw-r--r--zebra/zebra_evpn_mh.h7
-rw-r--r--zebra/zebra_vty.c8
-rw-r--r--zebra/zebra_vxlan.c46
23 files changed, 410 insertions, 226 deletions
diff --git a/bgpd/bgp_conditional_adv.c b/bgpd/bgp_conditional_adv.c
index b5cd1b52b7..b9ea26e862 100644
--- a/bgpd/bgp_conditional_adv.c
+++ b/bgpd/bgp_conditional_adv.c
@@ -19,8 +19,7 @@
*/
#include "bgpd/bgp_conditional_adv.h"
-
-const char *get_afi_safi_str(afi_t afi, safi_t safi, bool for_json);
+#include "bgpd/bgp_vty.h"
static route_map_result_t
bgp_check_rmap_prefixes_in_bgp_table(struct bgp_table *table,
@@ -198,10 +197,6 @@ static int bgp_conditional_adv_timer(struct thread *t)
continue;
FOREACH_AFI_SAFI (afi, safi) {
- if (strmatch(get_afi_safi_str(afi, safi, true),
- "Unknown"))
- continue;
-
if (!peer->afc_nego[afi][safi])
continue;
diff --git a/bgpd/bgp_damp.c b/bgpd/bgp_damp.c
index 94a27ead0e..f46d416c3c 100644
--- a/bgpd/bgp_damp.c
+++ b/bgpd/bgp_damp.c
@@ -35,8 +35,7 @@
#include "bgpd/bgp_route.h"
#include "bgpd/bgp_attr.h"
#include "bgpd/bgp_advertise.h"
-
-const char *get_afi_safi_str(afi_t afi, safi_t safi, bool for_json);
+#include "bgpd/bgp_vty.h"
/* Global variable to access damping configuration */
static struct bgp_damp_config damp[AFI_MAX][SAFI_MAX];
diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c
index ce665feb4e..a4d17cac40 100644
--- a/bgpd/bgp_fsm.c
+++ b/bgpd/bgp_fsm.c
@@ -55,10 +55,11 @@
#include "bgpd/bgp_keepalives.h"
#include "bgpd/bgp_io.h"
#include "bgpd/bgp_zebra.h"
+#include "bgpd/bgp_vty.h"
DEFINE_HOOK(peer_backward_transition, (struct peer * peer), (peer))
DEFINE_HOOK(peer_status_changed, (struct peer * peer), (peer))
-extern const char *get_afi_safi_str(afi_t afi, safi_t safi, bool for_json);
+
/* Definition of display strings corresponding to FSM events. This should be
* kept consistent with the events defined in bgpd.h
*/
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index 87e03d205f..60ad8d20e9 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -96,7 +96,7 @@
/* Extern from bgp_dump.c */
extern const char *bgp_origin_str[];
extern const char *bgp_origin_long_str[];
-const char *get_afi_safi_str(afi_t afi, safi_t safi, bool for_json);
+
/* PMSI strings. */
#define PMSI_TNLTYPE_STR_NO_INFO "No info"
#define PMSI_TNLTYPE_STR_DEFAULT PMSI_TNLTYPE_STR_NO_INFO
@@ -11739,10 +11739,6 @@ DEFPY (show_ip_bgp_json,
? AFI_IP
: AFI_IP6;
FOREACH_SAFI (safi) {
- if (strmatch(get_afi_safi_str(afi, safi, true),
- "Unknown"))
- continue;
-
if (!bgp_afi_safi_peer_exists(bgp, afi, safi))
continue;
@@ -11773,10 +11769,6 @@ DEFPY (show_ip_bgp_json,
} else {
/* show <ip> bgp all: for each AFI and SAFI*/
FOREACH_AFI_SAFI (afi, safi) {
- if (strmatch(get_afi_safi_str(afi, safi, true),
- "Unknown"))
- continue;
-
if (!bgp_afi_safi_peer_exists(bgp, afi, safi))
continue;
@@ -13318,10 +13310,6 @@ DEFPY (show_ip_bgp_instance_neighbor_advertised_route,
afi = CHECK_FLAG(show_flags, BGP_SHOW_OPT_AFI_IP) ? AFI_IP
: AFI_IP6;
FOREACH_SAFI (safi) {
- if (strmatch(get_afi_safi_str(afi, safi, true),
- "Unknown"))
- continue;
-
if (!bgp_afi_safi_peer_exists(bgp, afi, safi))
continue;
@@ -13341,10 +13329,6 @@ DEFPY (show_ip_bgp_instance_neighbor_advertised_route,
}
} else {
FOREACH_AFI_SAFI (afi, safi) {
- if (strmatch(get_afi_safi_str(afi, safi, true),
- "Unknown"))
- continue;
-
if (!bgp_afi_safi_peer_exists(bgp, afi, safi))
continue;
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
index b77c4b2297..cfac0bbb54 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -209,34 +209,38 @@ static enum node_type bgp_node_type(afi_t afi, safi_t safi)
static const char *get_afi_safi_vty_str(afi_t afi, safi_t safi)
{
- if (afi == AFI_IP && safi == SAFI_UNICAST)
- return "IPv4 Unicast";
- else if (afi == AFI_IP && safi == SAFI_MULTICAST)
- return "IPv4 Multicast";
- else if (afi == AFI_IP && safi == SAFI_LABELED_UNICAST)
- return "IPv4 Labeled Unicast";
- else if (afi == AFI_IP && safi == SAFI_MPLS_VPN)
- return "IPv4 VPN";
- else if (afi == AFI_IP && safi == SAFI_ENCAP)
- return "IPv4 Encap";
- else if (afi == AFI_IP && safi == SAFI_FLOWSPEC)
- return "IPv4 Flowspec";
- else if (afi == AFI_IP6 && safi == SAFI_UNICAST)
- return "IPv6 Unicast";
- else if (afi == AFI_IP6 && safi == SAFI_MULTICAST)
- return "IPv6 Multicast";
- else if (afi == AFI_IP6 && safi == SAFI_LABELED_UNICAST)
- return "IPv6 Labeled Unicast";
- else if (afi == AFI_IP6 && safi == SAFI_MPLS_VPN)
- return "IPv6 VPN";
- else if (afi == AFI_IP6 && safi == SAFI_ENCAP)
- return "IPv6 Encap";
- else if (afi == AFI_IP6 && safi == SAFI_FLOWSPEC)
- return "IPv6 Flowspec";
- else if (afi == AFI_L2VPN && safi == SAFI_EVPN)
- return "L2VPN EVPN";
- else
- return "Unknown";
+ if (afi == AFI_IP) {
+ if (safi == SAFI_UNICAST)
+ return "IPv4 Unicast";
+ if (safi == SAFI_MULTICAST)
+ return "IPv4 Multicast";
+ if (safi == SAFI_LABELED_UNICAST)
+ return "IPv4 Labeled Unicast";
+ if (safi == SAFI_MPLS_VPN)
+ return "IPv4 VPN";
+ if (safi == SAFI_ENCAP)
+ return "IPv4 Encap";
+ if (safi == SAFI_FLOWSPEC)
+ return "IPv4 Flowspec";
+ } else if (afi == AFI_IP6) {
+ if (safi == SAFI_UNICAST)
+ return "IPv6 Unicast";
+ if (safi == SAFI_MULTICAST)
+ return "IPv6 Multicast";
+ if (safi == SAFI_LABELED_UNICAST)
+ return "IPv6 Labeled Unicast";
+ if (safi == SAFI_MPLS_VPN)
+ return "IPv6 VPN";
+ if (safi == SAFI_ENCAP)
+ return "IPv6 Encap";
+ if (safi == SAFI_FLOWSPEC)
+ return "IPv6 Flowspec";
+ } else if (afi == AFI_L2VPN) {
+ if (safi == SAFI_EVPN)
+ return "L2VPN EVPN";
+ }
+
+ return "Unknown";
}
/*
@@ -247,34 +251,38 @@ static const char *get_afi_safi_vty_str(afi_t afi, safi_t safi)
*/
static const char *get_afi_safi_json_str(afi_t afi, safi_t safi)
{
- if (afi == AFI_IP && safi == SAFI_UNICAST)
- return "ipv4Unicast";
- else if (afi == AFI_IP && safi == SAFI_MULTICAST)
- return "ipv4Multicast";
- else if (afi == AFI_IP && safi == SAFI_LABELED_UNICAST)
- return "ipv4LabeledUnicast";
- else if (afi == AFI_IP && safi == SAFI_MPLS_VPN)
- return "ipv4Vpn";
- else if (afi == AFI_IP && safi == SAFI_ENCAP)
- return "ipv4Encap";
- else if (afi == AFI_IP && safi == SAFI_FLOWSPEC)
- return "ipv4Flowspec";
- else if (afi == AFI_IP6 && safi == SAFI_UNICAST)
- return "ipv6Unicast";
- else if (afi == AFI_IP6 && safi == SAFI_MULTICAST)
- return "ipv6Multicast";
- else if (afi == AFI_IP6 && safi == SAFI_LABELED_UNICAST)
- return "ipv6LabeledUnicast";
- else if (afi == AFI_IP6 && safi == SAFI_MPLS_VPN)
- return "ipv6Vpn";
- else if (afi == AFI_IP6 && safi == SAFI_ENCAP)
- return "ipv6Encap";
- else if (afi == AFI_IP6 && safi == SAFI_FLOWSPEC)
- return "ipv6Flowspec";
- else if (afi == AFI_L2VPN && safi == SAFI_EVPN)
- return "l2VpnEvpn";
- else
- return "Unknown";
+ if (afi == AFI_IP) {
+ if (safi == SAFI_UNICAST)
+ return "ipv4Unicast";
+ if (safi == SAFI_MULTICAST)
+ return "ipv4Multicast";
+ if (safi == SAFI_LABELED_UNICAST)
+ return "ipv4LabeledUnicast";
+ if (safi == SAFI_MPLS_VPN)
+ return "ipv4Vpn";
+ if (safi == SAFI_ENCAP)
+ return "ipv4Encap";
+ if (safi == SAFI_FLOWSPEC)
+ return "ipv4Flowspec";
+ } else if (afi == AFI_IP6) {
+ if (safi == SAFI_UNICAST)
+ return "ipv6Unicast";
+ if (safi == SAFI_MULTICAST)
+ return "ipv6Multicast";
+ if (safi == SAFI_LABELED_UNICAST)
+ return "ipv6LabeledUnicast";
+ if (safi == SAFI_MPLS_VPN)
+ return "ipv6Vpn";
+ if (safi == SAFI_ENCAP)
+ return "ipv6Encap";
+ if (safi == SAFI_FLOWSPEC)
+ return "ipv6Flowspec";
+ } else if (afi == AFI_L2VPN) {
+ if (safi == SAFI_EVPN)
+ return "l2VpnEvpn";
+ }
+
+ return "Unknown";
}
/* return string maps to afi-safi specific container names
@@ -282,30 +290,34 @@ static const char *get_afi_safi_json_str(afi_t afi, safi_t safi)
*/
const char *bgp_afi_safi_get_container_str(afi_t afi, safi_t safi)
{
- if (afi == AFI_IP && safi == SAFI_UNICAST)
- return "ipv4-unicast";
- else if (afi == AFI_IP && safi == SAFI_MULTICAST)
- return "ipv4-multicast";
- else if (afi == AFI_IP && safi == SAFI_LABELED_UNICAST)
- return "ipv4-labeled-unicast";
- else if (afi == AFI_IP && safi == SAFI_MPLS_VPN)
- return "l3vpn-ipv4-unicast";
- else if (afi == AFI_IP && safi == SAFI_FLOWSPEC)
- return "ipv4-flowspec";
- else if (afi == AFI_IP6 && safi == SAFI_UNICAST)
- return "ipv6-unicast";
- else if (afi == AFI_IP6 && safi == SAFI_MULTICAST)
- return "ipv6-multicast";
- else if (afi == AFI_IP6 && safi == SAFI_LABELED_UNICAST)
- return "ipv6-labeled-unicast";
- else if (afi == AFI_IP6 && safi == SAFI_MPLS_VPN)
- return "l3vpn-ipv6-unicast";
- else if (afi == AFI_IP6 && safi == SAFI_FLOWSPEC)
- return "ipv6-flowspec";
- else if (afi == AFI_L2VPN && safi == SAFI_EVPN)
- return "l2vpn-evpn";
- else
- return "Unknown";
+ if (afi == AFI_IP) {
+ if (safi == SAFI_UNICAST)
+ return "ipv4-unicast";
+ if (safi == SAFI_MULTICAST)
+ return "ipv4-multicast";
+ if (safi == SAFI_LABELED_UNICAST)
+ return "ipv4-labeled-unicast";
+ if (safi == SAFI_MPLS_VPN)
+ return "l3vpn-ipv4-unicast";
+ if (safi == SAFI_FLOWSPEC)
+ return "ipv4-flowspec";
+ } else if (afi == AFI_IP6) {
+ if (safi == SAFI_UNICAST)
+ return "ipv6-unicast";
+ if (safi == SAFI_MULTICAST)
+ return "ipv6-multicast";
+ if (safi == SAFI_LABELED_UNICAST)
+ return "ipv6-labeled-unicast";
+ if (safi == SAFI_MPLS_VPN)
+ return "l3vpn-ipv6-unicast";
+ if (safi == SAFI_FLOWSPEC)
+ return "ipv6-flowspec";
+ } else if (afi == AFI_L2VPN) {
+ if (safi == SAFI_EVPN)
+ return "l2vpn-evpn";
+ }
+
+ return "Unknown";
}
/* Utility function to get address family from current node. */
diff --git a/doc/user/overview.rst b/doc/user/overview.rst
index 07702cbdd1..a2ce67068f 100644
--- a/doc/user/overview.rst
+++ b/doc/user/overview.rst
@@ -109,9 +109,9 @@ daemons using a single configuration file through the integrated configuration
mode. This avoids the overhead of maintaining a separate configuration file for
each daemon.
-FRR is currently currently implementing a new internal configuration system
-based on YANG data models. When this work is completed, FRR will be a fully
-programmable routing stack.
+FRR is currently implementing a new internal configuration system based on YANG
+data models. When this work is completed, FRR will be a fully programmable
+routing stack.
.. _supported-platforms:
diff --git a/lib/lib_vty.c b/lib/lib_vty.c
index 0cc25f24ed..cd8b5c9809 100644
--- a/lib/lib_vty.c
+++ b/lib/lib_vty.c
@@ -222,7 +222,7 @@ static struct call_back {
DEFUN_HIDDEN (start_config,
start_config_cmd,
- "start_configuration",
+ "XFRR_start_configuration",
"The Beginning of Configuration\n")
{
callback.readin_time = monotime(NULL);
@@ -235,7 +235,7 @@ DEFUN_HIDDEN (start_config,
DEFUN_HIDDEN (end_config,
end_config_cmd,
- "end_configuration",
+ "XFRR_end_configuration",
"The End of Configuration\n")
{
time_t readin_time;
diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c
index 02a4c9c1fc..8e7b13cc17 100644
--- a/pimd/pim_cmd.c
+++ b/pimd/pim_cmd.c
@@ -5858,7 +5858,7 @@ static void show_mroute(struct pim_instance *pim, struct vty *vty,
vty_out(vty, "IP Multicast Routing Table\n");
vty_out(vty, "Flags: S - Sparse, C - Connected, P - Pruned\n");
vty_out(vty,
- " R - RP-bit set, F - Register flag, T - SPT-bit set\n");
+ " R - SGRpt Pruned, F - Register flag, T - SPT-bit set\n");
vty_out(vty,
"\nSource Group Flags Proto Input Output TTL Uptime\n");
}
diff --git a/pimd/pim_vty.c b/pimd/pim_vty.c
index 1f2ca11db3..57a0c69166 100644
--- a/pimd/pim_vty.c
+++ b/pimd/pim_vty.c
@@ -275,6 +275,13 @@ int pim_interface_config_write(struct vty *vty)
continue;
FOR_ALL_INTERFACES (pim->vrf, ifp) {
+ /* pim is enabled internally/implicitly on the vxlan
+ * termination device ipmr-lo. skip displaying that
+ * config to avoid confusion
+ */
+ if (pim_vxlan_is_term_dev_cfg(pim, ifp))
+ continue;
+
/* IF name */
if (vrf->vrf_id == VRF_DEFAULT)
vty_frame(vty, "interface %s\n", ifp->name);
diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_authentication.py b/tests/topotests/ospf_basic_functionality/test_ospf_authentication.py
index e92baefabf..9c3be58937 100644
--- a/tests/topotests/ospf_basic_functionality/test_ospf_authentication.py
+++ b/tests/topotests/ospf_basic_functionality/test_ospf_authentication.py
@@ -29,6 +29,7 @@ import pytest
from time import sleep
from copy import deepcopy
import json
+from lib.topotest import frr_unicode
# Save the Current Working Directory to find configuration files.
CWD = os.path.dirname(os.path.realpath(__file__))
@@ -318,7 +319,7 @@ def test_ospf_authentication_simple_pass_tc28_p1(request):
topo_modify_change_ip = deepcopy(topo)
intf_ip = topo_modify_change_ip["routers"]["r1"]["links"]["r2"]["ipv4"]
topo_modify_change_ip["routers"]["r1"]["links"]["r2"]["ipv4"] = str(
- IPv4Address(unicode(intf_ip.split("/")[0])) + 3
+ IPv4Address(frr_unicode(intf_ip.split("/")[0])) + 3
) + "/{}".format(intf_ip.split("/")[1])
build_config_from_json(tgen, topo_modify_change_ip, save_bkup=False)
@@ -529,7 +530,7 @@ def test_ospf_authentication_md5_tc29_p1(request):
intf_ip = topo_modify_change_ip["routers"]["r1"]["links"]["r2"]["ipv4"]
topo_modify_change_ip["routers"]["r1"]["links"]["r2"]["ipv4"] = str(
- IPv4Address(unicode(intf_ip.split("/")[0])) + 3
+ IPv4Address(frr_unicode(intf_ip.split("/")[0])) + 3
) + "/{}".format(intf_ip.split("/")[1])
build_config_from_json(tgen, topo_modify_change_ip, save_bkup=False)
diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_lan.py b/tests/topotests/ospf_basic_functionality/test_ospf_lan.py
index 1357a86c81..0f1115f815 100644
--- a/tests/topotests/ospf_basic_functionality/test_ospf_lan.py
+++ b/tests/topotests/ospf_basic_functionality/test_ospf_lan.py
@@ -29,6 +29,7 @@ import pytest
import json
from copy import deepcopy
import ipaddress
+from lib.topotest import frr_unicode
# Save the Current Working Directory to find configuration files.
CWD = os.path.dirname(os.path.realpath(__file__))
@@ -468,7 +469,7 @@ def test_ospf_lan_tc1_p0(request):
topo_modify_change_ip = deepcopy(topo)
intf_ip = topo_modify_change_ip["routers"]["r0"]["links"]["s1"]["ipv4"]
topo_modify_change_ip["routers"]["r0"]["links"]["s1"]["ipv4"] = str(
- IPv4Address(unicode(intf_ip.split("/")[0])) + 3
+ IPv4Address(frr_unicode(intf_ip.split("/")[0])) + 3
) + "/{}".format(intf_ip.split("/")[1])
build_config_from_json(tgen, topo_modify_change_ip, save_bkup=False)
@@ -601,7 +602,7 @@ def test_ospf_lan_tc2_p0(request):
topo_modify_change_ip = deepcopy(topo)
intf_ip = topo_modify_change_ip["routers"]["r0"]["links"]["s1"]["ipv4"]
topo_modify_change_ip["routers"]["r0"]["links"]["s1"]["ipv4"] = str(
- IPv4Address(unicode(intf_ip.split("/")[0])) + 3
+ IPv4Address(frr_unicode(intf_ip.split("/")[0])) + 3
) + "/{}".format(intf_ip.split("/")[1])
build_config_from_json(tgen, topo_modify_change_ip, save_bkup=False)
@@ -652,7 +653,7 @@ def test_ospf_lan_tc2_p0(request):
topo_modify_change_ip = deepcopy(topo)
intf_ip = topo_modify_change_ip["routers"]["r0"]["links"]["s1"]["ipv4"]
topo_modify_change_ip["routers"]["r0"]["links"]["s1"]["ipv4"] = str(
- IPv4Address(unicode(intf_ip.split("/")[0])) + 3
+ IPv4Address(frr_unicode(intf_ip.split("/")[0])) + 3
) + "/{}".format(int(intf_ip.split("/")[1]) + 1)
build_config_from_json(tgen, topo_modify_change_ip, save_bkup=False)
diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_single_area.py b/tests/topotests/ospf_basic_functionality/test_ospf_single_area.py
index 3a269d853c..b2b0fb8d44 100644
--- a/tests/topotests/ospf_basic_functionality/test_ospf_single_area.py
+++ b/tests/topotests/ospf_basic_functionality/test_ospf_single_area.py
@@ -29,6 +29,7 @@ import pytest
import json
from copy import deepcopy
from ipaddress import IPv4Address
+from lib.topotest import frr_unicode
# Save the Current Working Directory to find configuration files.
CWD = os.path.dirname(os.path.realpath(__file__))
@@ -233,7 +234,7 @@ def test_ospf_p2p_tc3_p0(request):
topo_modify_change_ip = deepcopy(topo)
intf_ip = topo_modify_change_ip["routers"]["r0"]["links"]["r3"]["ipv4"]
topo_modify_change_ip["routers"]["r0"]["links"]["r3"]["ipv4"] = str(
- IPv4Address(unicode(intf_ip.split("/")[0])) + 3
+ IPv4Address(frr_unicode(intf_ip.split("/")[0])) + 3
) + "/{}".format(intf_ip.split("/")[1])
build_config_from_json(tgen, topo_modify_change_ip, save_bkup=False)
@@ -284,7 +285,7 @@ def test_ospf_p2p_tc3_p0(request):
topo_modify_change_ip = deepcopy(topo)
intf_ip = topo_modify_change_ip["routers"]["r0"]["links"]["r3"]["ipv4"]
topo_modify_change_ip["routers"]["r0"]["links"]["r3"]["ipv4"] = str(
- IPv4Address(unicode(intf_ip.split("/")[0])) + 3
+ IPv4Address(frr_unicode(intf_ip.split("/")[0])) + 3
) + "/{}".format(int(intf_ip.split("/")[1]) + 1)
build_config_from_json(tgen, topo_modify_change_ip, save_bkup=False)
diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c
index 22eff40cd6..f3e28b70e8 100644
--- a/vtysh/vtysh.c
+++ b/vtysh/vtysh.c
@@ -3400,7 +3400,7 @@ DEFUN (vtysh_copy_to_running,
int ret;
const char *fname = argv[1]->arg;
- ret = vtysh_read_config(fname);
+ ret = vtysh_read_config(fname, true);
/* Return to enable mode - the 'read_config' api leaves us up a level */
vtysh_execute_no_pager("enable");
diff --git a/vtysh/vtysh.h b/vtysh/vtysh.h
index 9683518b67..20e1e1b0e9 100644
--- a/vtysh/vtysh.h
+++ b/vtysh/vtysh.h
@@ -93,7 +93,7 @@ void config_add_line(struct list *, const char *);
int vtysh_mark_file(const char *filename);
-int vtysh_read_config(const char *);
+int vtysh_read_config(const char *filename, bool dry_run);
int vtysh_write_config_integrated(void);
void vtysh_config_parse_line(void *, const char *);
diff --git a/vtysh/vtysh_config.c b/vtysh/vtysh_config.c
index f35a8af4b9..47f426b5e0 100644
--- a/vtysh/vtysh_config.c
+++ b/vtysh/vtysh_config.c
@@ -515,7 +515,7 @@ void vtysh_config_dump(void)
}
/* Read up configuration file from file_name. */
-static int vtysh_read_file(FILE *confp)
+static int vtysh_read_file(FILE *confp, bool dry_run)
{
struct vty *vty;
int ret;
@@ -528,12 +528,14 @@ static int vtysh_read_file(FILE *confp)
vtysh_execute_no_pager("enable");
vtysh_execute_no_pager("configure terminal");
- vtysh_execute_no_pager("start_configuration");
+ if (!dry_run)
+ vtysh_execute_no_pager("XFRR_start_configuration");
/* Execute configuration file. */
ret = vtysh_config_from_file(vty, confp);
- vtysh_execute_no_pager("end_configuration");
+ if (!dry_run)
+ vtysh_execute_no_pager("XFRR_end_configuration");
vtysh_execute_no_pager("end");
vtysh_execute_no_pager("disable");
@@ -544,7 +546,7 @@ static int vtysh_read_file(FILE *confp)
}
/* Read up configuration file from config_default_dir. */
-int vtysh_read_config(const char *config_default_dir)
+int vtysh_read_config(const char *config_default_dir, bool dry_run)
{
FILE *confp = NULL;
int ret;
@@ -557,7 +559,7 @@ int vtysh_read_config(const char *config_default_dir)
return CMD_ERR_NO_FILE;
}
- ret = vtysh_read_file(confp);
+ ret = vtysh_read_file(confp, dry_run);
fclose(confp);
return (ret);
diff --git a/vtysh/vtysh_main.c b/vtysh/vtysh_main.c
index 6e28df79d6..db7cc312d6 100644
--- a/vtysh/vtysh_main.c
+++ b/vtysh/vtysh_main.c
@@ -459,7 +459,7 @@ int main(int argc, char **argv, char **env)
/* Read vtysh configuration file before connecting to daemons.
* (file may not be readable to calling user in SUID mode) */
suid_on();
- vtysh_read_config(vtysh_config);
+ vtysh_read_config(vtysh_config, dryrun);
suid_off();
}
/* Error code library system */
@@ -478,9 +478,9 @@ int main(int argc, char **argv, char **env)
/* Start execution only if not in dry-run mode */
if (dryrun && !cmd) {
if (inputfile) {
- ret = vtysh_read_config(inputfile);
+ ret = vtysh_read_config(inputfile, dryrun);
} else {
- ret = vtysh_read_config(frr_config);
+ ret = vtysh_read_config(frr_config, dryrun);
}
exit(ret);
@@ -561,7 +561,7 @@ int main(int argc, char **argv, char **env)
if (inputfile) {
vtysh_flock_config(inputfile);
- ret = vtysh_read_config(inputfile);
+ ret = vtysh_read_config(inputfile, dryrun);
vtysh_unflock_config();
exit(ret);
}
@@ -670,7 +670,7 @@ int main(int argc, char **argv, char **env)
/* Boot startup configuration file. */
if (boot_flag) {
vtysh_flock_config(frr_config);
- ret = vtysh_read_config(frr_config);
+ ret = vtysh_read_config(frr_config, dryrun);
vtysh_unflock_config();
if (ret) {
fprintf(stderr,
diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c
index a68873882d..e4dd745f42 100644
--- a/zebra/if_netlink.c
+++ b/zebra/if_netlink.c
@@ -691,7 +691,7 @@ static int netlink_bridge_interface(struct nlmsghdr *h, int len, ns_id_t ns_id,
return 0;
}
-/* If the interface is and es bond member then it must follow EVPN's
+/* If the interface is an es bond member then it must follow EVPN's
* protodown setting
*/
static void netlink_proc_dplane_if_protodown(struct zebra_if *zif,
diff --git a/zebra/interface.c b/zebra/interface.c
index ddad9c9e56..4072eb1568 100644
--- a/zebra/interface.c
+++ b/zebra/interface.c
@@ -1428,6 +1428,14 @@ const char *zebra_protodown_rc_str(enum protodown_reasons protodown_rc,
return pd_buf;
}
+static inline bool if_is_protodown_applicable(struct interface *ifp)
+{
+ if (IS_ZEBRA_IF_BOND(ifp))
+ return false;
+
+ return true;
+}
+
/* Interface's information print out to vty interface. */
static void if_dump_vty(struct vty *vty, struct interface *ifp)
{
@@ -1592,14 +1600,13 @@ static void if_dump_vty(struct vty *vty, struct interface *ifp)
}
zebra_evpn_if_es_print(vty, zebra_if);
- vty_out(vty, " protodown: %s",
- (zebra_if->flags & ZIF_FLAG_PROTODOWN) ? "on" : "off");
+ vty_out(vty, " protodown: %s %s\n",
+ (zebra_if->flags & ZIF_FLAG_PROTODOWN) ? "on" : "off",
+ if_is_protodown_applicable(ifp) ? "" : "(n/a)");
if (zebra_if->protodown_rc)
- vty_out(vty, " rc: %s\n",
+ vty_out(vty, " protodown reasons: %s\n",
zebra_protodown_rc_str(zebra_if->protodown_rc, pd_buf,
sizeof(pd_buf)));
- else
- vty_out(vty, "\n");
if (zebra_if->link_ifindex != IFINDEX_INTERNAL) {
if (zebra_if->link)
diff --git a/zebra/interface.h b/zebra/interface.h
index ab1a245e5e..8dcb477f10 100644
--- a/zebra/interface.h
+++ b/zebra/interface.h
@@ -279,8 +279,12 @@ struct irdp_interface;
/* Ethernet segment info used for setting up EVPN multihoming */
struct zebra_evpn_es;
struct zebra_es_if_info {
+ /* type-3 esi config */
struct ethaddr sysmac;
uint32_t lid; /* local-id; has to be unique per-ES-sysmac */
+
+ esi_t esi;
+
uint16_t df_pref;
struct zebra_evpn_es *es; /* local ES */
};
diff --git a/zebra/zebra_evpn_mh.c b/zebra/zebra_evpn_mh.c
index 53412a434e..3a0df1c015 100644
--- a/zebra/zebra_evpn_mh.c
+++ b/zebra/zebra_evpn_mh.c
@@ -63,13 +63,14 @@ static void zebra_evpn_es_get_one_base_evpn(void);
static int zebra_evpn_es_evi_send_to_client(struct zebra_evpn_es *es,
zebra_evpn_t *zevpn, bool add);
static void zebra_evpn_local_es_del(struct zebra_evpn_es **esp);
-static int zebra_evpn_local_es_update(struct zebra_if *zif, uint32_t lid,
- struct ethaddr *sysmac);
+static int zebra_evpn_local_es_update(struct zebra_if *zif, esi_t *esi);
static bool zebra_evpn_es_br_port_dplane_update(struct zebra_evpn_es *es,
const char *caller);
static void zebra_evpn_mh_uplink_cfg_update(struct zebra_if *zif, bool set);
-static void zebra_evpn_mh_update_protodown_es(struct zebra_evpn_es *es);
+static void zebra_evpn_mh_update_protodown_es(struct zebra_evpn_es *es,
+ bool resync_dplane);
static void zebra_evpn_mh_clear_protodown_es(struct zebra_evpn_es *es);
+static void zebra_evpn_mh_startup_delay_timer_start(const char *rc);
esi_t zero_esi_buf, *zero_esi = &zero_esi_buf;
@@ -935,7 +936,7 @@ void zebra_evpn_if_init(struct zebra_if *zif)
/* if an es_id and sysmac are already present against the interface
* activate it
*/
- zebra_evpn_local_es_update(zif, zif->es_info.lid, &zif->es_info.sysmac);
+ zebra_evpn_local_es_update(zif, &zif->es_info.esi);
}
/* handle deletion of an access port by removing it from all associated
@@ -1469,16 +1470,16 @@ static bool zebra_evpn_es_br_port_dplane_update(struct zebra_evpn_es *es,
/* returns TRUE if dplane entry was updated */
static bool zebra_evpn_es_df_change(struct zebra_evpn_es *es, bool new_non_df,
- const char *caller)
+ const char *caller, const char *reason)
{
bool old_non_df;
old_non_df = !!(es->flags & ZEBRA_EVPNES_NON_DF);
if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
- zlog_debug("df-change(%s) es %s old %s new %s", caller,
- es->esi_str, old_non_df ? "non-df" : "df",
- new_non_df ? "non-df" : "df");
+ zlog_debug("df-change es %s %s to %s; %s: %s", es->esi_str,
+ old_non_df ? "non-df" : "df",
+ new_non_df ? "non-df" : "df", caller, reason);
if (old_non_df == new_non_df)
return false;
@@ -1506,7 +1507,8 @@ static bool zebra_evpn_es_run_df_election(struct zebra_evpn_es *es,
*/
if (!(es->flags & ZEBRA_EVPNES_LOCAL)
|| !zmh_info->es_originator_ip.s_addr)
- return zebra_evpn_es_df_change(es, new_non_df, caller);
+ return zebra_evpn_es_df_change(es, new_non_df, caller,
+ "not-ready");
/* if oper-state is down DF filtering must be on. when the link comes
* up again dataplane should block BUM till FRR has had the chance
@@ -1514,7 +1516,18 @@ static bool zebra_evpn_es_run_df_election(struct zebra_evpn_es *es,
*/
if (!(es->flags & ZEBRA_EVPNES_OPER_UP)) {
new_non_df = true;
- return zebra_evpn_es_df_change(es, new_non_df, caller);
+ return zebra_evpn_es_df_change(es, new_non_df, caller,
+ "oper-down");
+ }
+
+ /* ES was just created; we need to wait for the peers to rx the
+ * our Type-4 routes and for the switch to import the peers' Type-4
+ * routes
+ */
+ if (es->df_delay_timer) {
+ new_non_df = true;
+ return zebra_evpn_es_df_change(es, new_non_df, caller,
+ "df-delay");
}
for (ALL_LIST_ELEMENTS_RO(es->es_vtep_list, node, es_vtep)) {
@@ -1546,7 +1559,7 @@ static bool zebra_evpn_es_run_df_election(struct zebra_evpn_es *es,
}
}
- return zebra_evpn_es_df_change(es, new_non_df, caller);
+ return zebra_evpn_es_df_change(es, new_non_df, caller, "elected");
}
static void zebra_evpn_es_vtep_add(struct zebra_evpn_es *es,
@@ -1636,6 +1649,9 @@ static struct zebra_evpn_es *zebra_evpn_es_new(esi_t *esi)
{
struct zebra_evpn_es *es;
+ if (!memcmp(esi, zero_esi, sizeof(esi_t)))
+ return NULL;
+
es = XCALLOC(MTYPE_ZES, sizeof(struct zebra_evpn_es));
/* fill in ESI */
@@ -1928,6 +1944,20 @@ static void zebra_evpn_mh_dup_addr_detect_off(void)
}
}
+static int zebra_evpn_es_df_delay_exp_cb(struct thread *t)
+{
+ struct zebra_evpn_es *es;
+
+ es = THREAD_ARG(t);
+
+ if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
+ zlog_debug("es %s df-delay expired", es->esi_str);
+
+ zebra_evpn_es_run_df_election(es, __func__);
+
+ return 0;
+}
+
static void zebra_evpn_es_local_info_set(struct zebra_evpn_es *es,
struct zebra_if *zif)
{
@@ -1967,6 +1997,12 @@ static void zebra_evpn_es_local_info_set(struct zebra_evpn_es *es,
zebra_evpn_es_re_eval_send_to_client(es,
false /* es_evi_re_reval */);
+ /* Start the DF delay timer on the local ES */
+ if (!es->df_delay_timer)
+ thread_add_timer(zrouter.master, zebra_evpn_es_df_delay_exp_cb,
+ es, ZEBRA_EVPN_MH_DF_DELAY_TIME,
+ &es->df_delay_timer);
+
/* See if the local VTEP can function as DF on the ES */
if (!zebra_evpn_es_run_df_election(es, __func__)) {
/* check if the dplane entry needs to be re-programmed as a
@@ -1989,7 +2025,7 @@ static void zebra_evpn_es_local_info_set(struct zebra_evpn_es *es,
false /* force_clear_static */);
/* inherit EVPN protodown flags on the access port */
- zebra_evpn_mh_update_protodown_es(es);
+ zebra_evpn_mh_update_protodown_es(es, true /*resync_dplane*/);
}
static void zebra_evpn_es_local_info_clear(struct zebra_evpn_es **esp)
@@ -2003,6 +2039,8 @@ static void zebra_evpn_es_local_info_clear(struct zebra_evpn_es **esp)
es->flags &= ~(ZEBRA_EVPNES_LOCAL | ZEBRA_EVPNES_READY_FOR_BGP);
+ THREAD_OFF(es->df_delay_timer);
+
/* remove the DF filter */
dplane_updated = zebra_evpn_es_run_df_election(es, __func__);
@@ -2090,17 +2128,50 @@ static void zebra_evpn_es_remote_info_re_eval(struct zebra_evpn_es **esp)
/* A new local es is created when a local-es-id and sysmac is configured
* against an interface.
*/
-static int zebra_evpn_local_es_update(struct zebra_if *zif, uint32_t lid,
- struct ethaddr *sysmac)
+static int zebra_evpn_local_es_update(struct zebra_if *zif, esi_t *esi)
{
struct zebra_evpn_es *old_es = zif->es_info.es;
struct zebra_evpn_es *es;
+
+ memcpy(&zif->es_info.esi, esi, sizeof(*esi));
+ if (old_es && !memcmp(&old_es->esi, esi, sizeof(*esi)))
+ /* dup - nothing to be done */
+ return 0;
+
+ /* release the old_es against the zif */
+ if (old_es)
+ zebra_evpn_local_es_del(&old_es);
+
+ es = zebra_evpn_es_find(esi);
+ if (es) {
+ /* if it exists against another interface flag an error */
+ if (es->zif && es->zif != zif) {
+ memset(&zif->es_info.esi, 0, sizeof(*esi));
+ return -1;
+ }
+ } else {
+ /* create new es */
+ es = zebra_evpn_es_new(esi);
+ }
+
+ if (es)
+ zebra_evpn_es_local_info_set(es, zif);
+
+ return 0;
+}
+
+static int zebra_evpn_type3_esi_update(struct zebra_if *zif, uint32_t lid,
+ struct ethaddr *sysmac)
+{
+ struct zebra_evpn_es *old_es = zif->es_info.es;
esi_t esi;
int offset = 0;
int field_bytes = 0;
/* Complete config of the ES-ID bootstraps the ES */
if (!lid || is_zero_mac(sysmac)) {
+ /* clear old esi */
+ memset(&zif->es_info.esi, 0, sizeof(zif->es_info.esi));
/* if in ES is attached to zif delete it */
if (old_es)
zebra_evpn_local_es_del(&old_es);
@@ -2122,27 +2193,7 @@ static int zebra_evpn_local_es_update(struct zebra_if *zif, uint32_t lid,
esi.val[offset++] = (uint8_t)(lid >> 8);
esi.val[offset++] = (uint8_t)lid;
- if (old_es && !memcmp(&old_es->esi, &esi, sizeof(esi_t)))
- /* dup - nothing to be done */
- return 0;
-
- /* release the old_es against the zif */
- if (old_es)
- zebra_evpn_local_es_del(&old_es);
-
- es = zebra_evpn_es_find(&esi);
- if (es) {
- /* if it exists against another interface flag an error */
- if (es->zif && es->zif != zif)
- return -1;
- } else {
- /* create new es */
- es = zebra_evpn_es_new(&esi);
- }
-
- zebra_evpn_es_local_info_set(es, zif);
-
- return 0;
+ return zebra_evpn_local_es_update(zif, &esi);
}
static int zebra_evpn_remote_es_del(esi_t *esi, struct in_addr vtep_ip)
@@ -2349,7 +2400,7 @@ static int zebra_evpn_es_sys_mac_update(struct zebra_if *zif,
{
int rv;
- rv = zebra_evpn_local_es_update(zif, zif->es_info.lid, sysmac);
+ rv = zebra_evpn_type3_esi_update(zif, zif->es_info.lid, sysmac);
if (!rv)
memcpy(&zif->es_info.sysmac, sysmac, sizeof(struct ethaddr));
@@ -2361,13 +2412,29 @@ static int zebra_evpn_es_lid_update(struct zebra_if *zif, uint32_t lid)
{
int rv;
- rv = zebra_evpn_local_es_update(zif, lid, &zif->es_info.sysmac);
+ rv = zebra_evpn_type3_esi_update(zif, lid, &zif->es_info.sysmac);
if (!rv)
zif->es_info.lid = lid;
return rv;
}
+/* type-0 esi has changed */
+static int zebra_evpn_es_type0_esi_update(struct zebra_if *zif, esi_t *esi)
+{
+ int rv;
+
+ rv = zebra_evpn_local_es_update(zif, esi);
+
+ /* clear the old es_lid, es_sysmac - type-0 is being set so old
+ * type-3 params need to be flushed
+ */
+ memset(&zif->es_info.sysmac, 0, sizeof(struct ethaddr));
+ zif->es_info.lid = 0;
+
+ return rv;
+}
+
void zebra_evpn_es_cleanup(void)
{
struct zebra_evpn_es *es;
@@ -2425,10 +2492,10 @@ void zebra_evpn_if_es_print(struct vty *vty, struct zebra_if *zif)
char buf[ETHER_ADDR_STRLEN];
char mh_buf[80];
bool vty_print = false;
+ char esi_buf[ESI_STR_LEN];
mh_buf[0] = '\0';
- snprintf(mh_buf + strlen(mh_buf), sizeof(mh_buf) - strlen(mh_buf),
- " EVPN-MH:");
+ strlcat(mh_buf, " EVPN-MH:", sizeof(mh_buf));
if (zif->es_info.lid || !is_zero_mac(&zif->es_info.sysmac)) {
vty_print = true;
snprintf(
@@ -2436,17 +2503,21 @@ void zebra_evpn_if_es_print(struct vty *vty, struct zebra_if *zif)
sizeof(mh_buf) - strlen(mh_buf),
" ES id %u ES sysmac %s", zif->es_info.lid,
prefix_mac2str(&zif->es_info.sysmac, buf, sizeof(buf)));
+ } else if (memcmp(&zif->es_info.esi, zero_esi, sizeof(*zero_esi))) {
+ vty_print = true;
+ snprintf(mh_buf + strnlen(mh_buf, sizeof(mh_buf)),
+ sizeof(mh_buf) - strnlen(mh_buf, sizeof(mh_buf)),
+ " ES id %s",
+ esi_to_str(&zif->es_info.esi, esi_buf,
+ sizeof(esi_buf)));
}
if (zif->flags & ZIF_FLAG_EVPN_MH_UPLINK) {
vty_print = true;
if (zif->flags & ZIF_FLAG_EVPN_MH_UPLINK_OPER_UP)
- snprintf(mh_buf + strlen(mh_buf),
- sizeof(mh_buf) - strlen(mh_buf), " uplink-up");
+ strlcat(mh_buf, " uplink (up)", sizeof(mh_buf));
else
- snprintf(mh_buf + strlen(mh_buf),
- sizeof(mh_buf) - strlen(mh_buf),
- " uplink-down");
+ strlcat(mh_buf, " uplink (down)", sizeof(mh_buf));
}
if (vty_print)
@@ -2659,6 +2730,7 @@ static void zebra_evpn_es_show_entry_detail(struct vty *vty,
char alg_buf[EVPN_DF_ALG_STR_LEN];
struct zebra_evpn_es_vtep *es_vtep;
struct listnode *node;
+ char thread_buf[THREAD_TIMER_STRLEN];
if (json) {
json_object *json_vteps;
@@ -2695,6 +2767,12 @@ static void zebra_evpn_es_show_entry_detail(struct vty *vty,
listcount(es->es_evi_list));
json_object_int_add(json, "macCount", listcount(es->mac_list));
json_object_int_add(json, "dfPreference", es->df_pref);
+ if (es->df_delay_timer)
+ json_object_string_add(
+ json, "dfDelayTimer",
+ thread_timer_to_hhmmss(thread_buf,
+ sizeof(thread_buf),
+ es->df_delay_timer));
json_object_int_add(json, "nexthopGroup", es->nhg_id);
if (listcount(es->es_vtep_list)) {
json_vteps = json_object_new_array();
@@ -2729,9 +2807,16 @@ static void zebra_evpn_es_show_entry_detail(struct vty *vty,
"yes" : "no");
vty_out(vty, " VNI Count: %d\n", listcount(es->es_evi_list));
vty_out(vty, " MAC Count: %d\n", listcount(es->mac_list));
- vty_out(vty, " DF: status: %s preference: %u\n",
- (es->flags & ZEBRA_EVPNES_NON_DF) ? "non-df" : "df",
- es->df_pref);
+ if (es->flags & ZEBRA_EVPNES_LOCAL)
+ vty_out(vty, " DF status: %s \n",
+ (es->flags & ZEBRA_EVPNES_NON_DF) ? "non-df"
+ : "df");
+ if (es->df_delay_timer)
+ vty_out(vty, " DF delay: %s\n",
+ thread_timer_to_hhmmss(thread_buf,
+ sizeof(thread_buf),
+ es->df_delay_timer));
+ vty_out(vty, " DF preference: %u\n", es->df_pref);
vty_out(vty, " Nexthop group: %u\n", es->nhg_id);
vty_out(vty, " VTEPs:\n");
for (ALL_LIST_ELEMENTS_RO(es->es_vtep_list, node, es_vtep)) {
@@ -2833,14 +2918,25 @@ int zebra_evpn_mh_if_write(struct vty *vty, struct interface *ifp)
{
struct zebra_if *zif = ifp->info;
char buf[ETHER_ADDR_STRLEN];
+ bool type_3_esi = false;
+ char esi_buf[ESI_STR_LEN];
- if (zif->es_info.lid)
+ if (zif->es_info.lid) {
vty_out(vty, " evpn mh es-id %u\n", zif->es_info.lid);
+ type_3_esi = true;
+ }
- if (!is_zero_mac(&zif->es_info.sysmac))
+ if (!is_zero_mac(&zif->es_info.sysmac)) {
vty_out(vty, " evpn mh es-sys-mac %s\n",
prefix_mac2str(&zif->es_info.sysmac,
buf, sizeof(buf)));
+ type_3_esi = true;
+ }
+
+ if (!type_3_esi
+ && memcmp(&zif->es_info.esi, zero_esi, sizeof(*zero_esi)))
+ vty_out(vty, " evpn mh es-id %s\n",
+ esi_to_str(&zif->es_info.esi, esi_buf, sizeof(esi_buf)));
if (zif->es_info.df_pref)
vty_out(vty, " evpn mh es-df-pref %u\n", zif->es_info.df_pref);
@@ -2929,22 +3025,28 @@ DEFPY(zebra_evpn_es_sys_mac,
/* CLI for setting up local-ID part of ESI on an access port */
DEFPY(zebra_evpn_es_id,
zebra_evpn_es_id_cmd,
- "[no$no] evpn mh es-id [(1-16777215)$es_lid]",
+ "[no$no] evpn mh es-id [(1-16777215)$es_lid | NAME$esi_str]",
NO_STR
"EVPN\n"
EVPN_MH_VTY_STR
- "Ethernet segment local identifier\n"
- "ID\n"
+ "Ethernet segment identifier\n"
+ "local discriminator\n"
+ "10-byte ID - 00:AA:BB:CC:DD:EE:FF:GG:HH:II\n"
)
{
VTY_DECLVAR_CONTEXT(interface, ifp);
struct zebra_if *zif;
- int ret;
+ int ret = 0;
+ esi_t esi;
zif = ifp->info;
if (no) {
- ret = zebra_evpn_es_lid_update(zif, 0);
+ if (zif->es_info.lid)
+ ret = zebra_evpn_es_lid_update(zif, 0);
+ else if (memcmp(&zif->es_info.esi, zero_esi, sizeof(*zero_esi)))
+ ret = zebra_evpn_es_type0_esi_update(zif, zero_esi);
+
if (ret == -1) {
vty_out(vty, "%%Failed to clear ES local id\n");
return CMD_WARNING;
@@ -2956,14 +3058,23 @@ DEFPY(zebra_evpn_es_id,
return CMD_WARNING;
}
- if (!es_lid) {
- vty_out(vty, "%%Specify local ES ID\n");
- return CMD_WARNING;
+ if (esi_str) {
+ if (!str_to_esi(esi_str, &esi)) {
+ vty_out(vty, "%% Malformed ESI\n");
+ return CMD_WARNING;
+ }
+ ret = zebra_evpn_es_type0_esi_update(zif, &esi);
+ } else {
+ if (!es_lid) {
+ vty_out(vty, "%%Specify local ES ID\n");
+ return CMD_WARNING;
+ }
+ ret = zebra_evpn_es_lid_update(zif, es_lid);
}
- ret = zebra_evpn_es_lid_update(zif, es_lid);
+
if (ret == -1) {
vty_out(vty,
- "%%ESI already exists on a different interface\n");
+ "%%ESI already exists on a different interface\n");
return CMD_WARNING;
}
}
@@ -3029,7 +3140,7 @@ void zebra_evpn_mh_print(struct vty *vty)
vty_out(vty, " uplink-cfg-cnt: %u, uplink-active-cnt: %u\n",
zmh_info->uplink_cfg_cnt, zmh_info->uplink_oper_up_cnt);
if (zmh_info->protodown_rc)
- vty_out(vty, " protodown: %s\n",
+ vty_out(vty, " protodown reasons: %s\n",
zebra_protodown_rc_str(zmh_info->protodown_rc, pd_buf,
sizeof(pd_buf)));
}
@@ -3174,16 +3285,14 @@ void zebra_evpn_mh_update_protodown_bond_mbr(struct zebra_if *zif, bool clear,
protodown_rc = bond_zif->protodown_rc;
}
- if (zif->protodown_rc == protodown_rc)
- return;
-
old_protodown = !!(zif->flags & ZIF_FLAG_PROTODOWN);
old_protodown_rc = zif->protodown_rc;
zif->protodown_rc &= ~ZEBRA_PROTODOWN_EVPN_ALL;
zif->protodown_rc |= (protodown_rc & ZEBRA_PROTODOWN_EVPN_ALL);
new_protodown = !!zif->protodown_rc;
- if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
+ if (IS_ZEBRA_DEBUG_EVPN_MH_ES
+ && (zif->protodown_rc != old_protodown_rc))
zlog_debug(
"%s bond mbr %s protodown_rc changed; old 0x%x new 0x%x",
caller, zif->ifp->name, old_protodown_rc,
@@ -3220,14 +3329,20 @@ static void zebra_evpn_mh_update_protodown_bond(struct zebra_if *bond_zif)
}
/* The global EVPN MH protodown rc is applied to all local ESs */
-static void zebra_evpn_mh_update_protodown_es(struct zebra_evpn_es *es)
+static void zebra_evpn_mh_update_protodown_es(struct zebra_evpn_es *es,
+ bool resync_dplane)
{
struct zebra_if *zif;
enum protodown_reasons old_protodown_rc;
zif = es->zif;
- if ((zif->protodown_rc & ZEBRA_PROTODOWN_EVPN_ALL)
- == (zmh_info->protodown_rc & ZEBRA_PROTODOWN_EVPN_ALL))
+ /* if the reason code is the same bail unless it is a new
+ * ES bond in that case we would need to ensure that the
+ * dplane is really in sync with zebra
+ */
+ if (!resync_dplane
+ && (zif->protodown_rc & ZEBRA_PROTODOWN_EVPN_ALL)
+ == (zmh_info->protodown_rc & ZEBRA_PROTODOWN_EVPN_ALL))
return;
old_protodown_rc = zif->protodown_rc;
@@ -3235,7 +3350,8 @@ static void zebra_evpn_mh_update_protodown_es(struct zebra_evpn_es *es)
zif->protodown_rc |=
(zmh_info->protodown_rc & ZEBRA_PROTODOWN_EVPN_ALL);
- if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
+ if (IS_ZEBRA_DEBUG_EVPN_MH_ES
+ && (old_protodown_rc != zif->protodown_rc))
zlog_debug(
"es %s ifp %s protodown_rc changed; old 0x%x new 0x%x",
es->esi_str, zif->ifp->name, old_protodown_rc,
@@ -3273,7 +3389,7 @@ static void zebra_evpn_mh_update_protodown_es_all(void)
struct zebra_evpn_es *es;
for (ALL_LIST_ELEMENTS_RO(zmh_info->local_es_list, node, es))
- zebra_evpn_mh_update_protodown_es(es);
+ zebra_evpn_mh_update_protodown_es(es, false /*resync_dplane*/);
}
static void zebra_evpn_mh_update_protodown(enum protodown_reasons protodown_rc,
@@ -3381,6 +3497,13 @@ void zebra_evpn_mh_uplink_oper_update(struct zebra_if *zif)
if (old_protodown == new_protodown)
return;
+ /* if protodown_rc XXX_UPLINK_DOWN is about to be cleared
+ * fire up the start-up delay timer to allow the EVPN network
+ * to converge (Type-2 routes need to be advertised and processed)
+ */
+ if (!new_protodown && (zmh_info->uplink_oper_up_cnt == 1))
+ zebra_evpn_mh_startup_delay_timer_start("uplink-up");
+
zebra_evpn_mh_update_protodown(ZEBRA_PROTODOWN_EVPN_UPLINK_DOWN,
new_protodown);
}
@@ -3396,26 +3519,19 @@ static int zebra_evpn_mh_startup_delay_exp_cb(struct thread *t)
return 0;
}
-static void zebra_evpn_mh_startup_delay_timer_start(bool init)
+static void zebra_evpn_mh_startup_delay_timer_start(const char *rc)
{
- /* 1. This timer can be started during init.
- * 2. It can also be restarted if it is alreay running and the
- * admin wants to increase or decrease its value
- */
- if (!init && !zmh_info->startup_delay_timer)
- return;
-
if (zmh_info->startup_delay_timer) {
if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
zlog_debug("startup-delay timer cancelled");
- thread_cancel(&zmh_info->startup_delay_timer);
- zmh_info->startup_delay_timer = NULL;
+ THREAD_OFF(zmh_info->startup_delay_timer);
}
if (zmh_info->startup_delay_time) {
if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
- zlog_debug("startup-delay timer started for %d sec",
- zmh_info->startup_delay_time);
+ zlog_debug(
+ "startup-delay timer started for %d sec on %s",
+ zmh_info->startup_delay_time, rc);
thread_add_timer(zrouter.master,
zebra_evpn_mh_startup_delay_exp_cb, NULL,
zmh_info->startup_delay_time,
@@ -3476,7 +3592,12 @@ int zebra_evpn_mh_startup_delay_update(struct vty *vty, uint32_t duration,
duration = ZEBRA_EVPN_MH_STARTUP_DELAY_DEF;
zmh_info->startup_delay_time = duration;
- zebra_evpn_mh_startup_delay_timer_start(false /* init */);
+
+ /* if startup_delay_timer is running allow it to be adjusted
+ * up or down
+ */
+ if (zmh_info->startup_delay_timer)
+ zebra_evpn_mh_startup_delay_timer_start("config");
return 0;
}
@@ -3526,7 +3647,7 @@ void zebra_evpn_mh_init(void)
zebra_evpn_acc_vl_cmp, "access VLAN hash table");
zmh_info->startup_delay_time = ZEBRA_EVPN_MH_STARTUP_DELAY_DEF;
- zebra_evpn_mh_startup_delay_timer_start(true /*init*/);
+ zebra_evpn_mh_startup_delay_timer_start("init");
}
void zebra_evpn_mh_terminate(void)
diff --git a/zebra/zebra_evpn_mh.h b/zebra/zebra_evpn_mh.h
index dc2c299cf2..14b2987574 100644
--- a/zebra/zebra_evpn_mh.h
+++ b/zebra/zebra_evpn_mh.h
@@ -88,6 +88,13 @@ struct zebra_evpn_es {
* advertised via the ESR
*/
uint16_t df_pref;
+
+ /* When a new ES is configured it is held in a non-DF state
+ * for 3 seconds. This allows the peer Type-4 routes to be
+ * imported before running the DF election.
+ */
+#define ZEBRA_EVPN_MH_DF_DELAY_TIME 3 /* seconds */
+ struct thread *df_delay_timer;
};
RB_HEAD(zebra_es_rb_head, zebra_evpn_es);
RB_PROTOTYPE(zebra_es_rb_head, zebra_evpn_es, rb_node, zebra_es_rb_cmp);
diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c
index 266050784a..f18d8fbb6d 100644
--- a/zebra/zebra_vty.c
+++ b/zebra/zebra_vty.c
@@ -1331,7 +1331,7 @@ DEFUN (ip_nht_default_route,
zvrf->zebra_rnh_ip_default_route = 1;
- zebra_evaluate_rnh(zvrf, AFI_IP, 1, RNH_NEXTHOP_TYPE, NULL);
+ zebra_evaluate_rnh(zvrf, AFI_IP, 0, RNH_NEXTHOP_TYPE, NULL);
return CMD_SUCCESS;
}
@@ -1653,7 +1653,7 @@ DEFUN (no_ip_nht_default_route,
return CMD_SUCCESS;
zvrf->zebra_rnh_ip_default_route = 0;
- zebra_evaluate_rnh(zvrf, AFI_IP, 1, RNH_NEXTHOP_TYPE, NULL);
+ zebra_evaluate_rnh(zvrf, AFI_IP, 0, RNH_NEXTHOP_TYPE, NULL);
return CMD_SUCCESS;
}
@@ -1673,7 +1673,7 @@ DEFUN (ipv6_nht_default_route,
return CMD_SUCCESS;
zvrf->zebra_rnh_ipv6_default_route = 1;
- zebra_evaluate_rnh(zvrf, AFI_IP6, 1, RNH_NEXTHOP_TYPE, NULL);
+ zebra_evaluate_rnh(zvrf, AFI_IP6, 0, RNH_NEXTHOP_TYPE, NULL);
return CMD_SUCCESS;
}
@@ -1695,7 +1695,7 @@ DEFUN (no_ipv6_nht_default_route,
return CMD_SUCCESS;
zvrf->zebra_rnh_ipv6_default_route = 0;
- zebra_evaluate_rnh(zvrf, AFI_IP6, 1, RNH_NEXTHOP_TYPE, NULL);
+ zebra_evaluate_rnh(zvrf, AFI_IP6, 0, RNH_NEXTHOP_TYPE, NULL);
return CMD_SUCCESS;
}
diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c
index 09cb1cffc1..28bed846cf 100644
--- a/zebra/zebra_vxlan.c
+++ b/zebra/zebra_vxlan.c
@@ -116,7 +116,7 @@ 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_sg_cleanup(struct hash_bucket *bucket, void *arg);
+static void zebra_vxlan_cleanup_sg_table(struct zebra_vrf *zvrf);
bool zebra_evpn_do_dup_addr_detect(struct zebra_vrf *zvrf)
{
@@ -5784,7 +5784,7 @@ void zebra_vxlan_cleanup_tables(struct zebra_vrf *zvrf)
if (!zvrf)
return;
hash_iterate(zvrf->evpn_table, zebra_evpn_vxlan_cleanup_all, zvrf);
- hash_iterate(zvrf->vxlan_sg_table, zebra_vxlan_sg_cleanup, NULL);
+ zebra_vxlan_cleanup_sg_table(zvrf);
if (zvrf == evpn_zvrf)
zebra_evpn_es_cleanup();
@@ -5797,6 +5797,11 @@ void zebra_vxlan_close_tables(struct zebra_vrf *zvrf)
return;
hash_iterate(zvrf->evpn_table, zebra_evpn_vxlan_cleanup_all, zvrf);
hash_free(zvrf->evpn_table);
+ if (zvrf->vxlan_sg_table) {
+ zebra_vxlan_cleanup_sg_table(zvrf);
+ hash_free(zvrf->vxlan_sg_table);
+ zvrf->vxlan_sg_table = NULL;
+ }
}
/* init the l3vni table */
@@ -6045,6 +6050,30 @@ static void zebra_vxlan_sg_ref(struct in_addr local_vtep_ip,
zebra_vxlan_sg_do_ref(zvrf, local_vtep_ip, mcast_grp);
}
+static void zebra_vxlan_xg_pre_cleanup(struct hash_bucket *backet, void *arg)
+{
+ zebra_vxlan_sg_t *vxlan_sg = (zebra_vxlan_sg_t *)backet->data;
+
+ /* increment the ref count against (*,G) to prevent them from being
+ * deleted
+ */
+ if (vxlan_sg->sg.src.s_addr == INADDR_ANY)
+ ++vxlan_sg->ref_cnt;
+}
+
+static void zebra_vxlan_xg_post_cleanup(struct hash_bucket *backet, void *arg)
+{
+ zebra_vxlan_sg_t *vxlan_sg = (zebra_vxlan_sg_t *)backet->data;
+
+ /* decrement the dummy ref count against (*,G) to delete them */
+ if (vxlan_sg->sg.src.s_addr == INADDR_ANY) {
+ if (vxlan_sg->ref_cnt)
+ --vxlan_sg->ref_cnt;
+ if (!vxlan_sg->ref_cnt)
+ zebra_vxlan_sg_del(vxlan_sg);
+ }
+}
+
static void zebra_vxlan_sg_cleanup(struct hash_bucket *backet, void *arg)
{
zebra_vxlan_sg_t *vxlan_sg = (zebra_vxlan_sg_t *)backet->data;
@@ -6052,6 +6081,19 @@ static void zebra_vxlan_sg_cleanup(struct hash_bucket *backet, void *arg)
zebra_vxlan_sg_del(vxlan_sg);
}
+static void zebra_vxlan_cleanup_sg_table(struct zebra_vrf *zvrf)
+{
+ /* increment the ref count against (*,G) to prevent them from being
+ * deleted
+ */
+ hash_iterate(zvrf->vxlan_sg_table, zebra_vxlan_xg_pre_cleanup, NULL);
+
+ hash_iterate(zvrf->vxlan_sg_table, zebra_vxlan_sg_cleanup, NULL);
+
+ /* decrement the dummy ref count against the XG entries */
+ hash_iterate(zvrf->vxlan_sg_table, zebra_vxlan_xg_post_cleanup, NULL);
+}
+
static void zebra_vxlan_sg_replay_send(struct hash_bucket *backet, void *arg)
{
zebra_vxlan_sg_t *vxlan_sg = (zebra_vxlan_sg_t *)backet->data;