diff --git a/docs/caveats.md b/docs/caveats.md index 7536ddcd36..0781ff5913 100644 --- a/docs/caveats.md +++ b/docs/caveats.md @@ -169,7 +169,8 @@ and validation. Configuration is deployed with a bash script executed within the * We did not implement OSPFv3 for ASAv * ASAv static routes require an outgoing interface. *netlab* does not configure static routes with indirect next hops on ASAv. * ASAv does not support equal-cost static routes over multiple interfaces. *netlab* configures only the first next hop of a static route. -* ASAv releases before 9.18(2) do not support loopback interfaces. As *netlab* uses loopback interfaces for iBGP sessions, iBGP sessions with ASAv nodes are not configured. Use eBGP sessions instead. +* ASAv releases before 9.18(2) do not support loopback interfaces; *netlab* does not configure them by default. Set `loopback: true` on ASAv nodes running release 9.18(2) or later. +* *netlab* uses loopback interfaces for IBGP sessions. IBGP sessions with ASAv nodes that have no loopback interface do not work; use EBGP sessions instead. * OSPF routes are not imported into the IPv6 BGP address family (OSPFv3 is not implemented). Routing policies cannot be used with route import. (caveats-cat8000v)= diff --git a/netsim/ansible/templates/bgp/asa.j2 b/netsim/ansible/templates/bgp/asa.j2 index 635d28e029..ff50f3afa3 100644 --- a/netsim/ansible/templates/bgp/asa.j2 +++ b/netsim/ansible/templates/bgp/asa.j2 @@ -9,8 +9,7 @@ router bgp {{ bgp.as }} {% for af in ['ipv4','ipv6'] if bgp[af] is defined %} address-family {{ af }} unicast {% for n in bgp.neighbors if n[af] is defined %} - neighbor {{ n[af] }} remote-as {{ n.as }} - neighbor {{ n[af] }} description {{ n.name }} +{{ bgpcfg.neighbor_global(n,n[af]) }} {% endfor %} {% if bgp.import is defined %} {{ redistribute.config(bgp,af=af,ospf_pid=ospf.process|default(1))|indent(2,first=True) }} diff --git a/netsim/ansible/templates/bgp/asa.macro.j2 b/netsim/ansible/templates/bgp/asa.macro.j2 index 5b4065d6f6..aa3f7d1409 100644 --- a/netsim/ansible/templates/bgp/asa.macro.j2 +++ b/netsim/ansible/templates/bgp/asa.macro.j2 @@ -1,3 +1,13 @@ +{# + BGP neighbor definition: remote-as, description, update-source +#} +{% macro neighbor_global(n,ip) %} + neighbor {{ ip }} remote-as {{ n.as }} + neighbor {{ ip }} description {{ n.name }} +{% if n._source_intf is defined %} + neighbor {{ ip }} update-source {{ n._source_intf.ifname }} +{% endif %} +{%- endmacro -%} {# Address family BGP neighbor definition #} diff --git a/netsim/ansible/templates/initial/asa.j2 b/netsim/ansible/templates/initial/asa.j2 index 35edda3197..29beb07c6c 100644 --- a/netsim/ansible/templates/initial/asa.j2 +++ b/netsim/ansible/templates/initial/asa.j2 @@ -9,6 +9,17 @@ name {{ v.loopback.ipv4|ansible.utils.ipaddr('address') }} {{ k }} {% endfor %} {% endif %} ! +{% if loopback is defined %} +interface {{ loopback.ifname }} + nameif {{ loopback.ifname }} +{% if 'ipv4' in loopback %} + ip address {{ loopback.ipv4|ansible.utils.ipaddr('address') }} {{ loopback.ipv4|ansible.utils.ipaddr('netmask') }} +{% endif %} +{% if 'ipv6' in loopback %} + ipv6 address {{ loopback.ipv6|upper }} +{% endif %} +{% endif %} +! {% for l in interfaces|default([]) %} interface {{ l.ifname }} {% if l.shutdown|default(False) %} diff --git a/netsim/devices/asav.py b/netsim/devices/asav.py index 897c4e366a..c4674808e3 100644 --- a/netsim/devices/asav.py +++ b/netsim/devices/asav.py @@ -21,6 +21,19 @@ def check_isis_p2p_interfaces(node: Box, topology: Box, igp: str = 'isis') -> No more_data=[ f'Node {node.name} {intf.ifname} ({intf.name})' ], category=log.IncorrectType) +def check_ibgp_loopback(node: Box) -> None: + if 'loopback' in node: + return + if not any(n.type == 'ibgp' for n in node.get('bgp.neighbors',[])): + return + + report_quirk( + text=f"ASAv node '{node.name}' has no loopback, iBGP sessions will not work", + node=node, + quirk='ibgp_no_loopback', + more_hints=[ 'Set loopback: true on ASAv 9.18(2) or later, or use eBGP' ], + category=Warning) + class ASA(_Quirks): @classmethod @@ -36,3 +49,6 @@ def device_quirks(self, node: Box, topology: Box) -> None: text=f"netlab cannot configure OSPFv3 on ASAv node '{node.name}'", node=node, category=log.IncorrectType) + + if 'bgp' in mods: + check_ibgp_loopback(node) diff --git a/netsim/devices/asav.yml b/netsim/devices/asav.yml index 8db41902cc..30dad548e4 100644 --- a/netsim/devices/asav.yml +++ b/netsim/devices/asav.yml @@ -2,6 +2,8 @@ description: Cisco ASAv support: level: minimal +loopback_interface_name: Loopback{ifindex} +loopback: false interface_name: GigabitEthernet0/{ifindex} ifindex_offset: 0 mgmt_if: Management0/0