Skip to content

huawei bgp: fix patch ordering and nested config re-apply on IP peer asn-number change#566

Open
vaneuk wants to merge 1 commit into
annetutil:mainfrom
vaneuk:hu_rules
Open

huawei bgp: fix patch ordering and nested config re-apply on IP peer asn-number change#566
vaneuk wants to merge 1 commit into
annetutil:mainfrom
vaneuk:hu_rules

Conversation

@vaneuk

@vaneuk vaneuk commented May 27, 2026

Copy link
Copy Markdown

Summary

Huawei does not allow changing the AS number of an existing IP BGP peer in place:

[~huawei-sw] peer 1.1.1.1 as-number 2
Error: The peer already exists in AS 12345.

There is also no undo peer X as-number Y command for an IP peer — you
can't surgically remove only the as-number. The only way to change an IP
peer's as-number is to fully recreate the peer:

undo peer 1.1.1.1
peer 1.1.1.1 as-number 12345

undo peer X destroys every per-peer setting under every family block,
so the nested configuration must be re-applied after recreation.

After undo peer X, any per-option undo on that peer fails:

[~...-bgp]undo peer 1.1.1.1
Warning: All the configurations related to the BGP peer will be deleted. Continue? [Y/N]:y
[*...-bgp] ipv4-family unicast
[*...-bgp-af-ipv4]undo peer 1.1.1.1 enable
Error: The peer session does not exist.

The goal is for annet to produce clean patches: no commands that the device will reject, even if the deployment runner would mask the errors.
This drives both the ordering choices and the diff_logic.

Today, given the running config:

bgp 65536
  peer 1.1.1.1 as-number 12345
  ipv4-family unicast
    peer 1.1.1.1 enable
    peer 1.1.1.1 route-policy DENY_ALL import
    quit
  quit

and a target that changes only the as-number to 1234, annet produces a patch the device rejects:

bgp 65536
  peer 1.1.1.1 as-number 1234      # rejected: peer already exists in AS 12345
  undo peer 1.1.1.1
  quit

After this PR:

bgp 65536
  undo peer 1.1.1.1
  peer 1.1.1.1 as-number 1234
  ipv4-family unicast
    peer 1.1.1.1 enable
    peer 1.1.1.1 route-policy DENY_ALL import
    quit
  quit

A full peer deletion is also cleaner. Before:

bgp 65536
  undo peer 1.1.1.1 description    # redundant — peer about to be wiped
  undo peer 1.1.1.1
  ipv4-family unicast
    undo peer 1.1.1.1 enable        # redundant — peer no longer exists
    undo peer 1.1.1.1 route-policy DENY_ALL import
    quit
  quit

After:

bgp 65536
  undo peer 1.1.1.1
  quit

Peers under a VPN address-family

A peer <ip> can also be declared inside a vpn-instance block (ipv4-family vpn-instance EXAMPLE). The same recreate-and-re-apply logic applies, scoped to that block — undo peer <ip> is emitted inside the vpn-instance and only wipes that block's rows.

As-number change of a VPN peer (the unchanged route-policy is re-applied after the wipe):

bgp 65536
  ipv4-family vpn-instance EXAMPLE
    undo peer 192.0.2.1
    peer 192.0.2.1 as-number 1234
    peer 192.0.2.1 route-policy DENY_ALL import
    quit
  quit

Full removal of a VPN peer collapses to a single in-block undo peer <ip> (a sibling peer in the same block is untouched):

bgp 65536
  ipv4-family vpn-instance EXAMPLE
    undo peer 192.0.2.1
    quit
  quit

The vpn-instance boundary is a separate peer namespace: the same IP can be a
peer in two different vpn-instances, or both a global peer and a VPN peer,
and a wipe in one scope must never leak into another. These isolation cases
need their full multi-VRF before/after to make sense, so see the test
fixtures rather than an excerpt here:
huawei_peer_as_number_change_vpn_isolation.yaml
and
huawei_peer_full_removal_vpn_isolation.yaml.

