Repository: aristanetworks/avd
Pull request #5237: Feat(eos_designs): Hardware forwarding knob for diagnostic loopbacks
Author: login: emilarista
Labels: name: state: CI Updated
description: CI scenario have been updated in the PR
name: state: Documentation role Updated
name: role: eos_designs
description: issue related to eos_designs role
name: rn: Feat(eos_designs)
Created: 2025-03-31T12:22:00Z | Merged: 2025-04-03T14:33:12Z

## Change Summary

Adds the capability to enable hardware forwarding for vtep diagnostic loopbacks and other loopback interfaces under network services vrfs.

## Related Issue(s)

General SP enhancements.

## Component(s) name

`arista.avd.eos_designs`

## Proposed changes

```yaml
tenants:
  - name: ...
    vrfs:
      - name:
         vtep_diagnostic: 
           ...
           hardware_forwarding: < bool >
         loopbacks:
           - loopback: 123
             ...
             hardware_forwarding: < bool >
```

## How to test

Tested with molecule

## Checklist

### Repository Checklist

<!--- Go over all the following points, and put an `x` in all the boxes that apply. -->
<!--- If you're unsure about any of these, don't hesitate to ask. We're here to help! -->
- [x] My code has been rebased from devel before I start
- [x] I have read the [**CONTRIBUTING**](https://avd.arista.com/stable/docs/contribution/overview.html) document.
- [x] My change requires a change to the documentation and documentation have been updated accordingly.
- [x] I have updated [molecule CI](https://github.com/aristanetworks/avd/tree/devel/ansible_collections/arista/avd/molecule) testing accordingly. (check the box if not applicable)



Diff:
diff --git a/ansible_collections/arista/avd/molecule/eos_designs_unit_tests/intended/configs/DC1-LEAF2A.cfg b/ansible_collections/arista/avd/molecule/eos_designs_unit_tests/intended/configs/DC1-LEAF2A.cfg
index c00b1c93ebb..6b110e627c0 100644
--- a/ansible_collections/arista/avd/molecule/eos_designs_unit_tests/intended/configs/DC1-LEAF2A.cfg
+++ b/ansible_collections/arista/avd/molecule/eos_designs_unit_tests/intended/configs/DC1-LEAF2A.cfg
@@ -438,12 +438,14 @@ interface Loopback101
    no shutdown
    vrf Tenant_A_OSPF
    ip address 10.255.11.10/32
+   hardware forwarding id
 !
 interface Loopback123
    description Test-Loopback
    no shutdown
    vrf Tenant_A_OSPF
    ip address 10.1.53.0/32
+   hardware forwarding id
    ip ospf area 1
 !
 interface Management99
diff --git a/ansible_collections/arista/avd/molecule/eos_designs_unit_tests/intended/configs/DC1-LEAF2B.cfg b/ansible_collections/arista/avd/molecule/eos_designs_unit_tests/intended/configs/DC1-LEAF2B.cfg
index 6fc51bd0dee..a80cf061d44 100644
--- a/ansible_collections/arista/avd/molecule/eos_designs_unit_tests/intended/configs/DC1-LEAF2B.cfg
+++ b/ansible_collections/arista/avd/molecule/eos_designs_unit_tests/intended/configs/DC1-LEAF2B.cfg
@@ -402,6 +402,7 @@ interface Loopback101
    no shutdown
    vrf Tenant_A_OSPF
    ip address 10.255.11.11/32
+   hardware forwarding id
 !
 interface Loopback123
    shutdown
diff --git a/ansible_collections/arista/avd/molecule/eos_designs_unit_tests/intended/structured_configs/DC1-LEAF2A.yml b/ansible_collections/arista/avd/molecule/eos_designs_unit_tests/intended/structured_configs/DC1-LEAF2A.yml
index 1d63510e1e6..d604a9078e0 100644
--- a/ansible_collections/arista/avd/molecule/eos_designs_unit_tests/intended/structured_configs/DC1-LEAF2A.yml
+++ b/ansible_collections/arista/avd/molecule/eos_designs_unit_tests/intended/structured_configs/DC1-LEAF2A.yml
@@ -381,12 +381,14 @@ loopback_interfaces:
   shutdown: false
   vrf: Tenant_A_OSPF
   ip_address: 10.255.11.10/32
+  hardware_forwarding_id: true
 - name: Loopback123
   description: Test-Loopback
   shutdown: false
   vrf: Tenant_A_OSPF
   ip_address: 10.1.53.0/32
   ospf_area: '1'
+  hardware_forwarding_id: true
 management_api_http:
   enable_https: true
   default_services: false
diff --git a/ansible_collections/arista/avd/molecule/eos_designs_unit_tests/intended/structured_configs/DC1-LEAF2B.yml b/ansible_collections/arista/avd/molecule/eos_designs_unit_tests/intended/structured_configs/DC1-LEAF2B.yml
index 735fff46842..45bede29a08 100644
--- a/ansible_collections/arista/avd/molecule/eos_designs_unit_tests/intended/structured_configs/DC1-LEAF2B.yml
+++ b/ansible_collections/arista/avd/molecule/eos_designs_unit_tests/intended/structured_configs/DC1-LEAF2B.yml
@@ -319,6 +319,7 @@ loopback_interfaces:
   shutdown: false
   vrf: Tenant_A_OSPF
   ip_address: 10.255.11.11/32
+  hardware_forwarding_id: true
 - name: Loopback123
   shutdown: true
   vrf: Tenant_A_OSPF
diff --git a/ansible_collections/arista/avd/molecule/eos_designs_unit_tests/inventory/group_vars/DC1_TENANTS_NETWORKS/Tenant_A.yml b/ansible_collections/arista/avd/molecule/eos_designs_unit_tests/inventory/group_vars/DC1_TENANTS_NETWORKS/Tenant_A.yml
index 36dcc61399f..286c056afae 100644
--- a/ansible_collections/arista/avd/molecule/eos_designs_unit_tests/inventory/group_vars/DC1_TENANTS_NETWORKS/Tenant_A.yml
+++ b/ansible_collections/arista/avd/molecule/eos_designs_unit_tests/inventory/group_vars/DC1_TENANTS_NETWORKS/Tenant_A.yml
@@ -316,6 +316,7 @@ tenant_a:
             node: DC1-LEAF2A
             description: Test-Loopback
             enabled: true
+            hardware_forwarding: true
             ospf:
               enabled: true
               area: 1
@@ -330,6 +331,7 @@ tenant_a:
         vtep_diagnostic:
           loopback: 101
           loopback_ip_range: 10.255.11.0/24
+          hardware_forwarding: true
     l2vlans:
       # L2 vlan as string
       - id: '160'
diff --git a/ansible_collections/arista/avd/roles/eos_designs/docs/tables/network-services-vrfs-loopbacks-settings.md b/ansible_collections/arista/avd/roles/eos_designs/docs/tables/network-services-vrfs-loopbacks-settings.md
index a94c8923fe0..eb78b129535 100644
--- a/ansible_collections/arista/avd/roles/eos_designs/docs/tables/network-services-vrfs-loopbacks-settings.md
+++ b/ansible_collections/arista/avd/roles/eos_designs/docs/tables/network-services-vrfs-loopbacks-settings.md
@@ -20,6 +20,7 @@
     | [<samp>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ospf</samp>](## "<network_services_keys.name>.[].vrfs.[].loopbacks.[].ospf") | Dictionary |  |  |  | OSPF interface configuration. |
     | [<samp>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;enabled</samp>](## "<network_services_keys.name>.[].vrfs.[].loopbacks.[].ospf.enabled") | Boolean |  | `False` |  |  |
     | [<samp>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;area</samp>](## "<network_services_keys.name>.[].vrfs.[].loopbacks.[].ospf.area") | String |  | `0.0.0.0` |  | OSPF area ID. |
+    | [<samp>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hardware_forwarding</samp>](## "<network_services_keys.name>.[].vrfs.[].loopbacks.[].hardware_forwarding") | Boolean |  |  |  | Enable hardware forwarding for this loopback. This is required for correct forwarding in VRFs without physical interfaces.<br> |
     | [<samp>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;raw_eos_cli</samp>](## "<network_services_keys.name>.[].vrfs.[].loopbacks.[].raw_eos_cli") | String |  |  |  | EOS CLI rendered directly on the Loopback interface in the final EOS configuration.<br> |
 
 === "YAML"
@@ -59,6 +60,9 @@
                   # OSPF area ID.
                   area: <str; default="0.0.0.0">
 
+                # Enable hardware forwarding for this loopback. This is required for correct forwarding in VRFs without physical interfaces.
+                hardware_forwarding: <bool>
+
                 # EOS CLI rendered directly on the Loopback interface in the final EOS configuration.
                 raw_eos_cli: <str>
     ```
diff --git a/ansible_collections/arista/avd/roles/eos_designs/docs/tables/network-services-vrfs-settings.md b/ansible_collections/arista/avd/roles/eos_designs/docs/tables/network-services-vrfs-settings.md
index a2aa6562ac1..b66442c767a 100644
--- a/ansible_collections/arista/avd/roles/eos_designs/docs/tables/network-services-vrfs-settings.md
+++ b/ansible_collections/arista/avd/roles/eos_designs/docs/tables/network-services-vrfs-settings.md
@@ -37,6 +37,7 @@
     | [<samp>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-&nbsp;pod</samp>](## "<network_services_keys.name>.[].vrfs.[].vtep_diagnostic.loopback_ip_pools.[].pod") | String | Required, Unique |  |  | POD name. |
     | [<samp>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ipv4_pool</samp>](## "<network_services_keys.name>.[].vrfs.[].vtep_diagnostic.loopback_ip_pools.[].ipv4_pool") | String |  |  | Format: ipv4_pool | Comma separated list of prefixes (IPv4 address/Mask) or ranges (IPv4_address-IPv4_address). |
     | [<samp>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ipv6_pool</samp>](## "<network_services_keys.name>.[].vrfs.[].vtep_diagnostic.loopback_ip_pools.[].ipv6_pool") | String |  |  | Format: ipv6_pool | Comma separated list of prefixes (IPv6 address/Mask) or ranges (IPv6_address-IPv6_address). |
+    | [<samp>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hardware_forwarding</samp>](## "<network_services_keys.name>.[].vrfs.[].vtep_diagnostic.hardware_forwarding") | Boolean |  |  |  | Enable hardware forwarding for diagnostic loopbacks. This is required for correct forwarding in VRFs without physical interfaces.<br> |
     | [<samp>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;evpn_l2_multi_domain</samp>](## "<network_services_keys.name>.[].vrfs.[].evpn_l2_multi_domain") | Boolean |  |  |  | Explicitly extend all VLANs/VLAN-Aware Bundles inside the VRF to remote EVPN domains.<br>Overrides `<network_services_key>[].evpn_l2_multi_domain`.<br> |
     | [<samp>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;static_routes</samp>](## "<network_services_keys.name>.[].vrfs.[].static_routes") | List, items: Dictionary |  |  |  | List of static routes for v4 and/or v6.<br>This will create static routes inside the tenant VRF.<br>If nodes are not specified, all l3leafs that carry the VRF will also be applied the static routes.<br>If a node has a static route in the VRF, redistribute static will be automatically enabled in that VRF.<br>This automatic behavior can be overridden non-selectively with the redistribute_static knob for the VRF.<br> |
     | [<samp>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-&nbsp;destination_address_prefix</samp>](## "<network_services_keys.name>.[].vrfs.[].static_routes.[].destination_address_prefix") | String |  |  |  | IPv4_address. |
@@ -218,6 +219,9 @@
                   # Comma separated list of prefixes (IPv6 address/Mask) or ranges (IPv6_address-IPv6_address).
                   ipv6_pool: <str>
 
+              # Enable hardware forwarding for diagnostic loopbacks. This is required for correct forwarding in VRFs without physical interfaces.
+              hardware_forwarding: <bool>
+
             # Explicitly extend all VLANs/VLAN-Aware Bundles inside the VRF to remote EVPN domains.
             # Overrides `<network_services_key>[].evpn_l2_multi_domain`.
             evpn_l2_multi_domain: <bool>
diff --git a/python-avd/pyavd/_eos_designs/schema/__init__.py b/python-avd/pyavd/_eos_designs/schema/__init__.py
index 2df6189638c..a2490b0834a 100644
--- a/python-avd/pyavd/_eos_designs/schema/__init__.py
+++ b/python-avd/pyavd/_eos_designs/schema/__init__.py
@@ -35223,6 +35223,7 @@ class LoopbackIpPools(AvdIndexedList[str, LoopbackIpPoolsItem]):
                             "loopback_ip_range": {"type": str},
                             "loopback_ipv6_range": {"type": str},
                             "loopback_ip_pools": {"type": LoopbackIpPools},
+                            "hardware_forwarding": {"type": bool},
                         }
                         loopback: int | None
                         """Loopback interface number, required when vtep_diagnotics defined."""
@@ -35269,6 +35270,11 @@ class LoopbackIpPools(AvdIndexedList[str, LoopbackIpPoolsItem]):
 
                         Subclass of AvdIndexedList with `LoopbackIpPoolsItem` items. Primary key is `pod` (`str`).
                         """
+                        hardware_forwarding: bool | None
+                        """
+                        Enable hardware forwarding for diagnostic loopbacks. This is required for correct forwarding in VRFs
+                        without physical interfaces.
+                        """
 
                         if TYPE_CHECKING:
 
@@ -35280,6 +35286,7 @@ def __init__(
                                 loopback_ip_range: str | None | UndefinedType = Undefined,
                                 loopback_ipv6_range: str | None | UndefinedType = Undefined,
                                 loopback_ip_pools: LoopbackIpPools | UndefinedType = Undefined,
+                                hardware_forwarding: bool | None | UndefinedType = Undefined,
                             ) -> None:
                                 """
                                 VtepDiagnostic.
@@ -35324,6 +35331,9 @@ def __init__(
 
 
                                        Subclass of AvdIndexedList with `LoopbackIpPoolsItem` items. Primary key is `pod` (`str`).
+                                    hardware_forwarding:
+                                       Enable hardware forwarding for diagnostic loopbacks. This is required for correct forwarding in VRFs
+                                       without physical interfaces.
 
                                 """
 
@@ -37873,6 +37883,7 @@ def __init__(self, *, enabled: bool | UndefinedType = Undefined, area: str | Und
                             "description": {"type": str},
                             "enabled": {"type": bool, "default": True},
                             "ospf": {"type": Ospf},
+                            "hardware_forwarding": {"type": bool},
                             "raw_eos_cli": {"type": str},
                         }
                         node: str
@@ -37887,6 +37898,11 @@ def __init__(self, *, enabled: bool | UndefinedType = Undefined, area: str | Und
 
                         Subclass of AvdModel.
                         """
+                        hardware_forwarding: bool | None
+                        """
+                        Enable hardware forwarding for this loopback. This is required for correct forwarding in VRFs
+                        without physical interfaces.
+                        """
                         raw_eos_cli: str | None
                         """EOS CLI rendered directly on the Loopback interface in the final EOS configuration."""
 
@@ -37901,6 +37917,7 @@ def __init__(
                                 description: str | None | UndefinedType = Undefined,
                                 enabled: bool | UndefinedType = Undefined,
                                 ospf: Ospf | UndefinedType = Undefined,
+                                hardware_forwarding: bool | None | UndefinedType = Undefined,
                                 raw_eos_cli: str | None | UndefinedType = Undefined,
                             ) -> None:
                                 """
@@ -37919,6 +37936,9 @@ def __init__(
                                        OSPF interface configuration.
 
                                        Subclass of AvdModel.
+                                    hardware_forwarding:
+                                       Enable hardware forwarding for this loopback. This is required for correct forwarding in VRFs
+                                       without physical interfaces.
                                     raw_eos_cli: EOS CLI rendered directly on the Loopback interface in the final EOS configuration.
 
                                 """
diff --git a/python-avd/pyavd/_eos_designs/schema/eos_designs.schema.yml b/python-avd/pyavd/_eos_designs/schema/eos_designs.schema.yml
index 7c5ea815feb..1c99dab0596 100644
--- a/python-avd/pyavd/_eos_designs/schema/eos_designs.schema.yml
+++ b/python-avd/pyavd/_eos_designs/schema/eos_designs.schema.yml
@@ -6695,6 +6695,13 @@ $defs:
                           description: Comma separated list of prefixes (IPv6 address/Mask)
                             or ranges (IPv6_address-IPv6_address).
                           format: ipv6_pool
+                  hardware_forwarding:
+                    type: bool
+                    description: 'Enable hardware forwarding for diagnostic loopbacks.
+                      This is required for correct forwarding in VRFs without physical
+                      interfaces.
+
+                      '
               ospf:
                 documentation_options:
                   table: network-services-vrfs-ospf-settings
@@ -7339,6 +7346,13 @@ $defs:
                           - int
                           description: OSPF area ID.
                           default: 0.0.0.0
+                    hardware_forwarding:
+                      type: bool
+                      description: 'Enable hardware forwarding for this loopback.
+                        This is required for correct forwarding in VRFs without physical
+                        interfaces.
+
+                        '
                     raw_eos_cli:
                       type: str
                       description: 'EOS CLI rendered directly on the Loopback interface
diff --git a/python-avd/pyavd/_eos_designs/schema/schema_fragments/defs_network_services.schema.yml b/python-avd/pyavd/_eos_designs/schema/schema_fragments/defs_network_services.schema.yml
index 53bf9d0be66..08c1d885112 100644
--- a/python-avd/pyavd/_eos_designs/schema/schema_fragments/defs_network_services.schema.yml
+++ b/python-avd/pyavd/_eos_designs/schema/schema_fragments/defs_network_services.schema.yml
@@ -493,6 +493,10 @@ $defs:
                           type: str
                           description: Comma separated list of prefixes (IPv6 address/Mask) or ranges (IPv6_address-IPv6_address).
                           format: ipv6_pool
+                  hardware_forwarding:
+                    type: bool
+                    description: |
+                      Enable hardware forwarding for diagnostic loopbacks. This is required for correct forwarding in VRFs without physical interfaces.
               ospf:
                 documentation_options:
                   table: network-services-vrfs-ospf-settings
@@ -1047,6 +1051,10 @@ $defs:
                             - int
                           description: OSPF area ID.
                           default: "0.0.0.0"
+                    hardware_forwarding:
+                      type: bool
+                      description: |
+                        Enable hardware forwarding for this loopback. This is required for correct forwarding in VRFs without physical interfaces.
                     raw_eos_cli:
                       type: str
                       description: |
diff --git a/python-avd/pyavd/_eos_designs/structured_config/network_services/loopback_interfaces.py b/python-avd/pyavd/_eos_designs/structured_config/network_services/loopback_interfaces.py
index 15072cdad12..46e4f3bb8fe 100644
--- a/python-avd/pyavd/_eos_designs/structured_config/network_services/loopback_interfaces.py
+++ b/python-avd/pyavd/_eos_designs/structured_config/network_services/loopback_interfaces.py
@@ -53,6 +53,8 @@ def loopback_interfaces(self: AvdStructuredConfigNetworkServicesProtocol) -> Non
                         loopback_interface_item.vrf = vrf.name
                     if loopback.ospf.enabled and vrf.ospf.enabled:
                         loopback_interface_item.ospf_area = loopback.ospf.area
+                    if loopback.hardware_forwarding:
+                        loopback_interface_item.hardware_forwarding_id = True
                     self._set_virtual_source_nat_for_vrf_loopback(loopback_interface_item)
                     self.structured_config.loopback_interfaces.append(loopback_interface_item)
 
@@ -84,4 +86,5 @@ def _get_vtep_diagnostic_loopback_for_vrf(
             vrf=vrf.name,
             ip_address=f"{self.shared_utils.ip_addressing.vrf_loopback_ip(loopback_ipv4_pool)}/32" if loopback_ipv4_pool else None,
             ipv6_address=f"{self.shared_utils.ip_addressing.vrf_loopback_ipv6(loopback_ipv6_pool)}/128" if loopback_ipv6_pool else None,
+            hardware_forwarding_id=vrf.vtep_diagnostic.hardware_forwarding or None,
         )


Reviews:
user: login: laxmikantchintakindi
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-01T06:50:27Z
user: login: ClausHolbechArista
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-01T07:49:36Z
user: login: ClausHolbechArista
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-01T07:50:19Z
user: login: Vibhu-gslab
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-04-02T06:30:20Z
user: login: emilarista
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-02T08:06:45Z
user: login: gmuloc
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-02T08:23:19Z
user: login: gmuloc
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-04-02T08:42:46Z

Review comments:
diff_hunk: @@ -84,4 +86,5 @@ def _get_vtep_diagnostic_loopback_for_vrf(
             vrf=vrf.name,
             ip_address=f"{self.shared_utils.ip_addressing.vrf_loopback_ip(loopback_ipv4_pool)}/32" if loopback_ipv4_pool else None,
             ipv6_address=f"{self.shared_utils.ip_addressing.vrf_loopback_ipv6(loopback_ipv6_pool)}/128" if loopback_ipv6_pool else None,
+            hardware_forwarding_id=vrf.vtep_diagnostic.hardware_forwarding if vrf.vtep_diagnostic.hardware_forwarding else None,
path: python-avd/pyavd/_eos_designs/structured_config/network_services/loopback_interfaces.py
user: login: laxmikantchintakindi
body: ```suggestion
            hardware_forwarding_id=vrf.vtep_diagnostic._get("hardware_forwarding"),
```
created_at: 2025-04-01T06:50:27Z
author_association: CONTRIBUTOR
diff_hunk: @@ -84,4 +86,5 @@ def _get_vtep_diagnostic_loopback_for_vrf(
             vrf=vrf.name,
             ip_address=f"{self.shared_utils.ip_addressing.vrf_loopback_ip(loopback_ipv4_pool)}/32" if loopback_ipv4_pool else None,
             ipv6_address=f"{self.shared_utils.ip_addressing.vrf_loopback_ipv6(loopback_ipv6_pool)}/128" if loopback_ipv6_pool else None,
+            hardware_forwarding_id=vrf.vtep_diagnostic.hardware_forwarding if vrf.vtep_diagnostic.hardware_forwarding else None,
path: python-avd/pyavd/_eos_designs/structured_config/network_services/loopback_interfaces.py
user: login: ClausHolbechArista
body: why not just `hardware_forwarding_id=vrf.vtep_diagnostic.hardware_forwarding` ?
created_at: 2025-04-01T07:49:36Z
author_association: CONTRIBUTOR
diff_hunk: @@ -84,4 +86,5 @@ def _get_vtep_diagnostic_loopback_for_vrf(
             vrf=vrf.name,
             ip_address=f"{self.shared_utils.ip_addressing.vrf_loopback_ip(loopback_ipv4_pool)}/32" if loopback_ipv4_pool else None,
             ipv6_address=f"{self.shared_utils.ip_addressing.vrf_loopback_ipv6(loopback_ipv6_pool)}/128" if loopback_ipv6_pool else None,
+            hardware_forwarding_id=vrf.vtep_diagnostic.hardware_forwarding if vrf.vtep_diagnostic.hardware_forwarding else None,
path: python-avd/pyavd/_eos_designs/structured_config/network_services/loopback_interfaces.py
user: login: ClausHolbechArista
body: or if you wish to hide the `false` then do `hardware_forwarding_id=vrf.vtep_diagnostic.hardware_forwarding or None`
created_at: 2025-04-01T07:50:19Z
author_association: CONTRIBUTOR
diff_hunk: @@ -84,4 +86,5 @@ def _get_vtep_diagnostic_loopback_for_vrf(
             vrf=vrf.name,
             ip_address=f"{self.shared_utils.ip_addressing.vrf_loopback_ip(loopback_ipv4_pool)}/32" if loopback_ipv4_pool else None,
             ipv6_address=f"{self.shared_utils.ip_addressing.vrf_loopback_ipv6(loopback_ipv6_pool)}/128" if loopback_ipv6_pool else None,
+            hardware_forwarding_id=vrf.vtep_diagnostic.hardware_forwarding if vrf.vtep_diagnostic.hardware_forwarding else None,
path: python-avd/pyavd/_eos_designs/structured_config/network_services/loopback_interfaces.py
user: login: emilarista
body: Fixed, thanks!
created_at: 2025-04-02T08:06:45Z
author_association: CONTRIBUTOR
diff_hunk: @@ -493,6 +493,11 @@ $defs:
                           type: str
                           description: Comma separated list of prefixes (IPv6 address/Mask) or ranges (IPv6_address-IPv6_address).
                           format: ipv6_pool
+                  hardware_forwarding:
+                    type: bool
+                    description: |
+                      Enable hardware forwarding for diagnostic loopbacks. This is required for correct forwarding in VRFs where there are no
+                      physical interfaces present.
path: python-avd/pyavd/_eos_designs/schema/schema_fragments/defs_network_services.schema.yml
user: login: gmuloc
body: ```suggestion
                      Enable hardware forwarding for diagnostic loopbacks. This is required for correct forwarding in VRFs without physical interfaces.
```
created_at: 2025-04-02T08:22:40Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1047,6 +1052,11 @@ $defs:
                             - int
                           description: OSPF area ID.
                           default: "0.0.0.0"
+                    hardware_forwarding:
+                      type: bool
+                      description: |
+                        Enable hardware forwarding for this loopback. This is required for correct forwarding in VRFs where there are no
+                        physical interfaces present.
path: python-avd/pyavd/_eos_designs/schema/schema_fragments/defs_network_services.schema.yml
user: login: gmuloc
body: ```suggestion
                      description: |
                        Enable hardware forwarding for this loopback. This is required for correct forwarding in VRFs without physical interfaces.
```
created_at: 2025-04-02T08:23:07Z
author_association: CONTRIBUTOR

PR comments:
user: login: github-actions[bot]
created_at: 2025-03-31T12:22:10Z
body: Review docs on [Read the Docs](https://ansible-avd--5237.org.readthedocs.build/en/5237/)

To test this pull request:

```sh
# Create virtual environment for this testing below the current directory
python -m venv test-avd-pr-5237
# Activate the virtual environment
source test-avd-pr-5237/bin/activate
# Install all requirements including PyAVD
pip install "pyavd[ansible] @ git+https://github.com/emilarista/ansible-avd.git@feat/eos_designs/loopback_hardware_forwarding#subdirectory=python-avd" --force
# Point Ansible collections path to the Python virtual environment
export ANSIBLE_COLLECTIONS_PATH=$VIRTUAL_ENV/ansible_collections
# Install Ansible collection
ansible-galaxy collection install git+https://github.com/emilarista/ansible-avd.git#/ansible_collections/arista/avd/,feat/eos_designs/loopback_hardware_forwarding --force
# Optional: Install AVD examples
cd test-avd-pr-5237
ansible-playbook arista.avd.install_examples
```

author_association: NONE
user: login: sonarqubecloud[bot]
created_at: 2025-04-03T14:29:02Z
body: ## [![Quality Gate Passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-passed-20px.png 'Quality Gate Passed')](https://sonarcloud.io/dashboard?id=aristanetworks_avd&pullRequest=5237) **Quality Gate passed**  
Issues  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 New issues](https://sonarcloud.io/project/issues?id=aristanetworks_avd&pullRequest=5237&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/accepted-16px.png '') [0 Accepted issues](https://sonarcloud.io/project/issues?id=aristanetworks_avd&pullRequest=5237&issueStatuses=ACCEPTED)

Measures  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=aristanetworks_avd&pullRequest=5237&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [100.0% Coverage on New Code](https://sonarcloud.io/component_measures?id=aristanetworks_avd&pullRequest=5237&metric=new_coverage&view=list)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Duplication on New Code](https://sonarcloud.io/component_measures?id=aristanetworks_avd&pullRequest=5237&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=aristanetworks_avd&pullRequest=5237)


author_association: NONE