diff --git a/aci-preupgrade-validation-script.py b/aci-preupgrade-validation-script.py index b420eea..2bf8187 100644 --- a/aci-preupgrade-validation-script.py +++ b/aci-preupgrade-validation-script.py @@ -3756,6 +3756,25 @@ def isis_redis_metric_mpod_msite_check(**kwargs): return Result(result=result, headers=headers, data=data, recommended_action=recommended_action, doc_url=doc_url) +@check_wrapper(check_title="Fabric BFD on ISIS") +def fabric_bfd_isis_check(**kwargs): + result = PASS + headers = ["L3 Interface Policy DN"] + data = [] + recommended_action = 'Prior to upgrade or downgrade, disable Fabric BFD on ISIS.' + doc_url = 'https://datacenter.github.io/ACI-Pre-Upgrade-Validation-Script/validations/#fabric-bfd-on-isis' + + l3IfPols = icurl('class', 'l3IfPol.json') + for pol in l3IfPols: + if pol['l3IfPol']['attributes'].get('bfdIsis') == 'enabled': + data.append([pol['l3IfPol']['attributes']['dn']]) + + if data: + result = FAIL_O + + return Result(result=result, headers=headers, data=data, recommended_action=recommended_action, doc_url=doc_url) + + @check_wrapper(check_title="BGP route target type for GOLF over L2EVPN") def bgp_golf_route_target_type_check(cversion, tversion, **kwargs): result = FAIL_O @@ -6465,6 +6484,7 @@ class CheckManager: l3out_overlapping_loopback_check, intersight_upgrade_status_check, isis_redis_metric_mpod_msite_check, + fabric_bfd_isis_check, bgp_golf_route_target_type_check, docker0_subnet_overlap_check, uplink_limit_check, diff --git a/docs/docs/validations.md b/docs/docs/validations.md index 64d5955..dbcbfc5 100644 --- a/docs/docs/validations.md +++ b/docs/docs/validations.md @@ -201,6 +201,7 @@ Items | Defect | This Script [N9K-C9408 with more than 5 N9K-X9400-16W LEMs][d31] | CSCws82819 | :white_check_mark: | :no_entry_sign: [Multi-Pod Modular Spine Bootscript File][d32] | CSCwr66848 | :white_check_mark: | :no_entry_sign: [Inband Management Policy Misconfiguration][d33]| CSCwd40071 | :white_check_mark: | :no_entry_sign: +[Fabric BFD on ISIS][d34] | N/A | :white_check_mark: | :no_entry_sign: [d1]: #ep-announce-compatibility [d2]: #eventmgr-db-size-defect-susceptibility @@ -235,6 +236,7 @@ Items | Defect | This Script [d31]: #n9k-c9408-with-more-than-5-n9k-x9400-16w-lems [d32]: #multi-pod-modular-spine-bootscript-file [d33]: #inband-management-policy-misconfiguration +[d34]: #fabric-bfd-on-isis ## General Check Details @@ -2701,6 +2703,16 @@ Do not upgrade to any affected ACI software release if this check fails. Nexus Dashboard Insights (NDI) integration can cause ACI tech support generation to happen automatically as part of the bug scan feature. +### Fabric BFD on ISIS + +Enabling Fabric BFD (BFD on ISIS) is not recommended. The operational benefit is minimal to none, while the potential adverse impact is significantly higher: + +* In a leaf-spine fabric, ISIS peers are directly connected sub-interfaces. If a peer device goes down, the physical link also goes down, which triggers Layer-1 convergence. In such scenarios — the vast majority of failure cases — BFD provides no additional convergence benefit. +* BFD is susceptible to false flaps when BFD packets do not receive sufficient CPU cycles (for example, during periods of high CPU utilization such as tech-support collections). False BFD flaps directly impact ISIS adjacencies, which can destabilize the entire fabric control plane. + +This check fails if any `l3IfPol` (Fabric > Fabric Policies > Policies > Interface > L3 Interface) has `bfdIsis` set to `enabled`. Disable Fabric BFD on ISIS before upgrade or downgrade. + + ### Policydist configpushShardCont crash In ACI, there are internal objects which track the underlying transactions which occur as policies are handled by the Policydist process. One such object is `configpushShardCont` which populates the `headTx` and `tailTx` parameters to mark any potentially stuck transactions. diff --git a/tests/checks/fabric_bfd_isis_check/bfd_isis_disabled.json b/tests/checks/fabric_bfd_isis_check/bfd_isis_disabled.json new file mode 100644 index 0000000..246f224 --- /dev/null +++ b/tests/checks/fabric_bfd_isis_check/bfd_isis_disabled.json @@ -0,0 +1,10 @@ +[ + { + "l3IfPol": { + "attributes": { + "bfdIsis": "disabled", + "dn": "uni/fabric/l3IfP-default" + } + } + } +] diff --git a/tests/checks/fabric_bfd_isis_check/bfd_isis_enabled.json b/tests/checks/fabric_bfd_isis_check/bfd_isis_enabled.json new file mode 100644 index 0000000..4d83a31 --- /dev/null +++ b/tests/checks/fabric_bfd_isis_check/bfd_isis_enabled.json @@ -0,0 +1,10 @@ +[ + { + "l3IfPol": { + "attributes": { + "bfdIsis": "enabled", + "dn": "uni/fabric/l3IfP-default" + } + } + } +] diff --git a/tests/checks/fabric_bfd_isis_check/bfd_isis_mixed.json b/tests/checks/fabric_bfd_isis_check/bfd_isis_mixed.json new file mode 100644 index 0000000..fa63f9e --- /dev/null +++ b/tests/checks/fabric_bfd_isis_check/bfd_isis_mixed.json @@ -0,0 +1,26 @@ +[ + { + "l3IfPol": { + "attributes": { + "bfdIsis": "disabled", + "dn": "uni/fabric/l3IfP-default" + } + } + }, + { + "l3IfPol": { + "attributes": { + "bfdIsis": "enabled", + "dn": "uni/fabric/l3IfP-custom1" + } + } + }, + { + "l3IfPol": { + "attributes": { + "bfdIsis": "enabled", + "dn": "uni/fabric/l3IfP-custom2" + } + } + } +] diff --git a/tests/checks/fabric_bfd_isis_check/no_l3IfPol.json b/tests/checks/fabric_bfd_isis_check/no_l3IfPol.json new file mode 100644 index 0000000..fe51488 --- /dev/null +++ b/tests/checks/fabric_bfd_isis_check/no_l3IfPol.json @@ -0,0 +1 @@ +[] diff --git a/tests/checks/fabric_bfd_isis_check/test_fabric_bfd_isis_check.py b/tests/checks/fabric_bfd_isis_check/test_fabric_bfd_isis_check.py new file mode 100644 index 0000000..b76897b --- /dev/null +++ b/tests/checks/fabric_bfd_isis_check/test_fabric_bfd_isis_check.py @@ -0,0 +1,33 @@ +import os +import pytest +import logging +import importlib +from helpers.utils import read_data + +script = importlib.import_module("aci-preupgrade-validation-script") + +log = logging.getLogger(__name__) +dir = os.path.dirname(os.path.abspath(__file__)) + +test_function = "fabric_bfd_isis_check" + +# icurl queries +api = 'l3IfPol.json' + + +@pytest.mark.parametrize( + "icurl_outputs, expected_result", + [ + # No l3IfPol MOs returned + ({api: read_data(dir, "no_l3IfPol.json")}, script.PASS), + # bfdIsis disabled on the default policy + ({api: read_data(dir, "bfd_isis_disabled.json")}, script.PASS), + # bfdIsis enabled on the default policy + ({api: read_data(dir, "bfd_isis_enabled.json")}, script.FAIL_O), + # Multiple l3IfPol MOs - some enabled, some disabled + ({api: read_data(dir, "bfd_isis_mixed.json")}, script.FAIL_O), + ], +) +def test_logic(run_check, mock_icurl, expected_result): + result = run_check() + assert result.result == expected_result