Scope

This PR fixes IP peer as-number change and full removal, whether the
peer is declared at the bgp top level or inside an address-family /
vpn-instance block (e.g. ipv4-family vpn-instance EXAMPLE).

Peer-group removal is out of scope.

Changes

  1. annet/rulebook/texts/huawei.order — inside the bgp block, add
    two end-anchored rules above the family sub-block:

    • undo peer ~/[^\s]+$/ %order_reverse — matches exactly 3-token
      undo peer X (IP peer destroy). The ~/regex/ escape hatch is used
      to inject a literal $ end-anchor; otherwise undo peer * would be
      a greedy prefix pattern shadowing every more-specific undo peer …
      rule deeper in the file.
    • undo peer * as-number %order_reverse — matches undo peer X as-number (4-token, peer-group as-number undo). Terminates at the
      literal as-number, so it doesn't bleed onto undo peer X connect-interface etc.

    Other per-option undo peer … rules (description, * * *, * *)
    stay at their original after-family positions.

  2. annet/rulebook/texts/huawei.rul — attach
    %diff_logic=annet.rulebook.huawei.bgp.reapply_after_as_number_change
    to the bgp rule.

  3. annet/rulebook/huawei/bgp.py — new reapply_after_as_number_change
    that runs at diff-build time over the bgp subtree, recursing block by
    block (_rewrite_block). The peer <ip> as-number … row can live at the
    bgp top level or inside a family / vpn-instance block, so each block
    computes:

    • wiped — IPs whose peer <ip> as-number … row is in this block's old
      but not new (full removal or as-number value change), unioned with
      wiped IPs inherited from enclosing blocks (a top-level undo peer <ip>
      wipes the global family blocks too). huawei.bgp.peer emits undo peer <ip> for these.
    • recreated — subset that still has a peer <ip> as-number … row in
      new (renumbered, not deleted).

    And rewrites the diff:

    • Drops every peer <ip> … REMOVED row whose IP is in wiped
      (redundant after undo peer <ip> and would error against a nonexistent
      peer) — except the REMOVED peer <ip> as-number Y row, which is kept as
      the trigger that drives huawei.bgp.peer to emit undo peer <ip>.
    • Flips peer <ip> … AFFECTED rows to ADDED when the IP is in
      recreated, so the re-emit happens after undo peer <ip>.
    • Resets the inherited sets at a vpn-instance boundary: a vpn-instance
      peer is a separate namespace and its undo peer <ip> only wipes within
      that block, so an identically-numbered peer in another vpn-instance is
      left untouched.

    No huawei.order change is needed for the vpn-instance case — ordering
    inside a family block already emits undo peer before peer as-number
    before the re-applied options.

Tests

  • Two pre-existing golden patches updated:
  • Six new YAMLs for top-level peers in tests/annet/test_patch/
    covering IPv4 / IPv6 as-number changes, peer-group as-number rename
    (regression for the 4-token order rule), an unrelated sibling peer
    (untouched), a route-policy rename (no spurious undo), and full peer
    removal for both v4 and v6.
  • Five new YAMLs for peers declared inside a vpn-instance block:
    IPv4 / IPv6 as-number change (unchanged route-policy re-applied), full
    removal (collapses to a single undo peer <ip>, sibling peer untouched),
    and three isolation cases proving a wipe in one scope never leaks into
    another:
    • same IP in two vpn-instances, only ONE's as-number changes;
    • same IP as a global peer and a vpn-instance peer, only the global peer's
      as-number changes (the VPN peer is untouched);
    • same IP in two vpn-instances (mirroring a lab transcript), only one
      VRF's peer is removed (the other VRF's peer, with its route-policy,
      survives).
  • All addresses are from the IANA documentation pools 192.0.2.0/24 and
    2001:db8::/32.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant