diff options
| -rw-r--r-- | bgpd/bgp_conditional_adv.c | 7 | ||||
| -rw-r--r-- | bgpd/bgp_damp.c | 3 | ||||
| -rw-r--r-- | bgpd/bgp_fsm.c | 3 | ||||
| -rw-r--r-- | bgpd/bgp_route.c | 18 | ||||
| -rw-r--r-- | bgpd/bgp_vty.c | 172 | ||||
| -rw-r--r-- | doc/user/overview.rst | 6 | ||||
| -rw-r--r-- | lib/lib_vty.c | 4 | ||||
| -rw-r--r-- | pimd/pim_cmd.c | 2 | ||||
| -rw-r--r-- | pimd/pim_vty.c | 7 | ||||
| -rw-r--r-- | tests/topotests/ospf_basic_functionality/test_ospf_authentication.py | 5 | ||||
| -rw-r--r-- | tests/topotests/ospf_basic_functionality/test_ospf_lan.py | 7 | ||||
| -rw-r--r-- | tests/topotests/ospf_basic_functionality/test_ospf_single_area.py | 5 | ||||
| -rw-r--r-- | vtysh/vtysh.c | 2 | ||||
| -rw-r--r-- | vtysh/vtysh.h | 2 | ||||
| -rw-r--r-- | vtysh/vtysh_config.c | 12 | ||||
| -rw-r--r-- | vtysh/vtysh_main.c | 10 | ||||
| -rw-r--r-- | zebra/if_netlink.c | 2 | ||||
| -rw-r--r-- | zebra/interface.c | 17 | ||||
| -rw-r--r-- | zebra/interface.h | 4 | ||||
| -rw-r--r-- | zebra/zebra_evpn_mh.c | 287 | ||||
| -rw-r--r-- | zebra/zebra_evpn_mh.h | 7 | ||||
| -rw-r--r-- | zebra/zebra_vty.c | 8 | ||||
| -rw-r--r-- | zebra/zebra_vxlan.c | 46 |
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; |
