diff --git a/ansible_collections/arista/avd/docs/release-notes/5.x.x.md b/ansible_collections/arista/avd/docs/release-notes/5.x.x.md
index ec10e36215d..7d42a4ba427 100644
--- a/ansible_collections/arista/avd/docs/release-notes/5.x.x.md
+++ b/ansible_collections/arista/avd/docs/release-notes/5.x.x.md
@@ -237,9 +237,9 @@ With AVD version 5.0.0 the default encapsulation used for EVPN iBGP peering betw
See the [porting guide](../porting-guides/5.x.x.md#default-encapsulation-for-wan-evpn-ibgp-peerings-changed-to-path-selection) for details.
-#### PREVIEW WAN HA Direct Link now uses Port-Channel by default
+#### Preview WAN HA Direct Link now uses Port-Channel by default
-TODO: Keep PREVIEW changes at the end as we warn users that PREVIEW mean changes
+TODO: Keep Preview changes at the end as we warn users that Preview mean changes
For WAN direct HA, AVD will now configure a port-channel by default.
This feature was introduced recently in EOS and may not be supported on your version.
diff --git a/ansible_collections/arista/avd/molecule/eos_designs_negative_unit_tests/inventory/host_vars/failure-adapter-ptp-profile-does-not-exist.yml b/ansible_collections/arista/avd/molecule/eos_designs_negative_unit_tests/inventory/host_vars/failure-adapter-ptp-profile-does-not-exist.yml
new file mode 100644
index 00000000000..cc5df98a2b0
--- /dev/null
+++ b/ansible_collections/arista/avd/molecule/eos_designs_negative_unit_tests/inventory/host_vars/failure-adapter-ptp-profile-does-not-exist.yml
@@ -0,0 +1,33 @@
+---
+type: l3leaf
+
+ptp_profiles:
+ - profile: PROFILE-1
+
+l3leaf:
+ defaults:
+ loopback_ipv4_pool: 10.254.1.0/27
+ vtep_loopback_ipv4_pool: 10.254.11.0/27
+ mlag_interfaces: ['Ethernet9', 'Ethernet10']
+ mlag_peer_ipv4_pool: 10.254.1.64/27
+ mlag_peer_l3_ipv4_pool: 10.254.1.96/27
+ ptp:
+ enabled: true
+ nodes:
+ - name: failure-adapter-ptp-profile-does-not-exist
+ id: 1
+ bgp_as: 65101
+ mgmt_ip: 192.168.0.101/24
+
+servers:
+ - name: INDIVIDUAL_1
+ adapters:
+ - switches: [failure-adapter-ptp-profile-does-not-exist]
+ switch_ports: [Ethernet14]
+ ptp:
+ enabled: true
+ profile: THIS-PROFILE-DOES-NOT-EXIST
+
+expected_error_message: >-
+ PTP Profile 'THIS-PROFILE-DOES-NOT-EXIST' referenced under server[INDIVIDUAL_1].adapters[0]
+ does not exist in `ptp_profiles`.
diff --git a/ansible_collections/arista/avd/molecule/eos_designs_negative_unit_tests/inventory/host_vars/failure-network-port-ptp-profile-does-not-exist.yml b/ansible_collections/arista/avd/molecule/eos_designs_negative_unit_tests/inventory/host_vars/failure-network-port-ptp-profile-does-not-exist.yml
new file mode 100644
index 00000000000..a6173919272
--- /dev/null
+++ b/ansible_collections/arista/avd/molecule/eos_designs_negative_unit_tests/inventory/host_vars/failure-network-port-ptp-profile-does-not-exist.yml
@@ -0,0 +1,29 @@
+---
+type: l3leaf
+
+# Using default value of ptp_profiles
+
+l3leaf:
+ defaults:
+ loopback_ipv4_pool: 10.254.1.0/27
+ vtep_loopback_ipv4_pool: 10.254.11.0/27
+ mlag_interfaces: ['Ethernet9', 'Ethernet10']
+ mlag_peer_ipv4_pool: 10.254.1.64/27
+ mlag_peer_l3_ipv4_pool: 10.254.1.96/27
+ ptp:
+ enabled: true
+ nodes:
+ - name: failure-network-port-ptp-profile-does-not-exist
+ id: 1
+ bgp_as: 65101
+ mgmt_ip: 192.168.0.101/24
+
+network_ports:
+ - switches: [failure-network-port-ptp-profile-does-not-exist]
+ switch_ports: [Ethernet14, Ethernet15]
+ ptp:
+ enabled: true
+ profile: THIS-PROFILE-DOES-NOT-EXIST
+
+expected_error_message: >-
+ PTP Profile 'THIS-PROFILE-DOES-NOT-EXIST' referenced under network_ports[0] does not exist in `ptp_profiles`.
diff --git a/ansible_collections/arista/avd/molecule/eos_designs_negative_unit_tests/inventory/host_vars/failure-ptp-profile-does-not-exist.yml b/ansible_collections/arista/avd/molecule/eos_designs_negative_unit_tests/inventory/host_vars/failure-ptp-profile-does-not-exist.yml
new file mode 100644
index 00000000000..115e4c47a39
--- /dev/null
+++ b/ansible_collections/arista/avd/molecule/eos_designs_negative_unit_tests/inventory/host_vars/failure-ptp-profile-does-not-exist.yml
@@ -0,0 +1,31 @@
+---
+type: l3leaf
+
+ptp_profiles:
+ - profile: PROFILE-1
+
+l3leaf:
+ defaults:
+ loopback_ipv4_pool: 10.254.1.0/27
+ vtep_loopback_ipv4_pool: 10.254.11.0/27
+ nodes:
+ - name: failure-ptp-profile-does-not-exist
+ id: 1
+ bgp_as: 65101
+ mgmt_ip: 192.168.0.101/24
+ ptp:
+ enabled: true
+ # The profile is applied on uplink or l3edge
+ profile: THIS-PROFILE-DOES-NOT-EXIST
+
+l3_edge:
+ p2p_links:
+ - nodes: [failure-ptp-profile-does-not-exist, not-in-fabric]
+ interfaces: [Ethernet10, Ethernet11]
+ ip: [192.168.0.2/31, 192.168.0.3/31]
+ ptp:
+ enabled: true
+
+expected_error_message: >-
+ PTP Profile 'THIS-PROFILE-DOES-NOT-EXIST' referenced under `ptp.profile` node variables
+ does not exist in `ptp_profiles`.
diff --git a/ansible_collections/arista/avd/molecule/eos_designs_negative_unit_tests/inventory/hosts.yml b/ansible_collections/arista/avd/molecule/eos_designs_negative_unit_tests/inventory/hosts.yml
index 7d5bc888a78..33ff7214929 100644
--- a/ansible_collections/arista/avd/molecule/eos_designs_negative_unit_tests/inventory/hosts.yml
+++ b/ansible_collections/arista/avd/molecule/eos_designs_negative_unit_tests/inventory/hosts.yml
@@ -89,18 +89,20 @@ all:
duplicate-interfaces-underlay:
duplicate-ip-address-uplink-switch-router-bgp:
duplicate-tunnel-interface-internet-exit:
+ failure-adapter-ptp-profile-does-not-exist:
+ failure-connected-endpoint-port-profile-does-not-exist:
+ failure-connected-endpoint-parent-port-profile-does-not-exist:
+ failure-duplicate-evpn-vlan-bundle-name:
failure-missing-evpn-vlan-bundle:
failure-missing-evpn-vlan-bundle_svi:
failure-missing-evpn-multicast-l3-with-pim:
failure-missing-evpn-multicast-peg-rps:
failure-missing-evpn-multicast-with-pim:
- failure-duplicate-evpn-vlan-bundle-name:
+ failure-network-port-ptp-profile-does-not-exist:
failure-no-local-path-group-in-default-policy:
- failure-l3-interface-profile-does-not-exist:
+ failure-ptp-profile-does-not-exist:
failure-svi-parent-profile-does-not-exist:
failure-svi-grandparent-profile-does-not-exist:
- failure-connected-endpoint-port-profile-does-not-exist:
- failure-connected-endpoint-parent-port-profile-does-not-exist:
ipv4-acl-in-missing-on-wan-interface:
ipv4-acls:
isis-system-id-format-missing-node-id:
diff --git a/ansible_collections/arista/avd/molecule/eos_designs_unit_tests/intended/configs/custom-ptp-profile.cfg b/ansible_collections/arista/avd/molecule/eos_designs_unit_tests/intended/configs/custom-ptp-profile.cfg
new file mode 100644
index 00000000000..43ffb1a9596
--- /dev/null
+++ b/ansible_collections/arista/avd/molecule/eos_designs_unit_tests/intended/configs/custom-ptp-profile.cfg
@@ -0,0 +1,124 @@
+!
+no enable password
+no aaa root
+!
+vlan internal order ascending range 1006 1199
+!
+transceiver qsfp default-mode 4x10G
+!
+service routing protocols model multi-agent
+!
+hostname custom-ptp-profile
+!
+ptp clock-identity 00:1C:73:1e:00:0c
+ptp domain 127
+ptp mode boundary
+ptp priority1 30
+ptp priority2 12
+ptp monitor threshold offset-from-master 250
+ptp monitor threshold mean-path-delay 1500
+ptp monitor sequence-id
+ptp monitor threshold missing-message sync 3 sequence-ids
+ptp monitor threshold missing-message follow-up 3 sequence-ids
+ptp monitor threshold missing-message delay-resp 3 sequence-ids
+ptp monitor threshold missing-message announce 3 sequence-ids
+!
+vlan 11
+ name VLAN11
+!
+vrf instance MGMT
+!
+vrf instance VRF1
+!
+management api http-commands
+ protocol https
+ no shutdown
+ !
+ vrf MGMT
+ no shutdown
+!
+interface Ethernet8
+ description P2P_not-in-this-fabric_Ethernet8
+ no shutdown
+ mtu 9214
+ no switchport
+ ptp enable
+ ptp sync-message interval -7
+ ptp announce interval 4
+ ptp transport ipv4
+ ptp announce timeout 3
+ ptp delay-req interval -6
+!
+interface Loopback0
+ description ROUTER_ID
+ no shutdown
+ ip address 10.42.42.42/32/32
+!
+interface Loopback1
+ description VXLAN_TUNNEL_SOURCE
+ no shutdown
+ ip address 10.42.42.42/32/32
+!
+interface Vlan11
+ description VLAN11
+ no shutdown
+ vrf VRF1
+ ip address 172.16.11.1/24
+!
+interface Vxlan1
+ description custom-ptp-profile_VTEP
+ vxlan source-interface Loopback1
+ vxlan udp-port 4789
+ vxlan vlan 11 vni 10011
+ vxlan vrf VRF1 vni 1
+!
+ip routing
+no ip routing vrf MGMT
+ip routing vrf VRF1
+!
+ip prefix-list PL-LOOPBACKS-EVPN-OVERLAY
+ seq 10 permit 10.10.10.0/24 eq 32
+ seq 20 permit 10.10.10.0/24 eq 32
+!
+route-map RM-CONN-2-BGP permit 10
+ match ip address prefix-list PL-LOOPBACKS-EVPN-OVERLAY
+!
+router bfd
+ multihop interval 300 min-rx 300 multiplier 3
+!
+router bgp 65042
+ router-id 10.42.42.42/32
+ maximum-paths 4 ecmp 4
+ update wait-install
+ no bgp default ipv4-unicast
+ neighbor EVPN-OVERLAY-PEERS peer group
+ neighbor EVPN-OVERLAY-PEERS update-source Loopback0
+ neighbor EVPN-OVERLAY-PEERS bfd
+ neighbor EVPN-OVERLAY-PEERS ebgp-multihop 3
+ neighbor EVPN-OVERLAY-PEERS send-community
+ neighbor EVPN-OVERLAY-PEERS maximum-routes 0
+ neighbor IPv4-UNDERLAY-PEERS peer group
+ neighbor IPv4-UNDERLAY-PEERS send-community
+ neighbor IPv4-UNDERLAY-PEERS maximum-routes 12000
+ redistribute connected route-map RM-CONN-2-BGP
+ !
+ vlan 11
+ rd 10.42.42.42/32:10011
+ route-target both 10011:10011
+ redistribute learned
+ !
+ address-family evpn
+ neighbor EVPN-OVERLAY-PEERS activate
+ !
+ address-family ipv4
+ no neighbor EVPN-OVERLAY-PEERS activate
+ neighbor IPv4-UNDERLAY-PEERS activate
+ !
+ vrf VRF1
+ rd 10.42.42.42/32:1
+ route-target import evpn 1:1
+ route-target export evpn 1:1
+ router-id 10.42.42.42/32
+ redistribute connected
+!
+end
diff --git a/ansible_collections/arista/avd/molecule/eos_designs_unit_tests/intended/structured_configs/custom-ptp-profile.yml b/ansible_collections/arista/avd/molecule/eos_designs_unit_tests/intended/structured_configs/custom-ptp-profile.yml
new file mode 100644
index 00000000000..a9166b70fea
--- /dev/null
+++ b/ansible_collections/arista/avd/molecule/eos_designs_unit_tests/intended/structured_configs/custom-ptp-profile.yml
@@ -0,0 +1,175 @@
+hostname: custom-ptp-profile
+is_deployed: true
+router_bgp:
+ as: '65042'
+ router_id: 10.42.42.42/32
+ bgp:
+ default:
+ ipv4_unicast: false
+ maximum_paths:
+ paths: 4
+ ecmp: 4
+ updates:
+ wait_install: true
+ peer_groups:
+ - name: IPv4-UNDERLAY-PEERS
+ type: ipv4
+ maximum_routes: 12000
+ send_community: all
+ - name: EVPN-OVERLAY-PEERS
+ type: evpn
+ update_source: Loopback0
+ bfd: true
+ send_community: all
+ maximum_routes: 0
+ ebgp_multihop: 3
+ address_family_ipv4:
+ peer_groups:
+ - name: IPv4-UNDERLAY-PEERS
+ activate: true
+ - name: EVPN-OVERLAY-PEERS
+ activate: false
+ redistribute_routes:
+ - source_protocol: connected
+ route_map: RM-CONN-2-BGP
+ address_family_evpn:
+ peer_groups:
+ - name: EVPN-OVERLAY-PEERS
+ activate: true
+ vrfs:
+ - name: VRF1
+ rd: 10.42.42.42/32:1
+ route_targets:
+ import:
+ - address_family: evpn
+ route_targets:
+ - '1:1'
+ export:
+ - address_family: evpn
+ route_targets:
+ - '1:1'
+ router_id: 10.42.42.42/32
+ redistribute_routes:
+ - source_protocol: connected
+ vlans:
+ - id: 11
+ tenant: PTP
+ rd: 10.42.42.42/32:10011
+ route_targets:
+ both:
+ - 10011:10011
+ redistribute_routes:
+ - learned
+service_routing_protocols_model: multi-agent
+ip_routing: true
+vlan_internal_order:
+ allocation: ascending
+ range:
+ beginning: 1006
+ ending: 1199
+aaa_root:
+ disabled: true
+config_end: true
+enable_password:
+ disabled: true
+transceiver_qsfp_default_mode_4x10: true
+vrfs:
+- name: MGMT
+ ip_routing: false
+- name: VRF1
+ tenant: PTP
+ ip_routing: true
+management_api_http:
+ enable_vrfs:
+ - name: MGMT
+ enable_https: true
+ptp:
+ mode: boundary
+ clock_identity: 00:1C:73:1e:00:0c
+ priority1: 30
+ priority2: 12
+ domain: 127
+ monitor:
+ enabled: true
+ threshold:
+ offset_from_master: 250
+ mean_path_delay: 1500
+ missing_message:
+ sequence_ids:
+ enabled: true
+ announce: 3
+ delay_resp: 3
+ follow_up: 3
+ sync: 3
+loopback_interfaces:
+- name: Loopback0
+ description: ROUTER_ID
+ shutdown: false
+ ip_address: 10.42.42.42/32/32
+- name: Loopback1
+ description: VXLAN_TUNNEL_SOURCE
+ shutdown: false
+ ip_address: 10.42.42.42/32/32
+prefix_lists:
+- name: PL-LOOPBACKS-EVPN-OVERLAY
+ sequence_numbers:
+ - sequence: 10
+ action: permit 10.10.10.0/24 eq 32
+ - sequence: 20
+ action: permit 10.10.10.0/24 eq 32
+route_maps:
+- name: RM-CONN-2-BGP
+ sequence_numbers:
+ - sequence: 10
+ type: permit
+ match:
+ - ip address prefix-list PL-LOOPBACKS-EVPN-OVERLAY
+router_bfd:
+ multihop:
+ interval: 300
+ min_rx: 300
+ multiplier: 3
+ethernet_interfaces:
+- name: Ethernet8
+ peer: not-in-this-fabric
+ peer_interface: Ethernet8
+ peer_type: other
+ switchport:
+ enabled: false
+ shutdown: false
+ mtu: 9214
+ description: P2P_not-in-this-fabric_Ethernet8
+ ptp:
+ announce:
+ interval: 4
+ timeout: 3
+ delay_req: -6
+ sync_message:
+ interval: -7
+ transport: ipv4
+ enable: true
+vlans:
+- id: 11
+ name: VLAN11
+ tenant: PTP
+ip_igmp_snooping:
+ globally_enabled: true
+vlan_interfaces:
+- name: Vlan11
+ tenant: PTP
+ description: VLAN11
+ shutdown: false
+ ip_address: 172.16.11.1/24
+ vrf: VRF1
+vxlan_interface:
+ vxlan1:
+ description: custom-ptp-profile_VTEP
+ vxlan:
+ udp_port: 4789
+ source_interface: Loopback1
+ vlans:
+ - id: 11
+ vni: 10011
+ vrfs:
+ - name: VRF1
+ vni: 1
diff --git a/ansible_collections/arista/avd/molecule/eos_designs_unit_tests/inventory/host_vars/custom-ptp-profile.yml b/ansible_collections/arista/avd/molecule/eos_designs_unit_tests/inventory/host_vars/custom-ptp-profile.yml
new file mode 100644
index 00000000000..fbd45d54bd4
--- /dev/null
+++ b/ansible_collections/arista/avd/molecule/eos_designs_unit_tests/inventory/host_vars/custom-ptp-profile.yml
@@ -0,0 +1,51 @@
+---
+type: l3leaf
+
+# Overriding the default profiles
+ptp_profiles:
+ - profile: my-custom-ptp-profile
+ announce:
+ interval: 4
+ timeout: 3
+ delay_req: -6
+ sync_message:
+ interval: -7
+ transport: ipv4
+
+l3_edge:
+ p2p_links:
+ - nodes: [ custom-ptp-profile, not-in-this-fabric ]
+ interfaces: [ Ethernet8, Ethernet8 ]
+ ptp:
+ enabled: true
+ include_in_underlay_protocol: false
+
+ptp_settings:
+ enabled: true
+
+tenants:
+ - name: PTP
+ mac_vrf_vni_base: 10000
+ vrfs:
+ - name: VRF1
+ vrf_vni: 1
+ svis:
+ - id: 11
+ name: VLAN11
+ enabled: true
+ nodes:
+ - node: custom-ptp-profile
+ ip_address: 172.16.11.1/24
+
+l3leaf:
+ defaults:
+ loopback_ipv4_pool: 10.10.10.0/24
+ vtep_loopback_ipv4_pool: 10.10.10.0/24
+ bgp_as: 65042
+ nodes:
+ - name: custom-ptp-profile
+ loopback_ipv4_address: 10.42.42.42/32
+ vtep_loopback_ipv4_address: 10.42.42.42/32
+ id: 12
+ ptp:
+ profile: my-custom-ptp-profile
diff --git a/ansible_collections/arista/avd/molecule/eos_designs_unit_tests/inventory/hosts.yml b/ansible_collections/arista/avd/molecule/eos_designs_unit_tests/inventory/hosts.yml
index f06a89ef7f6..ea2d2f47b92 100644
--- a/ansible_collections/arista/avd/molecule/eos_designs_unit_tests/inventory/hosts.yml
+++ b/ansible_collections/arista/avd/molecule/eos_designs_unit_tests/inventory/hosts.yml
@@ -10,6 +10,7 @@ all:
connected_endpoints:
cvp-instance-ips-cvaas:
cvp-instance-ips-onprem-token:
+ custom-ptp-profile:
device.with.dots.in.hostname:
evpn-vtep-with-default-vrf-not-evpn:
duplicate-vrfs:
diff --git a/ansible_collections/arista/avd/roles/eos_designs/docs/tables/connected-endpoints.md b/ansible_collections/arista/avd/roles/eos_designs/docs/tables/connected-endpoints.md
index 5c8e02f188a..1b7d59c292b 100644
--- a/ansible_collections/arista/avd/roles/eos_designs/docs/tables/connected-endpoints.md
+++ b/ansible_collections/arista/avd/roles/eos_designs/docs/tables/connected-endpoints.md
@@ -42,7 +42,7 @@
| [ ptp](## ".[].adapters.[].ptp") | Dictionary | | | | The global PTP profile parameters will be applied to all connected endpoints where `ptp` is manually enabled.
`ptp role master` is set to ensure control over the PTP topology.
|
| [ enabled](## ".[].adapters.[].ptp.enabled") | Boolean | | `False` | | |
| [ endpoint_role](## ".[].adapters.[].ptp.endpoint_role") | String | | `follower` | Valid Values:
- bmca
- default
- follower
| |
- | [ profile](## ".[].adapters.[].ptp.profile") | String | | `aes67-r16-2016` | Valid Values:
- aes67
- aes67-r16-2016
- smpte2059-2
| |
+ | [ profile](## ".[].adapters.[].ptp.profile") | String | | `aes67-r16-2016` | | Default available profiles are:
- "aes67"
- "aes67-r16-2016"
- "smpte2059-2" |
| [ sflow](## ".[].adapters.[].sflow") | Boolean | | | | Configures sFlow on the interface. Overrides `fabric_sflow.endpoints` setting. |
| [ flow_tracking](## ".[].adapters.[].flow_tracking") | Dictionary | | | | Configures flow-tracking on the interface. Overrides `fabric_flow_tracking.endpoints` setting. |
| [ enabled](## ".[].adapters.[].flow_tracking.enabled") | Boolean | | | | |
@@ -274,7 +274,12 @@
ptp:
enabled:
endpoint_role:
- profile:
+
+ # Default available profiles are:
+ # - "aes67"
+ # - "aes67-r16-2016"
+ # - "smpte2059-2"
+ profile:
# Configures sFlow on the interface. Overrides `fabric_sflow.endpoints` setting.
sflow:
diff --git a/ansible_collections/arista/avd/roles/eos_designs/docs/tables/network-ports.md b/ansible_collections/arista/avd/roles/eos_designs/docs/tables/network-ports.md
index f4a3090cbd2..cb0a09ce1a5 100644
--- a/ansible_collections/arista/avd/roles/eos_designs/docs/tables/network-ports.md
+++ b/ansible_collections/arista/avd/roles/eos_designs/docs/tables/network-ports.md
@@ -37,7 +37,7 @@
| [ ptp](## "network_ports.[].ptp") | Dictionary | | | | The global PTP profile parameters will be applied to all connected endpoints where `ptp` is manually enabled.
`ptp role master` is set to ensure control over the PTP topology.
|
| [ enabled](## "network_ports.[].ptp.enabled") | Boolean | | `False` | | |
| [ endpoint_role](## "network_ports.[].ptp.endpoint_role") | String | | `follower` | Valid Values:
- bmca
- default
- follower
| |
- | [ profile](## "network_ports.[].ptp.profile") | String | | `aes67-r16-2016` | Valid Values:
- aes67
- aes67-r16-2016
- smpte2059-2
| |
+ | [ profile](## "network_ports.[].ptp.profile") | String | | `aes67-r16-2016` | | Default available profiles are:
- "aes67"
- "aes67-r16-2016"
- "smpte2059-2" |
| [ sflow](## "network_ports.[].sflow") | Boolean | | | | Configures sFlow on the interface. Overrides `fabric_sflow.endpoints` setting. |
| [ flow_tracking](## "network_ports.[].flow_tracking") | Dictionary | | | | Configures flow-tracking on the interface. Overrides `fabric_flow_tracking.endpoints` setting. |
| [ enabled](## "network_ports.[].flow_tracking.enabled") | Boolean | | | | |
@@ -248,7 +248,12 @@
ptp:
enabled:
endpoint_role:
- profile:
+
+ # Default available profiles are:
+ # - "aes67"
+ # - "aes67-r16-2016"
+ # - "smpte2059-2"
+ profile:
# Configures sFlow on the interface. Overrides `fabric_sflow.endpoints` setting.
sflow:
diff --git a/ansible_collections/arista/avd/roles/eos_designs/docs/tables/node-type-ptp-configuration.md b/ansible_collections/arista/avd/roles/eos_designs/docs/tables/node-type-ptp-configuration.md
index 8f532d1fbb3..a49156bf73b 100644
--- a/ansible_collections/arista/avd/roles/eos_designs/docs/tables/node-type-ptp-configuration.md
+++ b/ansible_collections/arista/avd/roles/eos_designs/docs/tables/node-type-ptp-configuration.md
@@ -11,7 +11,7 @@
| [ defaults](## ".defaults") | Dictionary | | | | Define variables for all nodes of this type. |
| [ ptp](## ".defaults.ptp") | Dictionary | | | | |
| [ enabled](## ".defaults.ptp.enabled") | Boolean | | `False` | | |
- | [ profile](## ".defaults.ptp.profile") | String | | `aes67-r16-2016` | Valid Values:
- aes67
- smpte2059-2
- aes67-r16-2016
| |
+ | [ profile](## ".defaults.ptp.profile") | String | | `aes67-r16-2016` | | Default available profiles are:
- "aes67"
- "aes67-r16-2016"
- "smpte2059-2" |
| [ mlag](## ".defaults.ptp.mlag") | Boolean | | `False` | | Configure PTP on the MLAG peer-link port-channel when PTP is enabled. By default PTP will not be configured on the MLAG peer-link port-channel. |
| [ domain](## ".defaults.ptp.domain") | Integer | | `127` | Min: 0
Max: 255 | |
| [ priority1](## ".defaults.ptp.priority1") | Integer | | | Min: 0
Max: 255 | default -> automatically set based on node_type.
|
@@ -52,7 +52,7 @@
| [ - name](## ".node_groups.[].nodes.[].name") | String | Required, Unique | | | The Node Name is used as "hostname". |
| [ ptp](## ".node_groups.[].nodes.[].ptp") | Dictionary | | | | |
| [ enabled](## ".node_groups.[].nodes.[].ptp.enabled") | Boolean | | `False` | | |
- | [ profile](## ".node_groups.[].nodes.[].ptp.profile") | String | | `aes67-r16-2016` | Valid Values:
- aes67
- smpte2059-2
- aes67-r16-2016
| |
+ | [ profile](## ".node_groups.[].nodes.[].ptp.profile") | String | | `aes67-r16-2016` | | Default available profiles are:
- "aes67"
- "aes67-r16-2016"
- "smpte2059-2" |
| [ mlag](## ".node_groups.[].nodes.[].ptp.mlag") | Boolean | | `False` | | Configure PTP on the MLAG peer-link port-channel when PTP is enabled. By default PTP will not be configured on the MLAG peer-link port-channel. |
| [ domain](## ".node_groups.[].nodes.[].ptp.domain") | Integer | | `127` | Min: 0
Max: 255 | |
| [ priority1](## ".node_groups.[].nodes.[].ptp.priority1") | Integer | | | Min: 0
Max: 255 | default -> automatically set based on node_type.
|
@@ -89,7 +89,7 @@
| [ sync](## ".node_groups.[].nodes.[].ptp.monitor.missing_message.sequence_ids.sync") | Integer | | `3` | Min: 2
Max: 255 | |
| [ ptp](## ".node_groups.[].ptp") | Dictionary | | | | |
| [ enabled](## ".node_groups.[].ptp.enabled") | Boolean | | `False` | | |
- | [ profile](## ".node_groups.[].ptp.profile") | String | | `aes67-r16-2016` | Valid Values:
- aes67
- smpte2059-2
- aes67-r16-2016
| |
+ | [ profile](## ".node_groups.[].ptp.profile") | String | | `aes67-r16-2016` | | Default available profiles are:
- "aes67"
- "aes67-r16-2016"
- "smpte2059-2" |
| [ mlag](## ".node_groups.[].ptp.mlag") | Boolean | | `False` | | Configure PTP on the MLAG peer-link port-channel when PTP is enabled. By default PTP will not be configured on the MLAG peer-link port-channel. |
| [ domain](## ".node_groups.[].ptp.domain") | Integer | | `127` | Min: 0
Max: 255 | |
| [ priority1](## ".node_groups.[].ptp.priority1") | Integer | | | Min: 0
Max: 255 | default -> automatically set based on node_type.
|
@@ -128,7 +128,7 @@
| [ - name](## ".nodes.[].name") | String | Required, Unique | | | The Node Name is used as "hostname". |
| [ ptp](## ".nodes.[].ptp") | Dictionary | | | | |
| [ enabled](## ".nodes.[].ptp.enabled") | Boolean | | `False` | | |
- | [ profile](## ".nodes.[].ptp.profile") | String | | `aes67-r16-2016` | Valid Values:
- aes67
- smpte2059-2
- aes67-r16-2016
| |
+ | [ profile](## ".nodes.[].ptp.profile") | String | | `aes67-r16-2016` | | Default available profiles are:
- "aes67"
- "aes67-r16-2016"
- "smpte2059-2" |
| [ mlag](## ".nodes.[].ptp.mlag") | Boolean | | `False` | | Configure PTP on the MLAG peer-link port-channel when PTP is enabled. By default PTP will not be configured on the MLAG peer-link port-channel. |
| [ domain](## ".nodes.[].ptp.domain") | Integer | | `127` | Min: 0
Max: 255 | |
| [ priority1](## ".nodes.[].ptp.priority1") | Integer | | | Min: 0
Max: 255 | default -> automatically set based on node_type.
|
@@ -173,7 +173,12 @@
defaults:
ptp:
enabled:
- profile:
+
+ # Default available profiles are:
+ # - "aes67"
+ # - "aes67-r16-2016"
+ # - "smpte2059-2"
+ profile:
# Configure PTP on the MLAG peer-link port-channel when PTP is enabled. By default PTP will not be configured on the MLAG peer-link port-channel.
mlag:
@@ -243,7 +248,12 @@
- name:
ptp:
enabled:
- profile:
+
+ # Default available profiles are:
+ # - "aes67"
+ # - "aes67-r16-2016"
+ # - "smpte2059-2"
+ profile:
# Configure PTP on the MLAG peer-link port-channel when PTP is enabled. By default PTP will not be configured on the MLAG peer-link port-channel.
mlag:
@@ -300,7 +310,12 @@
sync:
ptp:
enabled:
- profile:
+
+ # Default available profiles are:
+ # - "aes67"
+ # - "aes67-r16-2016"
+ # - "smpte2059-2"
+ profile:
# Configure PTP on the MLAG peer-link port-channel when PTP is enabled. By default PTP will not be configured on the MLAG peer-link port-channel.
mlag:
@@ -363,7 +378,12 @@
- name:
ptp:
enabled:
- profile:
+
+ # Default available profiles are:
+ # - "aes67"
+ # - "aes67-r16-2016"
+ # - "smpte2059-2"
+ profile:
# Configure PTP on the MLAG peer-link port-channel when PTP is enabled. By default PTP will not be configured on the MLAG peer-link port-channel.
mlag:
diff --git a/ansible_collections/arista/avd/roles/eos_designs/docs/tables/port-profiles.md b/ansible_collections/arista/avd/roles/eos_designs/docs/tables/port-profiles.md
index 7322c74c9a5..a1d4496d19b 100644
--- a/ansible_collections/arista/avd/roles/eos_designs/docs/tables/port-profiles.md
+++ b/ansible_collections/arista/avd/roles/eos_designs/docs/tables/port-profiles.md
@@ -33,7 +33,7 @@
| [ ptp](## "port_profiles.[].ptp") | Dictionary | | | | The global PTP profile parameters will be applied to all connected endpoints where `ptp` is manually enabled.
`ptp role master` is set to ensure control over the PTP topology.
|
| [ enabled](## "port_profiles.[].ptp.enabled") | Boolean | | `False` | | |
| [ endpoint_role](## "port_profiles.[].ptp.endpoint_role") | String | | `follower` | Valid Values:
- bmca
- default
- follower
| |
- | [ profile](## "port_profiles.[].ptp.profile") | String | | `aes67-r16-2016` | Valid Values:
- aes67
- aes67-r16-2016
- smpte2059-2
| |
+ | [ profile](## "port_profiles.[].ptp.profile") | String | | `aes67-r16-2016` | | Default available profiles are:
- "aes67"
- "aes67-r16-2016"
- "smpte2059-2" |
| [ sflow](## "port_profiles.[].sflow") | Boolean | | | | Configures sFlow on the interface. Overrides `fabric_sflow.endpoints` setting. |
| [ flow_tracking](## "port_profiles.[].flow_tracking") | Dictionary | | | | Configures flow-tracking on the interface. Overrides `fabric_flow_tracking.endpoints` setting. |
| [ enabled](## "port_profiles.[].flow_tracking.enabled") | Boolean | | | | |
@@ -230,7 +230,12 @@
ptp:
enabled:
endpoint_role:
- profile:
+
+ # Default available profiles are:
+ # - "aes67"
+ # - "aes67-r16-2016"
+ # - "smpte2059-2"
+ profile:
# Configures sFlow on the interface. Overrides `fabric_sflow.endpoints` setting.
sflow:
diff --git a/ansible_collections/arista/avd/roles/eos_designs/docs/tables/ptp_settings.md b/ansible_collections/arista/avd/roles/eos_designs/docs/tables/ptp_settings.md
index e4b2e42c958..c7b416afa5d 100644
--- a/ansible_collections/arista/avd/roles/eos_designs/docs/tables/ptp_settings.md
+++ b/ansible_collections/arista/avd/roles/eos_designs/docs/tables/ptp_settings.md
@@ -9,7 +9,7 @@
| -------- | ---- | -------- | ------- | ------------------ | ----------- |
| [ptp](## "ptp") removed | Dictionary | | | | This key was removed. Support was removed in AVD version v5.0.0. Use ptp_settings instead. |
| [ptp_profiles](## "ptp_profiles") | List, items: Dictionary | | See (+) on YAML tab | | |
- | [ - profile](## "ptp_profiles.[].profile") | String | | | | PTP profile. |
+ | [ - profile](## "ptp_profiles.[].profile") | String | Required, Unique | | | PTP profile. |
| [ announce](## "ptp_profiles.[].announce") | Dictionary | | | | PTP announce interval. |
| [ interval](## "ptp_profiles.[].announce.interval") | Integer | | | Min: -7
Max: 4 | |
| [ timeout](## "ptp_profiles.[].announce.timeout") | Integer | | | Min: 2
Max: 255 | |
@@ -19,7 +19,7 @@
| [ transport](## "ptp_profiles.[].transport") | String | | | Valid Values:
- ipv4
| |
| [ptp_settings](## "ptp_settings") | Dictionary | | | | Common PTP settings. |
| [ enabled](## "ptp_settings.enabled") | Boolean | | | | |
- | [ profile](## "ptp_settings.profile") | String | | `aes67-r16-2016` | Valid Values:
- aes67
- smpte2059-2
- aes67-r16-2016
| |
+ | [ profile](## "ptp_settings.profile") | String | | `aes67-r16-2016` | | Default available profiles are:
- "aes67"
- "aes67-r16-2016"
- "smpte2059-2" |
| [ domain](## "ptp_settings.domain") | Integer | | | Min: 0
Max: 255 | |
| [ auto_clock_identity](## "ptp_settings.auto_clock_identity") | Boolean | | `True` | | |
@@ -29,7 +29,7 @@
ptp_profiles: # (1)!
# PTP profile.
- - profile:
+ - profile:
# PTP announce interval.
announce:
@@ -45,7 +45,12 @@
# Common PTP settings.
ptp_settings:
enabled:
- profile:
+
+ # Default available profiles are:
+ # - "aes67"
+ # - "aes67-r16-2016"
+ # - "smpte2059-2"
+ profile:
domain:
auto_clock_identity:
```
diff --git a/development/compare.py b/development/compare.py
index 3198df8aea1..df1c7edaccc 100755
--- a/development/compare.py
+++ b/development/compare.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python
# Copyright (c) 2024 Arista Networks, Inc.
# Use of this source code is governed by the Apache License 2.0
# that can be found in the LICENSE file.
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 1055b13ada9..8aea7157cc8 100644
--- a/python-avd/pyavd/_eos_designs/schema/eos_designs.schema.yml
+++ b/python-avd/pyavd/_eos_designs/schema/eos_designs.schema.yml
@@ -3493,6 +3493,7 @@ keys:
documentation_options:
table: ptp_settings
type: list
+ primary_key: profile
items:
type: dict
keys:
@@ -3536,27 +3537,27 @@ keys:
valid_values:
- ipv4
default:
- - announce:
+ - profile: aes67-r16-2016
+ announce:
interval: 0
timeout: 3
delay_req: -3
- profile: aes67-r16-2016
sync_message:
interval: -3
transport: ipv4
- - announce:
+ - profile: smpte2059-2
+ announce:
interval: -2
timeout: 3
delay_req: -4
- profile: smpte2059-2
sync_message:
interval: -4
transport: ipv4
- - announce:
+ - profile: aes67
+ announce:
interval: 2
timeout: 3
delay_req: 0
- profile: aes67
sync_message:
interval: 0
transport: ipv4
@@ -3570,11 +3571,9 @@ keys:
type: bool
profile:
type: str
- valid_values:
- - aes67
- - smpte2059-2
- - aes67-r16-2016
default: aes67-r16-2016
+ description: "Default available profiles are:\n - \"aes67\"\n - \"aes67-r16-2016\"\n
+ \ - \"smpte2059-2\""
domain:
type: int
$ref: eos_cli_config_gen#/keys/ptp/keys/domain
@@ -5199,10 +5198,8 @@ $defs:
profile:
type: str
default: aes67-r16-2016
- valid_values:
- - aes67
- - aes67-r16-2016
- - smpte2059-2
+ description: "Default available profiles are:\n - \"aes67\"\n - \"aes67-r16-2016\"\n
+ \ - \"smpte2059-2\""
sflow:
type: bool
description: Configures sFlow on the interface. Overrides `fabric_sflow.endpoints`
@@ -8858,10 +8855,8 @@ $defs:
default: false
profile:
type: str
- valid_values:
- - aes67
- - smpte2059-2
- - aes67-r16-2016
+ description: "Default available profiles are:\n - \"aes67\"\n -
+ \"aes67-r16-2016\"\n - \"smpte2059-2\""
default: aes67-r16-2016
mlag:
description: Configure PTP on the MLAG peer-link port-channel when
diff --git a/python-avd/pyavd/_eos_designs/schema/schema_fragments/defs_adapter_config.schema.yml b/python-avd/pyavd/_eos_designs/schema/schema_fragments/defs_adapter_config.schema.yml
index b799a65d35d..f540f8f504d 100644
--- a/python-avd/pyavd/_eos_designs/schema/schema_fragments/defs_adapter_config.schema.yml
+++ b/python-avd/pyavd/_eos_designs/schema/schema_fragments/defs_adapter_config.schema.yml
@@ -145,10 +145,11 @@ $defs:
profile:
type: str
default: "aes67-r16-2016"
- valid_values:
- - "aes67"
- - "aes67-r16-2016"
- - "smpte2059-2"
+ description: |-
+ Default available profiles are:
+ - "aes67"
+ - "aes67-r16-2016"
+ - "smpte2059-2"
sflow:
type: bool
description: |-
diff --git a/python-avd/pyavd/_eos_designs/schema/schema_fragments/defs_node_type.schema.yml b/python-avd/pyavd/_eos_designs/schema/schema_fragments/defs_node_type.schema.yml
index dfad31b8b6c..95bf96d54ff 100644
--- a/python-avd/pyavd/_eos_designs/schema/schema_fragments/defs_node_type.schema.yml
+++ b/python-avd/pyavd/_eos_designs/schema/schema_fragments/defs_node_type.schema.yml
@@ -1067,10 +1067,11 @@ $defs:
default: false
profile:
type: str
- valid_values:
- - "aes67"
- - "smpte2059-2"
- - "aes67-r16-2016"
+ description: |-
+ Default available profiles are:
+ - "aes67"
+ - "aes67-r16-2016"
+ - "smpte2059-2"
default: "aes67-r16-2016"
mlag:
description: Configure PTP on the MLAG peer-link port-channel when PTP is enabled. By default PTP will not be configured on the MLAG peer-link port-channel.
diff --git a/python-avd/pyavd/_eos_designs/schema/schema_fragments/ptp_profiles.schema.yml b/python-avd/pyavd/_eos_designs/schema/schema_fragments/ptp_profiles.schema.yml
index 2a930f1aaa4..e3efafb8298 100644
--- a/python-avd/pyavd/_eos_designs/schema/schema_fragments/ptp_profiles.schema.yml
+++ b/python-avd/pyavd/_eos_designs/schema/schema_fragments/ptp_profiles.schema.yml
@@ -10,6 +10,7 @@ keys:
documentation_options:
table: ptp_settings
type: list
+ primary_key: profile
items:
type: dict
keys:
@@ -52,27 +53,27 @@ keys:
type: str
valid_values: ["ipv4"]
default:
- - announce:
+ - profile: aes67-r16-2016
+ announce:
interval: 0
timeout: 3
delay_req: -3
- profile: aes67-r16-2016
sync_message:
interval: -3
transport: ipv4
- - announce:
+ - profile: smpte2059-2
+ announce:
interval: -2
timeout: 3
delay_req: -4
- profile: smpte2059-2
sync_message:
interval: -4
transport: ipv4
- - announce:
+ - profile: aes67
+ announce:
interval: 2
timeout: 3
delay_req: 0
- profile: aes67
sync_message:
interval: 0
transport: ipv4
diff --git a/python-avd/pyavd/_eos_designs/schema/schema_fragments/ptp_settings.schema.yml b/python-avd/pyavd/_eos_designs/schema/schema_fragments/ptp_settings.schema.yml
index 741c2e303da..9e35c57aa4c 100644
--- a/python-avd/pyavd/_eos_designs/schema/schema_fragments/ptp_settings.schema.yml
+++ b/python-avd/pyavd/_eos_designs/schema/schema_fragments/ptp_settings.schema.yml
@@ -16,11 +16,12 @@ keys:
type: bool
profile:
type: str
- valid_values:
- - "aes67"
- - "smpte2059-2"
- - "aes67-r16-2016"
default: "aes67-r16-2016"
+ description: |-
+ Default available profiles are:
+ - "aes67"
+ - "aes67-r16-2016"
+ - "smpte2059-2"
domain:
type: int
$ref: "eos_cli_config_gen#/keys/ptp/keys/domain"
diff --git a/python-avd/pyavd/_eos_designs/shared_utils/ptp.py b/python-avd/pyavd/_eos_designs/shared_utils/ptp.py
index 4c5f1c15af1..77fde6da48b 100644
--- a/python-avd/pyavd/_eos_designs/shared_utils/ptp.py
+++ b/python-avd/pyavd/_eos_designs/shared_utils/ptp.py
@@ -11,39 +11,6 @@
if TYPE_CHECKING:
from . import SharedUtils
-DEFAULT_PTP_PROFILES = [
- {
- "profile": "aes67-r16-2016",
- "announce": {
- "interval": 0,
- "timeout": 3,
- },
- "delay_req": -3,
- "sync_message": {"interval": -3},
- "transport": "ipv4",
- },
- {
- "profile": "smpte2059-2",
- "announce": {
- "interval": -2,
- "timeout": 3,
- },
- "delay_req": -4,
- "sync_message": {"interval": -4},
- "transport": "ipv4",
- },
- {
- "profile": "aes67",
- "announce": {
- "interval": 2,
- "timeout": 3,
- },
- "delay_req": 0,
- "sync_message": {"interval": 0},
- "transport": "ipv4",
- },
-]
-
class PtpMixin:
"""
@@ -65,13 +32,15 @@ def ptp_mlag(self: SharedUtils) -> bool:
@cached_property
def ptp_profile_name(self: SharedUtils) -> str:
default_ptp_profile = get(self.hostvars, "ptp_settings.profile", default="aes67-r16-2016")
- return get(self.switch_data_combined, "ptp.profile", default_ptp_profile)
+ return get(self.switch_data_combined, "ptp.profile", default=default_ptp_profile)
@cached_property
def ptp_profile(self: SharedUtils) -> dict:
- return get_item(self.ptp_profiles, "profile", self.ptp_profile_name, default={})
+ msg = f"PTP Profile '{self.ptp_profile_name}' referenced under `ptp.profile` node variables does not exist in `ptp_profiles`."
+ return get_item(self.ptp_profiles, "profile", self.ptp_profile_name, required=True, custom_error_msg=msg)
@cached_property
def ptp_profiles(self: SharedUtils) -> list:
"""Return ptp_profiles."""
- return get(self.hostvars, "ptp_profiles", default=DEFAULT_PTP_PROFILES)
+ default_ptp_profiles = self.schema.get_default_value(["ptp_profiles"])
+ return get(self.hostvars, "ptp_profiles", default=default_ptp_profiles)
diff --git a/python-avd/pyavd/_eos_designs/structured_config/connected_endpoints/ethernet_interfaces.py b/python-avd/pyavd/_eos_designs/structured_config/connected_endpoints/ethernet_interfaces.py
index 7f4486c8f09..12ee6b9bc66 100644
--- a/python-avd/pyavd/_eos_designs/structured_config/connected_endpoints/ethernet_interfaces.py
+++ b/python-avd/pyavd/_eos_designs/structured_config/connected_endpoints/ethernet_interfaces.py
@@ -56,7 +56,8 @@ def ethernet_interfaces(self: AvdStructuredConfigConnectedEndpoints) -> list | N
},
network_port,
)
- ethernet_interface = self._get_ethernet_interface_cfg(tmp_network_port, 0, connected_endpoint, index)
+ context = f"network_ports[{index}]"
+ ethernet_interface = self._get_ethernet_interface_cfg(tmp_network_port, 0, connected_endpoint, context)
replace_or_append_item(ethernet_interfaces, "name", ethernet_interface)
for index, connected_endpoint in enumerate(self._filtered_connected_endpoints):
@@ -65,7 +66,8 @@ def ethernet_interfaces(self: AvdStructuredConfigConnectedEndpoints) -> list | N
if node_name != self.shared_utils.hostname:
continue
- ethernet_interface = self._get_ethernet_interface_cfg(adapter, node_index, connected_endpoint, index)
+ context = f"{connected_endpoint['type']}[{connected_endpoint['name']}].adapters[{index}]"
+ ethernet_interface = self._get_ethernet_interface_cfg(adapter, node_index, connected_endpoint, context)
append_if_not_duplicate(
list_of_dicts=non_overwritable_ethernet_interfaces,
primary_key="name",
@@ -81,7 +83,9 @@ def ethernet_interfaces(self: AvdStructuredConfigConnectedEndpoints) -> list | N
return None
- def _update_ethernet_interface_cfg(self: AvdStructuredConfigConnectedEndpoints, adapter: dict, ethernet_interface: dict, connected_endpoint: dict) -> dict:
+ def _update_ethernet_interface_cfg(
+ self: AvdStructuredConfigConnectedEndpoints, adapter: dict | ChainMap, ethernet_interface: dict, connected_endpoint: dict, context: str
+ ) -> dict:
ethernet_interface.update(
{
"mtu": adapter.get("mtu") if self.shared_utils.platform_settings_feature_support_per_interface_mtu else None,
@@ -105,7 +109,7 @@ def _update_ethernet_interface_cfg(self: AvdStructuredConfigConnectedEndpoints,
"storm_control": self._get_adapter_storm_control(adapter),
"dot1x": adapter.get("dot1x"),
"poe": self._get_adapter_poe(adapter),
- "ptp": self._get_adapter_ptp(adapter),
+ "ptp": self._get_adapter_ptp(adapter, context),
"service_profile": adapter.get("qos_profile"),
"sflow": self._get_adapter_sflow(adapter),
"flow_tracker": self._get_adapter_flow_tracking(adapter),
@@ -114,7 +118,9 @@ def _update_ethernet_interface_cfg(self: AvdStructuredConfigConnectedEndpoints,
)
return strip_null_from_data(ethernet_interface, strip_values_tuple=(None, "", {}))
- def _get_ethernet_interface_cfg(self: AvdStructuredConfigConnectedEndpoints, adapter: dict, node_index: int, connected_endpoint: dict, index: int) -> dict:
+ def _get_ethernet_interface_cfg(
+ self: AvdStructuredConfigConnectedEndpoints, adapter: dict, node_index: int, connected_endpoint: dict, context: str
+ ) -> dict:
"""Return structured_config for one ethernet_interface."""
peer = connected_endpoint["name"]
endpoint_ports: list = default(
@@ -192,11 +198,9 @@ def _get_ethernet_interface_cfg(self: AvdStructuredConfigConnectedEndpoints, ada
msg,
)
- profile = self.shared_utils.get_merged_port_profile(
- profile_name, context=f"{connected_endpoint['type']}[{connected_endpoint['name']}].adapters[{index}].port_channel.lacp_fallback.individual"
- )
+ profile = self.shared_utils.get_merged_port_profile(profile_name, context=f"{context}.port_channel.lacp_fallback.individual")
- ethernet_interface = self._update_ethernet_interface_cfg(profile, ethernet_interface, connected_endpoint)
+ ethernet_interface = self._update_ethernet_interface_cfg(profile, ethernet_interface, connected_endpoint, context)
if port_channel_mode != "on" and get(adapter, "port_channel.lacp_timer") is not None:
ethernet_interface["lacp_timer"] = {
@@ -206,7 +210,7 @@ def _get_ethernet_interface_cfg(self: AvdStructuredConfigConnectedEndpoints, ada
# NOT a port-channel member
else:
- ethernet_interface = self._update_ethernet_interface_cfg(adapter, ethernet_interface, connected_endpoint)
+ ethernet_interface = self._update_ethernet_interface_cfg(adapter, ethernet_interface, connected_endpoint, context)
ethernet_interface["evpn_ethernet_segment"] = self._get_adapter_evpn_ethernet_segment_cfg(
adapter,
short_esi,
diff --git a/python-avd/pyavd/_eos_designs/structured_config/connected_endpoints/port_channel_interfaces.py b/python-avd/pyavd/_eos_designs/structured_config/connected_endpoints/port_channel_interfaces.py
index b0d2a575171..5c90afaf5b4 100644
--- a/python-avd/pyavd/_eos_designs/structured_config/connected_endpoints/port_channel_interfaces.py
+++ b/python-avd/pyavd/_eos_designs/structured_config/connected_endpoints/port_channel_interfaces.py
@@ -35,7 +35,7 @@ def port_channel_interfaces(self: AvdStructuredConfigConnectedEndpoints) -> list
- Raise a duplicate error for any other duplicate port-channel interface
"""
port_channel_interfaces = []
- for connected_endpoint in self._filtered_connected_endpoints:
+ for index, connected_endpoint in enumerate(self._filtered_connected_endpoints):
for adapter in connected_endpoint["adapters"]:
if get(adapter, "port_channel.mode") is None:
continue
@@ -44,7 +44,8 @@ def port_channel_interfaces(self: AvdStructuredConfigConnectedEndpoints) -> list
channel_group_id = get(adapter, "port_channel.channel_id", default=default_channel_group_id)
port_channel_interface_name = f"Port-Channel{channel_group_id}"
- port_channel_config = self._get_port_channel_interface_cfg(adapter, port_channel_interface_name, channel_group_id, connected_endpoint)
+ context = f"{connected_endpoint['type']}[{connected_endpoint['name']}].adapters[{index}]"
+ port_channel_config = self._get_port_channel_interface_cfg(adapter, port_channel_interface_name, channel_group_id, connected_endpoint, context)
append_if_not_duplicate(
list_of_dicts=port_channel_interfaces,
primary_key="name",
@@ -75,7 +76,7 @@ def port_channel_interfaces(self: AvdStructuredConfigConnectedEndpoints) -> list
context_keys=["name"],
)
- for network_port in self._filtered_network_ports:
+ for index, network_port in enumerate(self._filtered_network_ports):
if get(network_port, "port_channel.mode") is None:
continue
@@ -100,7 +101,10 @@ def port_channel_interfaces(self: AvdStructuredConfigConnectedEndpoints) -> list
channel_group_id = get(tmp_network_port, "port_channel.channel_id", default=default_channel_group_id)
port_channel_interface_name = f"Port-Channel{channel_group_id}"
- port_channel_config = self._get_port_channel_interface_cfg(tmp_network_port, port_channel_interface_name, channel_group_id, connected_endpoint)
+ context = f"network_ports[{index}]"
+ port_channel_config = self._get_port_channel_interface_cfg(
+ tmp_network_port, port_channel_interface_name, channel_group_id, connected_endpoint, context
+ )
append_if_not_duplicate(
list_of_dicts=port_channel_interfaces,
primary_key="name",
@@ -116,10 +120,11 @@ def port_channel_interfaces(self: AvdStructuredConfigConnectedEndpoints) -> list
def _get_port_channel_interface_cfg(
self: AvdStructuredConfigConnectedEndpoints,
- adapter: dict,
+ adapter: dict | ChainMap,
port_channel_interface_name: str,
channel_group_id: int,
connected_endpoint: dict,
+ context: str,
) -> dict:
"""Return structured_config for one port_channel_interface."""
peer = connected_endpoint["name"]
@@ -154,7 +159,7 @@ def _get_port_channel_interface_cfg(
"mtu": adapter.get("mtu") if self.shared_utils.platform_settings_feature_support_per_interface_mtu else None,
"service_profile": adapter.get("qos_profile"),
"link_tracking_groups": self._get_adapter_link_tracking_groups(adapter),
- "ptp": self._get_adapter_ptp(adapter),
+ "ptp": self._get_adapter_ptp(adapter, context),
"sflow": self._get_adapter_sflow(adapter),
"flow_tracker": self._get_adapter_flow_tracking(adapter),
"validate_state": None if adapter.get("validate_state", True) else False,
diff --git a/python-avd/pyavd/_eos_designs/structured_config/connected_endpoints/utils.py b/python-avd/pyavd/_eos_designs/structured_config/connected_endpoints/utils.py
index 22654b41fb8..994caa94af7 100644
--- a/python-avd/pyavd/_eos_designs/structured_config/connected_endpoints/utils.py
+++ b/python-avd/pyavd/_eos_designs/structured_config/connected_endpoints/utils.py
@@ -197,7 +197,7 @@ def _get_adapter_link_tracking_groups(self: AvdStructuredConfigConnectedEndpoint
},
]
- def _get_adapter_ptp(self: AvdStructuredConfigConnectedEndpoints, adapter: dict) -> dict | None:
+ def _get_adapter_ptp(self: AvdStructuredConfigConnectedEndpoints, adapter: dict, context: str) -> dict | None:
"""Return ptp for one adapter."""
if get(adapter, "ptp.enabled") is not True:
return None
@@ -206,7 +206,8 @@ def _get_adapter_ptp(self: AvdStructuredConfigConnectedEndpoints, adapter: dict)
# Apply PTP profile config
if (ptp_profile_name := get(adapter, "ptp.profile", default=self.shared_utils.ptp_profile_name)) is not None:
- ptp_config.update(get_item(self.shared_utils.ptp_profiles, "profile", ptp_profile_name, default={}))
+ msg = f"PTP Profile '{ptp_profile_name}' referenced under {context} does not exist in `ptp_profiles`."
+ ptp_config.update(get_item(self.shared_utils.ptp_profiles, "profile", ptp_profile_name, required=True, custom_error_msg=msg))
ptp_config["enable"] = True